首页 > 解决方案 > Statsmodels AutoRegression 回测代码有效性

问题描述

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

我正在做的是从这里获取一个显示金融股票回报的数据集:

雅虎财经数据

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

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 来自下一个时期。因此,当我预测样本外时,它会从测试集中获取一个值。

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

标签: pythonstatsmodelsautoregressive-models

解决方案


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

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

如果您的目标是准确预测市场,那么已经有一些使用 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

推荐阅读