В этом посте мы продолжим изучение других способов использования методов фильтра Калмана, в основном в качестве альтернативы многомерному прогнозу. Другой вариант включает векторную авторегрессию (VAR). Этот пост не будет вдаваться в подробности о VAR, а скорее предоставит альтернативу моделированию многомерного вывода, когда известен процесс перехода. Важно знать, что при использовании фильтра Калмана известна как взаимосвязь между ненаблюдаемой переменной и наблюдаемым выходом (или есть разумное предположение), так и то, как ненаблюдаемая переменная переходит к следующему периоду таймера (предполагается). Кроме того, все модели, сделанные до сих пор, имеют линейное предположение, и процесс перехода, и процесс наблюдения являются линейными.

Введение

Для тех, кто не знаком с моделями векторной авторегрессии, вы можете найти подробную информацию на вики. В python пакет statsmodel имеет встроенные функции для VAR, подробное использование можно найти в документации.

Короче говоря, VAR используется, если мы считаем, что наблюдаемые переменные взаимодействуют друг с другом. В этой статье предлагается PC-VAR, который применялся для моделирования многих экономических рядов. Быстрый пример — процентные ставки. Процентные ставки сильно коррелированы, и существует множество рядов (от однодневных до 30-летних ставок), но их можно легко свести к трем измерениям с помощью анализа основных компонентов (PCA). Первые 3 компонента процентной ставки хорошо определены как уровень, наклон и кривизна, что объясняет более 95% дисперсии процентной ставки. Затем мы применили бы VAR к этим основным компонентам, одновременно находя коэффициенты.

Что касается PC-VAR, существует преобразование, позволяющее превратить исходные процентные ставки в основные компоненты, применить VAR к основным компонентам для прогнозирования, а затем преобразовать основные компоненты обратно в процентные ставки. Учтите, что на практике модели сложно предсказать уровень (на долю которого приходится более 50 % дисперсии процентной ставки).

Многомерный фильтр Калмана

В этом посте мы будем анализировать временной ряд SP500 вместе с двухлетней процентной ставкой.

Матрица перехода разработана таким образом, что

