Statsmodels AutoRegression回测代码有效性

Statsmodels AutoRegression backtesting code validity

我正在使用统计模型库学习 Python 中的自回归模型。

我正在做的是获取一个数据集,该数据集显示来自此处的金融股票的 returns:

Yahoo Finance Data

当我运行以下命令时,数据如下所示:

data['y'] = data['close'].shift(-1).astype(float)
data.dropna(inplace=True)
data.tail()

基本上,y 列是下一个时间步长的收盘价。我的数据集中总共有 500 个时间步。

现在我想拟合一个简单的 AR 模型,使用当前收盘价预测下一期收盘价。为了测试我的模型的适合度,我做了一个回测。

from statsmodels.tsa.arima_model import AutoReg

def backtest(num_periods, data):
    predictions = []
    true_values = []
    x = data[['open', 'high', 'low', 'close']]
    y = data['y']
    for i in reversed(range(1, num_periods)):
        # split the data into training and test splits
        # the y_test variable should be a single value for the next period out of the sample
        x_train = x.iloc[:len(x)-i]
        y_train = y.iloc[:len(y)-i]
        x_test = x.iloc[len(x)-i]
        y_test = y.iloc[len(y)-i]
        # fit the model on the endogenous variables
        model = AutoReg(endog=x_train.close.astype(float), lags = 13).fit()
        # forecast for the period out of the 
        pred = model.predict(start=len(x_train), end=len(x_train)+1)
        # create the prediction and true value arrays
        predictions.append(pred)
        true_values.append(y_test)
    return true_values, predictions

true, pred = backtest(10, data)

但这给了我两个预测系列:

plt.plot(true, label='true', );
plt.plot(pred, label = 'pred', );
plt.legend();

这是怎么回事?我回测 AR 模型的方法是否正确?我主要担心的是,我似乎是在 y 上训练模型,但 y 来自下一个时期。因此,当我预测样本外时,它会从测试集中获取一个值。

任何指导都将非常感谢代码示例。

这里有很多事情需要解决。 首先,不应该使用 Autoregressive model 来预测股票或任何高流动性市场。这是因为自回归模型会考虑第 n 个滞后的值,如果数据不是周期性的,它就没有用,我将进一步详细解释:

考虑 efficient market hypothesis,这表明市场会将所有已知信息考虑到资产价格中。对于预测,这意味着如果每个人都知道价格会在周二上涨和周五下跌,那么人们就会在周一买入并在周四卖出,从而使股价回到均衡状态。

如果您的目标是准确预测市场,已经有一些使用 LSTM 神经网络模型的尝试在这方面取得了一定的成功。

关于验证方法,它似乎没问题,但是有一种方法可以增加灵活性来验证代码,在每次迭代中,您可以直接为每次迭代获得带有验证指标的结果,所以在这种情况下您只需使用数据集和添加行数的测试大小,在本例中为天数。

from sklearn.metrics import mean_absolute_error
from sklearn.metrics import mean_squared_error

def test_train_spl(data, testsize):

    test = data.tail(testsize)
    train = data.head(data.shape[0] - testsize)
    return test, train





def walkforward_validation(data, test_start_date, test_end_date=None, step_size=15, testsize=15, model='SARIMA'):

    test_start_date = pd.to_datetime(test_start_date)
    current_max_date = test_start_date

    modelling_results = pd.DataFrame(columns=['test_start', 'test_end', 'MAE', 'MAPE'])

    if test_end_date is None:
        test_end_date = data.index.max()
        test_end_date = pd.to_datetime(test_end_date)
    else:
        test_end_date = pd.to_datetime(test_end_date)

    while current_max_date < test_end_date:
        data.index = pd.to_datetime(data.index)
        iter_data = data[data.index <= current_max_date + timedelta(days=testsize)]
        test, train = test_train_spl(iter_data, testsize=testsize)

         # fit the model on the endogenous variables
        model = AutoReg(endog=x_train.close.astype(float), lags = 13).fit()
        # forecast for the period out of the 
        pred = model.predict(start=len(x_train), end=len(x_train)+1)
        # create the prediction and true value arrays
    
        mae=mean_absolute_error(y_test, pred)
        mape=mean_absolute_error(y_test, pred)
    
        iter_results = pd.DataFrame({'test_start': [current_max_date],'test_end': [current_max_date + timedelta(testsize)], 'MAE': [mae], 'MAPE': [mape]})
        modelling_results = modelling_results.append(iter_results, ignore_index=True)

        #add the step size to the current date analized and continue the while loop until it is over
        current_max_date = current_max_date + timedelta(days=step_size)


    return modelling_results