Ниже я честно описал одну из своих неудачных попыток применения нейросетей для трейдинга и привёл результат теста на истории системы для торговли на фьючерсе RI.
Разрабатываемая торговая система относится к непрерывным с фиксированным капиталом: в ней нет ни тейков, ни стопов, а есть лишь доля капитала, которая сейчас размещена в торгуемом инструменте (аллокация) и тройка предикторов. В тестах размер капитала постоянный, чтобы реинвестирование не искажало результат. Если доля равна 1, то взят лонг на весь капитал при торговле по номиналу, если доля -1, то шорт на весь капитал; для аллокации допустимы любые вещественные значения между -1 и 1.
Возьмём 15-минутный таймфрейм. Торговая система осуществляет сделки по ценам закрытия свечей. На каждой свече, за исключением самой последней свечи торговой сессии, с помощью нейросети вычисляется доля капитала под позицию, определяется, сколько контрактов должно быть в этой позиции, после чего покупается или продаётся такое число контрактов, чтобы текущая позиция превратилась в целевую.
Нейросеть берём простую. У неё четыре входа:
1) текущая аллокация;
2) значение индикатора MFI с периодом mfiPeriod;
3) значение индикатора RSI с периодом rsiPeriod;
4) номер текущей свечи с начала торгового дня;
три внутренних нейрона и один выход, который интерпретируется как целевая аллокация. Нейросеть будет полносвязной, поэтому количество весовых коэффициентов в нейросети равно (4+1) * 3 + (3 + 1) * 1 = 19. В качестве сигмоидной функции возьмём
s(x) = -0.5 + 1.0 / (1.0 + exp(-x)).
Эта функция выдаёт значения в диапазоне от -0.5 до +0.5. Если умножить на 2, как раз получится диапазон от -1 до 1 для аллокации капитала.
Нейросеть – это некоторый способ преобразовать 4 входных значения в одно выходное, используя 19 весовых коэффициентов, записанных в массив w, умножения, сложения и функцию сигмоида. На языке программирования Java это может выглядеть примерно так:
// 4 входных параметра: текущая аллокация alloc, mfi, rsi, номер свечи дня num
// 3 нейрона на внутреннем слое
// 1 выход: целевая аллокация
// 19 весовых коэффициентов w
double a1 = w[0] + w[1] * alloc + w[2] * mfi + w[3] * rsi + w[4] * num;
double a2 = w[5] + w[6] * alloc + w[7] * mfi + w[8] * rsi + w[9] * num;
double a3 = w[10] + w[11] * alloc + w[12] * mfi + w[13] * rsi + w[14] * num;
a1 = sigmoid(a1);
a2 = sigmoid(a2);
a3 = sigmoid(a3);
double b1 = w[15] + w[16] * a1 + w[17] * a2 + w[18] * a3;
b1 = sigmoid(b1);
allocation = 2 * b1;
В этом месте я опущу технические детали одного трюка, который использует симметрию и приводит в некотором смысле к удалению информации о тренде из данных. В результате даже если обучать нейросеть только на растущем рынке, то потом она будет справляться с торговлей и на падающем рынке.
Теперь надо рассчитать оптимальные весовые коэффициенты нейросети и параметры mfiPeriod и rsiPeriod.
С параметрами mfiPeriod и rsiPeriod всё понятно: сделаем перебор по некоторой сетке значений, например, от 12 (3 торговых часа) до 100 (25 торговых часов) с некоторым постепенно увеличивающимся шагом, а потом выберем параметры с наилучшим результатом.
Для каждой пары периодов mfiPeriod и rsiPeriod подберём весовые коэффициенты нейросети так, чтобы график эквити торговли за промежуток времени показывал максимальную доходность. Нейросеть с произвольным набором коэффициентов даст какую-то торговую систему с каким-то графиком эквити. А мы с помощью оптимизации будем искать наилучшую доходность. В принципе, у каждого из нас могут быть свои представления о качественной эквити. В этом месте можно использовать их, а не максимальную доходность, как сделал я.
Обучение нейросети реализовано с помощью итерационного алгоритма Нелдера-Мида (Nelder-Mead Optimization), где в качестве начальных приближений берутся вектора из 19 случайных вещественных чисел, целевая функция для максимизации – доходность торговой системы за 3 года. Алгоритм оптимизации находит локальный экстремум, так что коэффициенты нейросети далеко не всегда могут оказаться удачными. По-хорошему, надо делать мультистарт, когда делается несколько попыток рассчитать коэффициенты нейросети и выбирается лучшая. С другой стороны, мы применяем перебор по параметрам mfiPeriod и rsiPeriod по довольно обширной и частой сетке значений, так что хоть где-то и хоть как-то адекватные нейросети должны получиться и без мультистарта.
В каждой итерации метода оптимизации вычисляется доходность нейросетевой стратегии за 3 года торговли путём генерации сделок, учёта комиссии и проскальзывания (0.02% для фьючерса RI), вычисления эквити. Так что вычисление значения оптимизируемой функции тут трудоёмкое и без быстрого тестера никак не обойтись. Мой тестер написан на языке программирования Java и обладает приемлемой для этого скоростью. Однако, даже в этом случае подбор коэффициентов нейросетей занимает несколько часов.
В итоге оптимизации имеем таблицу с лучшей нейросетью для каждого из вариантов mfiPeriod, rsiPeriod, из которых выбираем лучшую. Для каждого периода оптимизации оптимальные параметры mfiPeriod, rsiPeriod существенно отличаются друг от друга, никаких закономерностей на глаз не видно.
Результаты для лучших систем, которые получены на периоде оптимизации, поражают воображение, особенно если помнить, что это торговля по номиналу и частичным использованием капитала:
* 2011-2013 гг. +145%;
* 2012-2014 гг. +187%;
* 2013-2015 гг. +175%;
* 2014-2016 гг. +217%;
* 2015-2017 гг. +222%;
* 2016-2018 гг. +130%;
* 2017-2019 гг. +106%.
Наверняка тут наблюдается существенное переобучение нейросети и подгонка под историю!
Для более корректной оценки того, что получилось, проведём walk-forward тестирование. По данным с января 2011 года по декабрь 2013 года проводим оптимизацию, запоминаем одну лучшую нейросеть и торгуем с её помощью 2014 год. Потом сдвигаем промежуток оптимизации на год, проводим новую оптимизацию с января 2012 года по декабрь 2014 года, торгуем по лучшей нейросети 2015 год, и так далее до текущего момента времени. Графики эквити торговли, начиная с 2014 года, собираем в один общий. Получается результат в +20 % за шесть с половиной лет при торговле фиксированным капиталом, а график эквити больше похож на случайное блуждание.
Скорее всего, если выбирать не одну лучшую стратегию, а, скажем, пять, распределять между ними капитал поровну и поддерживать итоговую позицию этого набора стратегий, то график эквити walk-forward теста принципиально не изменится, если только размахи станут меньше из-за диверсификации по параметрам.
Остаётся вопрос: а почему это всё не заработало? Тут наблюдается влияние сразу нескольких факторов, среди которых:
1) низкая ценность предикторов MFI, RSI;
2) большое количество параметров оптимизации по сравнению с имеющимся массивом рыночных данных;
3) нестационарность рынка как большая беда для моделей машинного обучения.
На мой взгляд, такой подход вряд ли приведёт к успеху, хотя с точки зрения машинного обучения, вроде бы, он здравый. Получение плохих результатов – это важная часть процесса познания, т. к. негативный опыт иногда важнее позитивного.
Вот так выглядит типичный нейросетевой грааль алготрейдера: IS – для покупки яхт, OOS и walk-forward для разочарований.
Чисто математический подход — в этом главная причина.
Трейдер попытался бы эти закономерности заложить предварительно САМ, учитывая специфику индикаторов (основные паттерны и особенности), а вот после этого нейросеть должна обучиться какие параметры этих закономерностей лучше всего подходят.
Я в сетях и в программировании… Взгляд трейдера.
Истина или ближе ко мне, или где-то посередине.
Но пост плюсанул таки — рабочий пост.
Ну, можно сказать, что это очередное доказательство того, что нейросети как и ничто другое в лоб с первого захода не работают. Как не работает так случайный лес, как не работают так свечные паттерны, как не работают так треугольники и уровни. Кстати, видимо, поэтому про одни и те же инструменты одни говорят, что норм тема, другие — что не работает.
Через 2 месяца тоже пощупаю нейросети в трейдинге)).
Сети хороши на сыром сигнале — в нашем случае котировках. В реальных задачах не работают неглубокие сети, а так же сети из полносвязный слоев. Тут мы видим сеть из пары полносвязный слоев и придуманными в ручную признаками — в такой ситуации лучше использовать другие методы: градиентный бустинг, случайный лес, а в таком простом случае может и логистическую регрессию.
Данных слишком мало — нужно на порядок минимум больше по моему опыту.
Признаки слишком разного типа и масштаба — на таких данных сети не учат. Количественные признаки нужно нормировать к одному масштабу, а порядковый (номер в периоде) превращать в эмбеддинг. Правда порядковый признак сам по себе очень странный, но я в теме торговли на пятиминутках не сильно смыслю, возможно он имеет смысл.
Никто в реальной жизни не учит сети с помощью Nelder-Mead Optimization — лучше использовать AdamW, да и сам подход к оптимизации на мой взгляд страшно странный — насколько я понял у вас вообще один большой обучающий пример получается. Не удивительно, что такая переподгонка. Нужно бить данные на множество маленьких эпизодов и подсовывать их сети в качестве отдельных обучающих примеров.
Подход к разметке данных для обучения хорошо описан тут
www.amazon.com/Advances-Financial-Machine-Learning-Marcos/dp/1119482089/
Книга про ML, но в разметка для DL делается аналогично
Test score: 82%
Test accuracy: 61%
sber
Test score: 0.77%
Test accuracy: 0.68%
gmk
Test score: 0.85%
Test accuracy: 0.58%
luk
Test score: 0.84%
Test accuracy: 0.60%
На акциях пробуй. Сбер дает 68% точности предсказания. Остальные более манипулятивные
Каждый имеет свою точку зрения и нет единства мнений. Это хорошо, подтверждает банальную истину, что рынок не так прост, как думают экономисты.
Внесу свои 5 копеек. Мы работаем в условиях низкого отношения сигнала к помехе. Поэтому критическое значение имеет минимизация числа степеней свободы в системе оптимизации (ну и максимизация, до известного предела, объема сырых входных данных). С этой точки зрения непонятно, почему автор сдвигает окно подгонки, а не добавляет новые годы к предыдущим.
Поэтому необходимо ввести механизм, контролирующий число степеней свободы в подгонке. Математики вводят регуляризацию, например, или сокращают класс функций, используемых для подгонки.
Лично я предпочитаю явные методы, то есть ограничение на число и форму кластеров в маломерном пространстве функционалов на исходных данных.
Попытка адаптации к изменяющемуся рынку.
Последнее время много обсуждают в чате ML, нейросети. Возможно, вам будет интересно.
торгую только через QUIK и QLua. Спасибо за ссылку на чат.
При работе с несложными картинками сетки быстро умнеют примерно после 5000-10000. Поэтому обычно придумывают способы увеличения датасета или/и собственные методы обучения или/и особый дизайн сети.