Как легко использовать модели SARIMAX для прогнозирования вашего портфеля?

Интересно, как построить эту модель машинного обучения в хорошо подготовленной среде программирования? Нажмите здесь, чтобы построить эту модель шаг за шагом с помощью Управляемого проекта CognitiveClass.ai



У обанкротившейся криптофирмы FTX не хватает по меньшей мере 1 миллиарда долларов клиентских средств, а их токен FTX потерял большую часть своей стоимости в ноябре 2022 года. Как бы вы предотвратили массовые потери своего портфеля в случае «черного лебедя»?

Этот пошаговый проект поможет вам понять метод очистки данных и то, как крупные финансовые компании создают популярные индексы, такие как S&P 500 или Nasdaq. Самое главное, как создать индекс вашего портфеля, который содержит различные криптовалюты, чтобы отслеживать вашу производительность и использовать машинное обучение для прогнозирования движения индекса в ближайшем будущем.

Цель состоит в том, чтобы помочь новичку, который немного знаком с временными рядами, но испытывает трудности с обработкой реальных наборов данных, быстро заполнить пробел с помощью этого управляемого проекта. Надеюсь, каждый сможет найти здесь что-то полезное и получить от этого удовольствие.

Загрузка наборов данных

Во-первых, давайте получим цену закрытия каждой криптовалюты, включая биткойн, Binance Coin, Dogecoin, Ethereum, USD Coin, Tether, XRP и токен FTX с 2010 года от Coincodex.

Примечание. Все цены, используемые в данных, основаны на обменном курсе между целевой валютой и долларом США.

import pandas as pd

coins = pd.read_csv("/cryptocurrency/coins.csv", sep=",", header=0)
coins.set_index("Date", inplace=True)  # make the date become the index
coins = coins.sort_index()

coins

Затем нам нужно выяснить некоторые внешние факторы, которые могут повлиять на цену криптовалют. Давайте возьмем некоторые командные индексы с рынка, такие как S&P 500, Nasdaq, золото и серебро, которые были запущены в 2018 году. Мы также можем добавить некоторые популярные экономические индикаторы, такие как Daily Treasury Par Yield Rates из U.S. Министерство финансов, или CPI и PSR, но имейте в виду, что временная последовательность данных CPI и PSR основана на ежемесячном показе.

factors = pd.read_csv("/cryptocurrency/predictor_variables.csv", sep=",", header=0)
factors.set_index("Date", inplace=True)  # make the date become the index
factors = factors.sort_index()

factors

Очистка данных

Когда мы получаем данные временных рядов, они лишь иногда имеют требуемый формат. Большая часть необработанных данных либо нуждается в большей организации, либо содержит много пропущенных значений или дат, что делает невозможным обучение моделей. Поэтому понимание того, как правильно очищать и правильно подготавливать данные, является одним из важных навыков специалиста по данным.

Очистка пропущенных значений

Во-первых, давайте очистим нулевые значения в криптоданных.

coins = coins.dropna()

coins

Заполнение пропущенных значений

Мы не можем использовать один и тот же метод для внешних факторов, поскольку данные основаны на другой временной последовательности. Таким образом, нам нужно найти и установить первые даты данных, которые будут совпадать со всеми криптовалютами. Из предыдущего результата мы знаем, что можем установить дату 01.08.2019. Чтобы преобразовать эти данные в полезную информацию, мы сначала предположим, что большинство пропущенных дней приходится либо на выходные, либо на праздничные дни, а значения остаются такими же, как и накануне. Основываясь на этом предположении, мы можем заполнить отсутствующую дату и время значениями предыдущего дня.

factors = factors["2019-08-01":]
factors = factors.reindex(pd.date_range("2019-08-01", "2022-11-15")).reset_index().rename(columns={"index": "Date"})
factors = factors.groupby(factors["Date"].dt.time).ffill() # fill the missing date values
factors.set_index("Date", inplace=True)

factors

Создание индекса настройки

Мы хотим предсказать индекс в этом проекте, и в какой-то момент 𝑡t мы будем использовать простой метод индекса, называемый «Равновзвешенный индекс». Это просто среднее значение криптовалют.

Другой метод называется Индекс, взвешенный по капитализации, который позволяет настраивать вес каждой криптовалюты в зависимости от вашего портфеля. Если вы хотите использовать эту технику в своем портфолио, вы можете найти подробное объяснение в CognitiveClass.ai.

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

  • Значение индекса (V): относится к равновзвешенному индексу.
  • Цена(P): относится к цене криптовалюты.
  • Вес (W): относится к присвоенному весу, но в равновзвешенном индексе каждый вес равен 1/N, где N — количество криптографических средств в индексе.
result = []

# calculate the index value
for i in range(len(coins.columns)):
    coin = coins[coins.columns[i]] / len(coins.columns)
    result.append(coin)
