Обзор:
- В этой статье объясняется моя попытка предсказать, пойдет ли цена акции вверх или вниз за один день, учитывая историческую цену закрытия за предыдущие 50 дней.
- Я преобразовываю эти 50-дневные данные временных рядов с помощью грамианских угловых полей, чтобы сделать их интерпретируемыми CNN, и маркирую это изображение с направлением движения акций на 51-й день.
- Хотя результаты посредственные, с точностью около 58%, это новый метод решения вечной проблемы.
Примечания и предварительные условия:
Вы должны хорошо понимать, как работает CNN, уметь пользоваться библиотекой fastai и обладать некоторыми навыками работы с данными.
Также убедитесь, что вы можете импортировать все следующее:
from fastai.vision import * import requests import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import ImageGrid from pyts.image import GramianAngularField import pandas as pd import numpy as np import os.path
Настройка конвейера данных:
Данные → фрагменты временных рядов → создание изображений → помеченные изображения
Получение данных:
Мы собираемся получать ежедневные данные для индекса Dow Jones с начала 2000 года. С помощью этого API от alphavantage мы получаем следующие поля: timestamp, o pen, high, low, close, и объем.
import requests TICKER = 'DJI' API_KEY = 'MAKE YOUR OWN ACCOUNT' url = 'https://www.alphavantage.co/query?function=TIME_SERIES_DAILY&symbol='+ TICKER +'&interval=5min&apikey='+API_KEY+'&outputsize=full&datatype=csv' r = requests.get(url, allow_redirects=True) open('daily_'+TICKER+'.csv', 'wb').write(r.content)
Давайте быстро взглянем на данные
X = pd.read_csv('daily_'+TICKER+'.csv', index_col='timestamp') X = X.iloc[::-1] X.head()
Образцы фрагментов:
Наша цель сейчас - преобразовать данные, случайным образом взяв 50-дневные фрагменты. Нам также необходимо разделить эти фрагменты на обучающий набор и набор проверки. Поскольку это данные временного ряда, а не случайное разбиение фрагментов, нам нужно отметить некоторый период времени, который будет нашим набором проверки. Мы будем использовать предыдущие 500 дней как таковые, а остальные (~ 4400) дней как тренировочные.
Чтобы отметить места, где должны начинаться наши фрагменты, мы единообразно выбираем соответствующие дни обучения и дни проверки соответственно.
X.head() n_samples, n_timestamps = 1000, 50 valid_days, valid_samples = 500, n_samples // 5 startIdx_train = np.random.randint(0, len(X) - n_timestamps - valid_days, n_samples) df_train = [] for x in startIdx_train: a = X.close[x: x + n_timestamps].to_numpy() df_train.append(a) df_train = np.array(df_train) startIdx_valid = np.random.randint(len(X) - n_timestamps - valid_days, len(X) - n_timestamps , valid_samples) df_valid = [] for x in startIdx_valid: a = X.close[x: x + n_timestamps].to_numpy() df_valid.append(a) df_valid = np.array(df_valid)
Преобразование в изображения:
Эти процедуры подробно обсуждаются в этой статье, но по сути мы преобразуем данные временных рядов в грамианские угловые поля суммирования / разности, упрощая интерпретацию данных CNN.
gasf = GramianAngularField(image_size=50, method='summation') X_gasf_train = gasf.fit_transform(df_train)
Преобразование этого:
В это:
Пометка изображений:
Наконец, нам нужно настроить наши папки и пометить наши изображения. Мы используем каталог типа ImageNet, в котором есть папки test и valid с подпапками для двух классов: вверх и вниз. .
def getMvmt(start, end): if end > start: return "up" return "down" cmap = 'rainbow' for i in range(0,len(df_train)): direction = getMvmt(X.close[startIdx[i] + 49], X.close[startIdx[i] + 50]) plt.figure(figsize=(8, 8)) plt.imshow(X_gadf_train[i], cmap=cmap, origin='lower') plt.axis('off') plt.savefig(os.path.join("data/stocks",TICKER,"train",direction,"img" + str(i)), transparent=True, bbox_inches='tight') plt.close()
Построение модели:
Загрузка данных:
При создании этой модели я полностью полагаюсь на библиотеку fastai.vision. Сначала мы устанавливаем путь и загружаем изображения в ImageDataBunch.
path = Path("data/stocks/"+TICKER) data = ImageDataBunch.from_folder(path, ds_tfms=None, size=224, num_workers=4, bs=32).normalize(imagenet_stats) data.classes
Мы проверяем data.classes, чтобы убедиться, что данные введены правильно. Также обратите внимание, что, в отличие от большинства классификаторов, мы не используем аугментацию, поскольку переворачивание изображения аналогично переворачиванию графика.
Обучение учащегося:
Мы создаем обучаемого на основе архитектуры ResNet50 и используем точность в качестве метрики. За 19 лет работы индекс DJI растет в 53% случаев, так что это наш базовый уровень точности.
learn.fit_one_cycle(4)
Теперь мы можем выполнить некоторую тонкую настройку, разморозив все слои и используя средство поиска скорости обучения, чтобы выбрать подходящую меньшую скорость обучения.
learn.unfreeze() learn.lr_find() learn.recorder.plot() learn.fit_one_cycle(2, max_lr=slice(1e-6,3e-5))
После этой тонкой настройки мы все еще получаем уровень точности около 58–59%, что выше нашего базового уровня, но не слишком велик по сравнению с другими методами, поскольку SOTA для этого типа прогнозирования находится в середине 60-х годов. %.
Движение вперед:
- Проверьте точность при заданном пороге.
- Поэкспериментируйте с фрагментами разной длины и разными полями, такими как дневной максимум, возможно, цена открытия, а не цена закрытия.
- Попробуйте разные акции и индексы или даже разные классы активов, такие как криптовалюты.
Кредит:
- Fast.ai за уроки и библиотеку.
- Oguiza для своей записной книжки с оливковым маслом
- Alphavantage для их набора данных