Вот код: Обратите внимание, что казначейская ставка взята из Министерства финансов США.

    n_train = int(len(data) * 0.9)
    n_test = len(data) - n_train
    result_set = {}
    graph_text = ""
    filter_input = np.concatenate([sp_return.T, interest_rate], axis=1)

    kf = KalmanFilter(transition_matrices=[1], observation_matrices=[1],
                      transition_covariance=np.array([[1]]), observation_covariance=1,
                      n_dim_obs=1)
    kf_mean, filtered_std = kf.filter(filter_input[:n_train,0])
    kf_pred = np.array([1]) * np.power(np.array([1]), np.arange(n_test-1)) * kf_mean[-1]
    result_set = {'kf-1 state': np.append(kf_mean[5:], kf_pred.reshape(-1,1))}
    graph_text = "kf-1 rmse: " + "{:.4f}".format(rmse(filter_input[n_train:,0],kf_pred))


    n_season = 5
    F = np.zeros((n_season + 1, n_season + 1))
    F[0,0] = 1
    F[1, 1:-1] = [-1.0] * (n_season - 1)
    F[2:,1:-1] = np.eye(n_season - 1)
    H = np.array([1, 1, 0, 0, 0, 0])
    P_init = np.eye(n_season + 1) * 0
    P_init[:2,:2] = np.eye(1) * Q
    kf = KalmanFilter(transition_matrices=F, observation_matrices=H,
                      transition_covariance=P_init, observation_covariance=1,
                      n_dim_obs=1)
    kf_1, filtered_std = kf.filter(filter_input[:n_train,0])
    filtered_obs = kf_1.dot(H)
    filtered_pred = forecast_kf(n_test-1, kf_1[-1], F, H.reshape(1,-1))
    graph_text += "\nkf_5 rmse: " + "{:.4f}".format(rmse(filter_input[n_train:,0],filtered_pred))
    result_set['kf_5_2'] = np.append(filtered_obs[5:], filtered_pred.reshape(-1,1))

    n_int=2
    F = np.zeros((n_season + 1 + n_int, n_season + 1 + n_int))
    F[0,0] = 1
    F[0,-2:] = [-1, 1]
    F[1, 1:n_season] = [-1.0] * (n_season - 1)
    F[2:n_season+1,1:n_season] = np.eye(n_season - 1)
    F[-2,-2] = 1
    F[-1,-2] = 1
    H = np.array([[1, 1, 0, 0, 0, 0, 0, 0],[0,0,0,0,0,0,1,0]])
    P_init = np.eye(n_season + 1 + n_int) * 0
    P_init[:2,:2] = np.eye(2) * Q
    P_init[-2:,-2:] = np.eye(2) * Q
    R = np.eye(2) * R
    X_0 = np.zeros(n_season + 1 + n_int)
    kf = KalmanFilter(transition_matrices=F, observation_matrices=H,
                      transition_covariance=P_init, observation_covariance=R,
                      initial_state_mean=X_0, initial_state_covariance=P_init,
                      n_dim_state=8
                      )
    mean_, std_ = kf.filter(filter_input[:n_train,:])


    filtered_pred = forecast_kf(n_test-1, mean_[-1], F, H)
    fitted_value = np.dot(mean_,H.T)
    result_set['SPY Kalman with Treasury'] = np.append(fitted_value.T[0,5:], filtered_pred[0,:])
    graph_text += "\nSPY Kalman with Treasury rmse: " + "{:.4f}".format(rmse(filter_input[n_train:,0], filtered_pred[0,:]))
    ## VAR
    model = VAR(filter_input[:n_train,:])
    results = model.fit(1)
    filtered_pred = results.forecast(filter_input[n_train-1:n_train,:], n_test-1)
    result_set['SPY VAR(1)'] = np.append(results.fittedvalues[4:,0], filtered_pred[:,0])
    graph_text += "\nSPY VAR(1) rmse: " + "{:.4f}".format(rmse(filter_input[n_train:,0], filtered_pred[:,0]))

    results = model.fit(5)
    filtered_pred = results.forecast(filter_input[n_train - 5:n_train, :], n_test - 1)
    result_set['SPY VAR(5)'] = np.append(results.fittedvalues[:, 0], filtered_pred[:, 0])
    graph_text += "\nSPY VAR(5) rmse: " + "{:.4f}".format(rmse(filter_input[n_train:, 0], filtered_pred[:, 0]))

Результат выглядит следующим образом. Обратите внимание, что на графике ниже он рассматривает только прогноз доходности SP500, игнорируя результат, чтобы прогноз процентной ставки соответствовал другим сообщениям. Сила модели в том, что она предсказывает оба ряда.

увеличение в течение зеленого периода тестирования

Существует небольшая разница между фильтром Калмана с циклическим термином из последнего поста (названным kf_5 здесь и kf_5_2 ранее, в основном второй горб менее выражен при включении казначейской ставки).

Заключение

Присмотревшись внимательнее, мы заметили, что хотя и наблюдается небольшое снижение RMSE с включением казначейства, точность направления несколько падает. Мы могли бы улучшить набор моделей, вдохновившись моделью PC-VAR, включив дополнительные ряды процентных ставок (сначала применив PCA для уменьшения размерности) и/или мы могли бы включить другую доходность капитала (DJ) или ряды, такие как индекс волатильности.

Что следует учитывать

До сих пор мы сделали несколько сильных предположений (линейность) и не использовали неизвестный параметр в модели перехода и наблюдения. Во многих случаях использования это не так. В будущих сообщениях мы рассмотрим, как работать с нелинейной моделью перехода и как оценивать параметры.

Пожалуйста, следите и подпишитесь, если вас интересуют будущие публикации на эту тему.