# assign index value with date
ew_index = pd.DataFrame(1 + pd.DataFrame(pd.concat(result, axis=1)).sum(axis=1))
ew_index.set_axis([*ew_index.columns[:-1], "Index"], axis=1, inplace=True)

ew_index.tail(5)

Здесь мы можем использовать пакет seaborn для просмотра межквартильного диапазона индекса за каждый месяц.

import seaborn as sns
import matplotlib.pyplot as plt

ts_fig, ts_ax = plt.subplots(figsize=(36, 9))
sns.boxplot(x=ew_index.index.strftime("%Y-%b"), y=ew_index.Index, ax=ts_ax)
ts_ax.set_xlabel("Month", labelpad=9, fontsize=15)
ts_ax.set_ylabel("Total Rides", labelpad=9, fontsize=15)
ts_ax.set_xticklabels(ts_ax.get_xticklabels(), rotation=90)
ts_ax.set_title("Monthly Index", fontsize=21)
plt.show()

Предварительная обработка данных

Прежде чем мы обучим данные индекса, мы должны нормализовать данные и проверить корреляцию между нашим индексом и внешними факторами. Давайте сначала объединим значения индекса и переменные-предикторы в один кадр данных.

data = factors.merge(ew_index, how="left", left_on="Date", right_on="Date")

Нормализация переменных

Теперь у нас наконец есть чистые данные, готовые к использованию. Прежде чем мы начнем обучать модель с этими данными, одним из важных шагов является обеспечение нормализации всех данных. Поскольку и наши целевые переменные, и переменные-предикторы измеряются в разных шкалах, в этом разделе мы должны привести значения к условно стандартной шкале. Есть много способов добиться этого, но в этом проекте будет использоваться один из самых простых методов, нормализация минимума и максимума, который состоит в изменении масштаба диапазона функций для масштабирования диапазона в [0, 1].

from sklearn.preprocessing import MinMaxScaler

data_nor = pd.DataFrame(MinMaxScaler().fit_transform(data)).assign(label=data.index) # normalized the data with min-max scaling
data_nor.columns = data.columns.to_list() + ["Date"]
data_nor.set_index("Date", inplace=True)

data_nor.tail(5)

Нахождение корреляции между переменными

Еще один необходимый шаг, прежде чем мы начнем обучать модель с этими данными, — это проверить корреляцию между нашими целевыми переменными и переменными-предикторами. Мы будем использовать коэффициент корреляции Пирсона для анализа корреляции и, основываясь на следующем рисунке, удалим переменные слабой корреляции (коэффициент корреляции от -0,2 до 0,2).

data_nor.corr(method="pearson").style.background_gradient(cmap="coolwarm", axis=None).set_precision(2)

cor = data_nor.corr(method="pearson")
data_nor.drop(data_nor.columns[(cor.Index >= -0.2) & (cor.Index <= 0.2)], axis=1, inplace=True) # remove the weak corellation (% between -0.2 to 0.2)

data_nor.tail(5)

Прогнозирование временных рядов

Наборы для обучения и тестирования

В машинном обучении случайное разбиение набора данных/теста является нормальным, потому что нет зависимости от одного наблюдения к другому. Тем не менее, это не относится к данным временных рядов. Как мы упоминали ранее, наши модели прогнозирования основаны на авторегрессионном анализе, что означает, что данные временного ряда Y(t+h) коррелируют со своим историческим значением Y(t). . Здесь мы хотим использовать значения в конце набора данных для тестирования и все остальное для обучения.

Исходя из этого предположения, у нас было 1203 записи с дневными интервалами (почти 4 года); хорошим подходом будет сохранение первых 1143 записей (3,1 года) для обучения и последних 60 записей (2 месяца) для тестирования.

train_size = int(len(df) * 0.9505)
X_train, y_train = pd.DataFrame(df.iloc[:train_size, :-1]), pd.DataFrame(df.iloc[:train_size, -1])
X_test, y_test = pd.DataFrame(df.iloc[train_size:, :-1]), pd.DataFrame(df.iloc[train_size:, -1])

Как определить параметры d? Стационарное обнаружение

Стационарный – это фактор, описывающий предсказуемость данных временного ряда. Строгая стационарность описывает все распределение вероятностей как инвариантное к сдвигу во времени, а слабая стационарность сообщает, что среднее значение и ковариация инвариантны к сдвигу во времени, что означает, что момент t значения сильно зависит от его истории. Мы будем использовать функцию stationary, чтобы проверить, являются ли данные временного ряда стационарными.

ori_df = y_train  # original time series
fir_df = y_train.diff().dropna()  # first difference time series
sec_df = y_train.diff().diff().dropna()  # second difference time series
stationary_test = None
for i in range(3):
    if i == 0:
        print("Original Time Series")
        stationary_test = adfuller(ori_df)
    elif i == 1:
        print("First Order Differencing")
        stationary_test = adfuller(fir_df)
    elif i == 2:
        print("Second Order Differencing")
        stationary_test = adfuller(sec_df)

    print("ADF Statistic: %f" %stationary_test[0])
    print("p-value: %f\n" %stationary_test[1])

Внедрение модели SARIMAX

Функция модели SARIMAX аналогична модели ARIMA, но добавляет два дополнительных элемента: сезонность и внешние факторы.

Ключевым выводом является то, что SARIMAX требует не только аргументов p, d и q, которые требуются ARIMA, но также требует другого набора P, D и Q для аспекта сезонности, а также аргумент под названием «m». Это периодичность сезонного цикла данных; другими словами, это количество периодов в каждом сезоне.

Выбирая значение m, постарайтесь понять, когда сезонные данные циклически повторяются. Если точки данных разделены на месячной основе, а сезонный цикл равен году, установите для m значение 12. Или, если точки данных разделены на дневной основе, а сезонный цикл равен неделе, установите s равно 7. Вот таблица, на которую можно ссылаться, чтобы настроить параметры m.

Далее нам нужно найти наилучшие параметры, которые подходят для нашей модели. На этом этапе мы будем использовать один из самых мощных инструментов под названием auto_arima, который поможет нам найти p, q, P и В. Нам не нужно находить d с помощью этого инструмента, потому что мы уже выполнили стационарный тест в предыдущем разделе, что означает d и D. можно установить на 1. Не забудьте установить X_train в exogenous и seasonal в True.

from pmdarima import auto_arima

sarimax_param = auto_arima(y_train, exogenous=X_train, m=7, start_p=0, d=1, start_q=0, start_P=0, D=1, start_Q=0, max_p=3, max_q=1, max_P=3, max_Q=1, trace=True, seasonal=True)

Основываясь на результате, мы обнаружили, что наилучшие параметры для моделей SARIMAX — это когда p равно 1, q равно 0, P равно 3, Q равно 0. Затем мы можем поместить эти параметры в модель и начать обучать нашу модель. На этом этапе мы поместим набор обучающих данных в SARIMAX, а параметры, полученные из auto_arima, — в order, а сезонные параметры — в seasonal_order.

from statsmodels.tsa.statespace.sarimax import SARIMAX

algorithm = SARIMAX(endog=y_train, exog=X_train, order=sarimax_param.get_params()["order"], seasonal_order=sarimax_param.get_params()["seasonal_order"])
model = algorithm.fit(disp=False)

Наконец, мы можем использовать обученную модель для прогнозирования данных тестирования. Здесь нам нужно установить параметры start и end в качестве длины тестовых данных и поместить все внешние факторы в параметр exog. Затем мы можем проверить частоту ошибок модели, чтобы убедиться в ее производительности.

from sklearn.metrics import mean_absolute_error, mean_squared_error

# forecast the data
forecast = model.get_prediction(start=len(y_train), end=len(y_train)+len(y_test)-1, exog=X_test, dynamic=True)
prediction = forecast.predicted_mean
ci = forecast.conf_int()

# check error rate
mse = mean_squared_error(y_test, prediction, squared=False)
rmse = mean_squared_error(y_test, prediction, squared=True)
print("The error rates of the SARIMAX forecasting are: \nMSE = %f \nRMSE = %f" %(mse, rmse))

Сравним результаты прогнозирования с реальностью на графике.

plt.figure(figsize=(24, 9))
plt.plot(y_test.index, y_test, label="observation")
plt.plot(prediction.index, prediction, label="prediction")
plt.fill_between(ci.index, ci.iloc[:, 0], ci.iloc[:, 1], color="k", alpha=0.2)
plt.ylim([0.18, 0.3])
plt.title("SARIMAX Model Prediction", fontsize=21)
plt.legend()
plt.show()

Когда мы смотрим на график, мы можем сказать, что прогноз очень близок к фактическим движениям рынка, а также уловить случайность в прогнозе, за исключением 11 ноября, когда FTX внезапно подала заявление о защите от банкротства.

Вот и все!

Однако не прекращайте читать сейчас! Это практическое занятие знакомит только с методами прогнозирования временных рядов. Узнайте, как построить взвешенный по капитализации индекс, такой как S&P 500 или Nasdaq, для вашего портфеля, чтобы отслеживать криптоиндустрию в этом подробном и бесплатном CognitiveClass. ai управляемый проект. Давайте прокачаем ваши знания сегодня.

Также не стесняйтесь связаться со мной в LinkedIn!



ВНИМАНИЕ: ЭТОТ УПРАВЛЯЕМЫЙ ПРОЕКТ НЕ ЯВЛЯЕТСЯ ФИНАНСОВОЙ КОНСУЛЬТАЦИЕЙ
Информация, содержащаяся на этом веб-сайте, и ресурсы, доступные для загрузки через этот веб-сайт, не предназначены и не должны пониматься или толковаться как финансовые рекомендации. Информация, содержащаяся на этом веб-сайте, не заменяет финансового совета от профессионала, который осведомлен о фактах и ​​обстоятельствах вашей индивидуальной ситуации.