Quantitative trading - страница 29

 

Торговля волатильностью акций с помощью процесса Орнштейна-Уленбека


Торговля волатильностью акций с помощью процесса Орнштейна-Уленбека

В начале 2020 года S&P 500 испытал значительный рост волатильности, поскольку цены резко упали. За месяц индекс упал почти на тысячу пунктов. В то же время ожидания будущей волатильности, основанные на торгуемых индексных опционах, также выросли в этот период, достигнув пика в 66. Стало очевидным, что в периоды рыночной волатильности, когда значение индекса снижалось, VIX (индекс волатильности) рос. VIX служит будущей оценкой волатильности. Это явление заставило маркет-мейкеров и профессионалов трейдинга предвидеть, что реализованная волатильность сохранится.

В этом видео мы стремимся объяснить рыночные характеристики волатильности и обсудить методологию моделирования волатильности путем подгонки формулы Орнштейна-Уленбека к конкретному индексу волатильности. Мы будем использовать метод оценки максимального правдоподобия для калибровки трех параметров модели в соответствии с рыночными данными. Впоследствии мы смоделируем этот процесс в Python, что позволит нам понять и проанализировать динамику волатильности во времени.

Для этого мы импортируем различные зависимости, такие как time, math, numpy, pandas, datetime, scipy, matplotlib, pandas_datareader и функцию plot_acf из модуля статистики. Данные, которые мы будем использовать, — это данные S&P 500 с 2003 года. Чтобы изучить кластеризацию волатильности и ее свойства в финансовых временных рядах, мы обратимся к исследовательской статье Ramacant (2005) «Кластеризация волатильности на финансовых рынках», в которой исследуются статистические свойства финансовых временных рядов. Мы сосредоточимся на трех важных свойствах: избыточной волатильности, тяжелых хвостах и кластеризации волатильности.

Кластеризация волатильности относится к наблюдению, что за большими изменениями цен обычно следуют другие большие изменения, независимо от их направления, в то время как за небольшими изменениями часто следуют небольшие изменения. Это количественное проявление предполагает, что, хотя доходность может быть некоррелированной, абсолютная доходность или ее квадраты демонстрируют небольшую положительную корреляцию, которая со временем постепенно уменьшается. Чтобы проанализировать это, мы исследуем логарифмическую доходность, которая представляет собой логарифм изменения цены с течением времени. Визуально изучая логарифмическую доходность S&P 500, мы можем наблюдать кластеры высокой величины в определенные периоды, такие как значительные кластеры в 2008–2009 и 2020 годах.

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

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

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

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

Теперь, когда мы получили математическое ожидание и дисперсию процесса Орнштейна-Уленбека, мы можем приступить к моделированию волатильности, используя эту структуру. Для этого мы откалибруем параметры модели по рыночным данным, используя метод оценки максимального правдоподобия (MLE).

Во-первых, мы импортируем необходимые зависимости, включая библиотеки, такие как time, math, numpy, pandas, datetime, scipy, matplotlib, pandas_datareader и функцию plot_acf из модуля статистики. Мы также импортируем данные S&P 500 с 2003 года, которые будут служить нашими рыночными данными.

Далее мы исследуем концепцию кластеризации волатильности в финансовых временных рядах. Кластеризация волатильности относится к явлению, когда за большими изменениями цен обычно следуют другие крупные изменения, а за небольшими изменениями обычно следуют небольшие изменения. Мы наблюдаем этот эффект кластеризации визуально при построении логарифмической доходности S&P 500. Мы видим, что в периоды волатильности рынка величина логарифмической доходности группируется вместе, указывая на корреляцию между большими движениями цены. Например, мы можем наблюдать кластеры во время финансового кризиса 2008-2009 годов и всплеск волатильности в 2020 году.

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

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

Теперь мы вводим формулу Орнштейна-Уленбека (OU), которая используется для моделирования волатильности. Модель OU включает возврат к среднему, средний уровень и волатильность относительно средней цены. Параметры модели включают каппа (скорость возврата к среднему), тета (средний уровень) и сигма (изменчивость). Чтобы оценить эти параметры, мы применяем метод оценки максимального правдоподобия (MLE), который включает в себя поиск значений параметров, которые максимизируют вероятность наблюдаемых данных, поступающих из распределения OU.

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

В случае процесса OU нам необходимо использовать численные методы для нахождения оценок максимального правдоподобия из-за недифференцируемости функции логарифмического правдоподобия. Мы используем функцию scipy.optimize.minimize для минимизации отрицательного логарифмического правдоподобия, поскольку она обеспечивает численное решение задачи максимизации. Определив функцию логарифмического правдоподобия, начальные параметры и ограничения, мы можем оценить параметры, которые максимизируют вероятность наблюдаемых данных.

После того, как мы оценили параметры процесса OU, мы можем смоделировать процесс с помощью Python. Мы можем смоделировать процесс, либо дискретизируя временные шаги и получив путь во времени, либо смоделировав его как процесс Ито с непрерывным временем. Последний метод обеспечивает более точное представление динамики волатильности в определенные моменты времени.

В заключение в тексте обсуждаются характеристики волатильности, наблюдаемые в S&P 500 в периоды рыночной волатильности. Он вводит концепцию кластеризации волатильности и демонстрирует ее наличие с использованием логарифмических и квадратичных логарифмических возвратов. Затем в качестве основы для моделирования волатильности вводится модель Орнштейна-Уленбека (OU), а для оценки параметров модели используется метод оценки максимального правдоподобия (MLE). Наконец, объясняется моделирование процесса OU, что позволяет анализировать и понимать динамику волатильности с течением времени.

 

Волшебная формула торговли опционами без риска



Волшебная формула торговли опционами без риска

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

Для начала давайте разберемся с концепцией нейтральной к риску вероятности. Анализ Фейнмана-Каца позволяет нам определить нейтральную к риску вероятность как меру (Q) конечной нейтральной к риску вероятности в момент времени (t). Кумулятивная функция распределения вероятностей (F) представляет нейтральное к риску распределение вероятностей. Оценка европейского колл-опциона в момент времени (t) со страйком (k) и временем до погашения (tau) может быть выполнена путем принятия нейтрального к риску дисконтированного ожидания выплаты. Это может быть выражено как интеграл от (S_t - k), умноженный на нейтральную к риску функцию плотности (PDF) между страйком (k) и бесконечностью, дисконтированный на безрисковую ставку.

Чтобы рассчитать нейтральную к риску вероятность непосредственно из этой формулы, мы можем использовать формулу Бридена-Литценбергера 1978 года. Она утверждает, что первая производная интеграла по страйку (k) равна минус экспоненциальный коэффициент дисконтирования, умноженный на (1 - F), где F - кумулятивная функция плотности. Вторая производная интеграла, сосредоточенная вокруг страйка (k), извлекает PDF, который представляет собой коэффициент дисконтирования, умноженный на нейтральную к риску PDF.

Теперь давайте обсудим, как применить эту формулу в Python. Нам нужно импортировать такие библиотеки, как NumPy, SciPy, Pandas и Matplotlib. Для примера рассмотрим европейский колл-опцион со стохастической волатильностью по модели Хестона. Модель Хестона обеспечивает динамику базового актива и его волатильность. Мы инициализируем необходимые параметры, такие как цена акции, страйк, время до погашения, безрисковая ставка и параметры модели Хестона, такие как средняя скорость возврата, долгосрочная дисперсия, начальная волатильность, корреляция и волатильность волатильности.

Используя формулу Бридена-Литценбергера, мы можем определить нейтральную к риску функцию распределения вероятностей. Путем аппроксимации второй производной с использованием аппроксимации конечных разностей мы рассчитываем нейтральное к риску распределение для различных значений цен исполнения и времени до погашения. Мы строим 2D PDF для определенного времени до погашения.

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

Мы сравниваем результаты, полученные с помощью прямоугольного интегрирования, с библиотекой QuantLib, которая реализована на языке C и обеспечивает более точное численное интегрирование. Хотя между этими двумя подходами есть некоторые различия, среднеквадратическая ошибка (MSE) невелика. Расхождения в основном связаны с ошибками округления, вызванными двоичным представлением десятичных значений в Python.

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

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

 

Торговая стратегия глубокого обучения от начала до производства с использованием TensorFlow 2.0 и TFX


Торговая стратегия глубокого обучения от начала до производства с использованием TensorFlow 2.0 и TFX

Я рад представиться как Денис и тепло приветствую вас на ClosetoAlgotrading, вашем канале, где вы можете узнать обо всем, что связано с алгоритмической торговлей.

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

Моя цель — всесторонне охватить все промежуточные этапы, включая подготовку данных, тщательное тестирование и многое другое. Забегая вперед, я буду использовать TensorFlow 2.0 и изучать возможности, предлагаемые конвейером tfx. Я намерен избегать сложных расчетов или правил, полагаясь вместо этого на силу глубокого обучения, чтобы выяснить, сможем ли мы создать действительно прибыльное предприятие. Если эта идея находит отклик у вас, я призываю вас подписаться на канал и присоединиться ко мне в этой увлекательной экспедиции. Вместе мы будем ориентироваться в хитросплетениях алгоритмического трейдинга и стремиться раскрыть его скрытый потенциал.

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

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

Чтобы определить характер нашей задачи, мы должны искать ответы на основные вопросы. Если наше исследование вращается вокруг «сколько» или «сколько», мы имеем дело с задачей регрессии. С другой стороны, если мы спрашиваем, «какая категория», мы вступаем в область классификации и так далее. Как только мы поймем тип задачи, которую хотим выполнить, важно определить показатели, которые будут означать успех. В нашем случае эти показатели могут включать рентабельность инвестиций (ROI) и точность. В конце концов, наша конечная цель — получать прибыль от рынка, что требует четкого понимания будущих движений цен.

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

Чтобы первоначально измерить производительность нашей модели при прогнозировании направления, мы можем использовать точность классификации. Эта метрика количественно определяет количество правильных прогнозов, деленное на общее количество прогнозов, умноженное на 100, чтобы выразить его в процентах. А как насчет нашего целевого уровня цен? Для нашей торговой стратегии мы можем определить уровень прибыли в процентах от нашего вложенного капитала. Кроме того, мы должны определить нашу толерантность к риску, установив уровень стоп-лосса как максимально допустимый риск для отдельной сделки. Наши уровни прибыли и стопа служат значениями ROI для каждой сделки. Например, предположим, что мы покупаем акции по цене 100 долларов и продаем их, когда они достигают 105 долларов. Это 5-процентное движение цены принесет 5-процентную прибыль на наши инвестиции. Определив наши уровни выхода, охватывающие как тейк-профит, так и стоп-лосс, мы должны решить проблему времени. Мы не хотим бесконечно ждать, пока цена достигнет желаемого уровня.

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

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

Не пропустите следующую часть нашего путешествия. А пока берегите себя, и я с нетерпением жду нашей следующей встречи.

 

Торговая стратегия глубокого обучения от начала до производства. Часть II.


Торговая стратегия глубокого обучения от начала до производства. Часть II.

Я рад приветствовать вас во второй части нашего увлекательного путешествия по созданию торговой системы. В предыдущем видео мы обсуждали наши цели, а сегодня сосредоточимся на подготовке и маркировке нашего набора данных. Итак, давайте погрузимся прямо в!

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

Кроме того, я ввел в набор данных важный параметр: размер спреда. Спред рассчитывается как разница между ценами Ask и Bid. Почему размер спреда важен? Чтобы проиллюстрировать это, давайте рассмотрим пример, где цена Bid составляет 100 долларов, а цена Ask — 101 доллар. В этом случае спред равен 1 доллару. Если бы мы покупали и сразу же продавали акции, мы всегда теряли бы спред, который в этом примере составляет 1 доллар. Чтобы получить представление о размере спреда, я рассчитал средний спред за все дни для каждой секунды. Как показано на графике, спред обычно колеблется в пределах от 1 до 2 центов, с редкими случаями немного больших спредов. Основываясь на этом анализе, мы можем принять решение о совершении сделок только в том случае, если спред составляет менее 3 центов.

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

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

Чтобы решить эту задачу, я рассчитаю историческую волатильность за день и весь набор данных. Например, представленный график иллюстрирует изменение цены на каждом тике в течение дня вместе с соответствующей волатильностью. Кроме того, мы можем оценить волатильность по всему набору данных. Как показано, средняя волатильность составляет всего 0,003%, что соответствует примерно 30 центам от текущей цены. Однако я не собираюсь использовать окно, охватывающее весь день. Чтобы определить длину окна, я попытался создать 100 окон случайных размеров и оценил среднюю волатильность в каждом окне. Полученный график отображает среднюю волатильность для окон разной длины. Например, выбрав размер окна в 50 баров, мы можем ожидать волатильность около 0,001%.

Это значение волатильности становится полезным для определения нашего минимального ожидаемого дохода и расчета размера нашей цены стоп-лосса. Имея эту информацию на руках, мы можем приступить к созданию баров объема из наших тиковых данных. Использование баров вместо тиков позволяет нам легче рассчитать длину окна, поскольку один бар обычно содержит аналогичный объем, что обеспечивает стабильные условия. Чтобы сгенерировать полосу объема, мы перебираем тики и накапливаем объем до тех пор, пока он не превысит или не сравняется с предопределенным целевым объемом (например, 1000). Тики, встречающиеся во время этой фазы накопления, представляют собой один бар объема. В качестве примера сгенерируем бары объема за один день. Как показано, мы получаем 179 баров для выбранного дня.

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

Теперь, когда мы завершили эти подготовительные шаги, мы готовы создать этикетки. Для этой демонстрации я выбрал размер окна 50 баров и ожидаемую доходность 0,003%, что соответствует примерно 30 центам на основе средней цены. После завершения процесса маркировки мы можем найти несколько похожих меток, известных как перекрестные метки. Чтобы избежать одинаковых меток для разных событий, мы оставим только метки с ближайшим расстоянием между первым баром окна и баром, где цена пересекает барьер окна. При осмотре мы видим, что у нас есть около 700 меток, равномерно распределенных по трем категориям (вверх, вниз и плоско).

Теперь давайте сохраним наш набор данных. Мы создадим два файла: один, содержащий набор данных бара объема, и другой файл, содержащий тиковую информацию для каждого бара. Последнее может оказаться полезным в нашей модели, так что его стоит сохранить. На этом я прерву нашу дискуссию на сегодня. Я считаю, что мы рассмотрели достаточно материала, и тем, кто заинтересован в более глубоком изучении маркировки данных, я рекомендую изучить главы 3 и 4 книги Маркоса Лопеса де Прадо, в которых содержится ценная информация.

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

А пока берегите себя, и я с нетерпением жду нашего следующего видео.

 

Торговая стратегия глубокого обучения от начала до производства. Часть 3. Конвеер TFX.


Торговая стратегия глубокого обучения от начала до производства. Часть 3. Конвеер TFX.

Я очень рад снова приветствовать вас на другом эпизоде «Близко к АлгоТрейдингу» вместе со мной, Денис. Мы возобновили наш эксперимент после новогодних праздников, и хотя прогресс был медленным, мы все еще движемся вперед. В сегодняшнем видео мы более подробно рассмотрим наши размеченные данные и изучим конвейер TFX. Итак, давайте погрузимся прямо в!

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

В нашем фрейме данных столбец «dir» содержит метки, а столбец «cross_idx» представляет номер тика, когда цена пересекает определенное нами окно. Чтобы визуально представить события открытия и закрытия позиции на основе этих столбцов, я создал простую функцию. На графике событие открытия позиции обозначено закрашенным треугольником, а событие закрытия позиции представлено незакрашенным треугольником.

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

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

Для ознакомления с TFX рекомендую изучить официальную веб-страницу Tensorflow TFX, на которой представлена подробная информация о его компонентах и о том, как они взаимосвязаны. Соответствующие ссылки вы найдете в описании видео.

Поскольку я тоже новичок в TFX, мы будем учиться вместе в каждом эпизоде. Сегодня мы сосредоточимся на первых четырех компонентах конвейера. Кратко представим их:

  1. ExampleGen: этот начальный входной компонент конвейера принимает входной набор данных и при необходимости разбивает его на разные подмножества. В нашем случае он напрямую не поддерживает пользовательские разбиения временных рядов, поэтому я вручную разделил данные на наборы данных для обучения, оценки и тестирования.

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

  3. SchemaGen: после изучения статистики компонент SchemaGen создает схему данных на основе наблюдаемых характеристик данных. Схема описывает структуру и свойства наших данных.

  4. ExampleValidator: этот компонент проверяет наличие аномалий и отсутствующих значений в наборе данных, используя статистику и схему в качестве ссылок. Это помогает выявить любые неожиданные или противоречивые шаблоны данных.

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

Теперь давайте вернемся к нашим собственным данным. После импорта необходимых модулей и установки необходимых переменных для папок входных и выходных данных мы можем попытаться загрузить наши данные в конвейер TFX. Входная папка содержит вложенные папки для наборов данных для оценки, обучения и тестирования.

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

В результате компонент ExampleGen создает два артефакта: один для набора данных для обучения, а другой для набора данных для оценки. Давайте рассмотрим первые три элемента нашего обучающего набора, чтобы убедиться, что он соответствует нашему исходному набору данных. Двигаясь дальше, мы передаем выходные данные из компонента ExampleGen в компонент StatisticsGen. Этот компонент создает статистические артефакты как для наборов данных для обучения, так и для наборов данных для оценки. С помощью всего одной команды мы можем визуально представить статистику набора данных, включая распределение данных, стандартное отклонение, пропущенные значения и многое другое.

Здесь мы можем наблюдать статистику набора обучающих данных, получая ценную информацию о характеристиках данных. Мы также можем изучить тот же набор статистических данных для оценочного набора. Основываясь на статистике, мы замечаем, что только 2% наших меток отличны от нуля, что позволяет предположить, что наши события входа для прибыльных сделок могут быть выбросами. Это может стать проблемой в будущем из-за дисбаланса между классами.

Далее мы автоматически генерируем схему данных с помощью компонента SchemaGen. Эта схема получена из наблюдаемой статистики, но мы также можем определить собственное описание данных, если это необходимо. Результатом является схема, которая обеспечивает исчерпывающее описание структуры и свойств наших данных. Наконец, мы достигаем компонента ExampleValidator, который проверяет данные на основе сгенерированной статистики и схемы. Он проверяет любые аномалии или несоответствия в наборе данных. Например, в примере с такси в Чикаго функция «_company» имела неожиданное строковое значение. Мы можем использовать ExampleValidator для обнаружения таких проблем в нашем собственном наборе данных.

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

Спасибо за просмотр, и я с нетерпением жду встречи с вами в следующем видео!

 

Часть IV. Торговая стратегия глубокого обучения от начала до производства. Конвеер TFX 2.


Часть IV. Торговая стратегия глубокого обучения от начала до производства. Конвейер TFX 2.

Добро пожаловать в очередной выпуск «Близко к алготрейдингу». Меня зовут Денис, и сегодня мы продолжим изучение конвейера TFX в рамках построения нашей торговой стратегии.

В предыдущем видео мы рассмотрели первые четыре компонента конвейера TFX: ExampleGen, StatisticsGen, SchemaGen и ExampleValidator. Эти компоненты заложили основу для нашего пайплайна, обеспечив проверку и согласованность данных.

Теперь давайте погрузимся в оставшиеся компоненты: Transformer, Trainer, Evaluator, ModelValidator и Pusher. Эти компоненты позволят нам преобразовать наши данные, обучить нашу модель, оценить ее производительность, проверить модель по сравнению с базовым уровнем и, наконец, отправить проверенную модель в производственную среду.

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

Компонент Transform отвечает за преобразование данных и разработку функций, которые подходят как для обучения, так и для обслуживания. Это означает, что мы можем использовать одну и ту же функцию преобразования данных как для обучения модели, так и для ее использования в производстве. Эта функциональность — одна из главных причин, по которой я начал изучать TFX.

Чтобы начать процесс преобразования, нам нужно создать пару файлов Python. Первый файл будет содержать наши константы, такие как список числовых признаков и меток. Второй файл будет содержать функцию предварительной обработки (preprocessing_fn), которая является функцией обратного вызова, используемой tf.Transform для предварительной обработки входных данных. В этой функции мы определим этапы преобразования данных и построения признаков. А пока давайте сосредоточимся на преобразовании всех числовых входных признаков в z-значения и изменении значений меток с -1, 0 и 1 на 0, 1 и 2 соответственно. Это преобразование метки необходимо, поскольку средство оценки TensorFlow ожидает положительные значения.

Важно отметить, что в текущей версии TFX поддерживаются только оценщики TensorFlow. Если вы предпочитаете использовать модель Keras, вам необходимо преобразовать ее в оценщик с помощью API model_to_estimator. Хотя TFX версии 0.21 утверждает, что поддерживает модели Keras для компонента Trainer, я столкнулся с некоторыми проблемами с его функциональностью интерактивного контекста. Надеемся, что команда TFX скоро решит эти проблемы и предоставит стабильный и полнофункциональный инструмент.

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

В файле Python, содержащем нашу модель и входные функции, мы определяем функцию train_fn, которая будет вызываться компонентом Trainer. Эта функция должна возвращать словарь со следующими элементами:

  • оценщик: оценщик TensorFlow, используемый для обучения модели.
  • train_spec: конфигурация обучающей части вызова TensorFlow train_and_evaluate().
  • eval_spec: конфигурация для оценочной части вызова TensorFlow train_and_evaluate().
  • eval_input_receiver_fn: конфигурация, используемая компонентом ModelValidator при проверке модели.

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

Чтобы создать наш оценщик, мы определяем функцию build_estimator. В этой функции мы настраиваем входной набор функций и создаем нашу оценку. Стоит отметить, что я использовал DNNLinearCombinedEstimator, потому что DNNClassifier и DNNEstimator вызывали ошибки, связанные с передачей функций из TensorFlow 1. Я считаю, что это не так, поскольку мы используем методы TensorFlow 2. К сожалению, я не нашел решения этой проблемы. Тем не менее, линейная оценка работает нормально.

Теперь, когда наша модель определена, мы можем приступить к ее обучению с помощью компонента Trainer. Как видите, компонент Trainer ожидает файл module_file, который содержит функцию Trainer_fn вместе с другими параметрами, такими как transform_examples, схема данных, график преобразования, а также аргументы обучения и оценки. На данный момент мы указали только количество шагов для обучения и оценки. После завершения обучения модели мы можем перейти к анализу модели с использованием анализа моделей TensorFlow (TFMA). Прежде чем мы продолжим, убедитесь, что вы установили TFMA, перейдя по предоставленной ссылке. TFMA позволяет нам выполнять анализ нашей модели либо по всему набору данных, либо по отдельным фрагментам признаков. В этом случае мы проведем анализ трех срезов: полного набора данных, метки и двух конкретных функций.

Анализируя полный набор данных, мы наблюдаем замечательную точность в 98 процентов. Однако при изучении производительности модели на основе меток мы замечаем, что она постоянно предсказывает метку 0. Такой результат был ожидаем из-за несбалансированных меток и отсутствия полезных функций в нашей модели. Тем не менее, TFMA предоставляет удобный способ оценить производительность модели.

Двигаясь вперед, у нас есть компонент ModelValidator, который помогает нам проверять наши экспортированные модели. Он сравнивает новые модели с базовыми показателями (например, с текущей моделью) и определяет, соответствуют ли они предопределенным критериям. Эта проверка включает в себя оценку моделей в наборе данных eval и вычисление показателей, таких как AUC и потери. Если показатели новой модели удовлетворяют указанным разработчиком критериям по отношению к базовому уровню, модель считается «достаточно хорошей» и помечается как таковая.

Наконец, у нас есть компонент Pusher, который проверяет, прошла ли модель проверку. Если модель соответствует критериям проверки, она помещается в указанный файл назначения. Этот шаг гарантирует, что только проверенные модели будут развернуты в производственной среде.

Чтобы завершить наш конвейер, мы можем экспортировать все компоненты в конвейер Apache Beam. Затем мы можем упаковать все необходимые файлы в zip-архив. Распаковав файлы из архива в нашу рабочую директорию на сервере, мы можем выполнить пайплайн. После завершения выполнения у нас будет обученная модель, готовая к использованию с TensorFlow Serving. Если вам интересно узнать, как запустить и использовать TensorFlow Serving из контейнера Docker, вы можете найти видеоруководство на моем канале.

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

В следующем видео мы вернемся к нашей основной цели — разработке торговой стратегии. Оставайтесь с нами! Не забывайте комментировать, подписываться и ставить лайк этому видео. Спасибо за просмотр, и увидимся в следующем!

 

Часть V. ГИГО. Торговая стратегия глубокого обучения от начала до производства.


Часть V. ГИГО. Торговая стратегия глубокого обучения от начала до производства.

Добро пожаловать в очередной выпуск «Близко к алготрейдингу». Меня зовут Денис, и я здесь, чтобы поделиться своим опытом и неудачами в разработке торговой системы с глубоким обучением.

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

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

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

Теперь важно помнить, что нейронная сеть не предназначена для творения чудес. Возможно, пришло время пересмотреть наш подход. События, которые мы пытаемся предсказать, составляют всего 2% всего набора данных. Эти события можно считать выбросами, и наша простая сеть изо всех сил пытается отличить их от остальных данных. Кроме того, существует высокая вероятность того, что эти события не связаны между собой и имеют разные причины, что затрудняет построение модели, которая точно предсказывает их.

Учитывая эти проблемы, стало очевидно, что нам нужно сосредоточиться на лучшем понимании данных и выявлении признаков с предсказательной силой. Имея это в виду, я решил вернуться к простой стратегии скользящих средних. В нашем первоначальном подходе нам не хватало четкого понимания того, почему мы должны открывать позицию. Однако теперь у нас есть стратегия открытия позиций. Хотя это не идеально, это широко используемая стратегия, которую мы можем использовать. Я добавил в наш набор данных две скользящие средние и индикатор RSI (индекс относительной силы) и собрал все события, в которых скользящие средние пересекались друг с другом. Это позволило оценить направления движения цены.

Затем я создал мета-метки, используя тот же метод маркировки, что и раньше, но на этот раз я пометил только те столбцы, где скользящие средние пересекаются друг с другом. Здесь есть важное отличие: поскольку мы уже знаем направление позиции (длинная или короткая), значение наших меток будет другим. Метка 1 указывает на прибыль, -1 представляет убыток, а 255 назначается для других случаев. С обновленным набором данных и метками я обучил простую модель LSTM и получил идеальную кривую ROC (рабочая характеристика приемника). Кривая ROC показывает производительность модели классификации при различных порогах классификации. Значение AUC (площадь под кривой) кривой ROC помогает нам оценить, насколько хорошо модель различает классы.

Однако при изучении прогнозов модели я заметил, что она постоянно предсказывает класс 0. Такой результат произошел потому, что я снова использовал весь набор данных, а не только соответствующие события. Наш набор данных оставался несбалансированным, а функциям не хватало предсказательной способности. Кривые ROC не идеальны для несбалансированных наборов данных, поскольку они могут маскировать плохую производительность модели при прогнозировании других классов.

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

Как я упоминал ранее, для нас крайне важно понимать наши данные и определять процессы, которые могут помочь нам найти способ победить рынок.

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

 

Часть VII. Обучение с подкреплением. Торговая среда.


Часть VII. Обучение с подкреплением. Торговая среда.

Меня зовут Денис, и вы смотрите "Близко к АлгоТрейдингу". В нашем последнем выпуске мы представили краткое введение в обучение с подкреплением. Сегодня мы погрузимся в создание простой торговой среды для нашего агента. Давайте изучим детали.

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

Далее нам нужно определить действия, которые может выполнять наш агент. Должен ли он быть ограничен действиями «купить» и «продать», или он также может пропускать определенные шаги? Определение пространства действия имеет решающее значение для процесса принятия решений нашим агентом.

Теперь давайте обсудим цель и то, как мы будем определять награды. В реальном мире торговая среда имеет непрерывное пространство состояний. Однако для простоты давайте сделаем среду как можно более простой, что позволит нам понять ее внутреннюю работу и реализацию.

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

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

Учитывая типичные торговые действия, мы включим «покупка» и «продажа» для случаев, когда ни одна позиция не открыта. Однако, если уже есть открытая позиция, агент может только пропустить или закрыть позицию. Таким образом, в этом сценарии действие «продать» или «купить» эквивалентно «пропустить».

Цель нашего агента — максимизировать прибыль и убытки (PnL) за 10-дневный период. Поэтому мы определим награду как ежедневный PnL.

Имея четкое представление о структуре и поведении нашей среды, мы можем перейти к этапу реализации. Как упоминалось ранее, мы будем использовать фреймворк TensorFlow (tf-agent). Команда tf-agent предоставила исчерпывающее руководство по разработке подходящей среды для tf-agent, с которым я рекомендую ознакомиться для более глубокого понимания кода.

Чтобы создать нашу среду, мы начнем с наследования класса PyEnvironment, поскольку он определяет интерфейс, который должны реализовать все среды Python. В функции Init мы инициализируем переменные, устанавливаем начальные состояния и, что наиболее важно, указываем спецификации действия и наблюдения. В нашем случае пространство действий будет состоять из четырех различных действий с минимальным и максимальным значениями, равными 0 и 3 соответственно. Спецификация наблюдения будет описывать состояние среды с ценой, начинающейся с 0, без максимального ограничения. Тип данных для цен будет плавающим. Возврат спецификаций действия и наблюдения имеет решающее значение для бесшовной интеграции с tf-agent.

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

Теперь давайте обсудим самую важную функцию: шаг. Пошаговая функция получает действие в качестве входного параметра и отвечает за управление переходами состояний среды. В этой функции мы обработаем все возможные действия и рассчитаем PnL (вознаграждение). Функция возвращает time_step, который состоит из наблюдения (часть состояния среды, которую агент может наблюдать, чтобы выбрать свои действия на следующем шаге), вознаграждения (цели обучения агента), step_type (указывает, является ли этот временной шаг максимальным). первый, промежуточный или последний в последовательности) и скидка.

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

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

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

Я провел несколько тестов с использованием простого tf-агента DQN, и вот результаты. После 20 000 шагов агент продемонстрировал приемлемую производительность. Однако имейте в виду, что у нас был только один временной ряд для изучения агентом, что делало его относительно простым. Если мы введем второй временной ряд и запустим 20 000 шагов, результаты могут быть не такими многообещающими. Но примерно после 100 000 шагов производительность агента значительно улучшилась.

 

Часть VIII. Торговая стратегия обучения с подкреплением. DQN: QNetwork, QRNNNetwork


Часть VIII. Торговая стратегия обучения с подкреплением. DQN: QNetwork, QRNNNetwork

Здравствуйте, меня зовут Денис, и вы смотрите «Рядом с АлгоТрейдингом». В этом видео мы кратко расскажем о нашей предыдущей среде для агента обучения с подкреплением. Мы также дадим краткое описание Q-Learning и агента DQN. Затем мы приступим к реализации основных этапов обучения для агента rDQN из библиотеки tf-agents и обсудим результаты тестирования.

Для начала давайте вернемся к торговой среде, которую мы создали в предыдущем видео. В этой среде мы использовали синтетические сгенерированные данные. Однако в этой обновленной версии наша среда будет получать фрейм данных с историческими данными в качестве входных параметров. Observation_spec для среды представляет собой словарь с двумя ключами: «Цена» и «Позиция». Ключ «Цена» содержит 20 элементов с данными об открытии, закрытии, максимуме, минимуме и объеме. Ключ "Pos" содержит информацию о нашей открытой позиции.

В начале каждого эпизода мы случайным образом выбираем фрагмент из 20 цен из наших данных. Это изменение позволяет нашему агенту обучения с подкреплением учиться на реальных исторических данных.

Двигаясь дальше, давайте обсудим Q-Learning и концепцию Q-Table. Q-Learning включает присвоение Q-значения каждой паре (состояние, действие). Эта таблица, известная как таблица Q, используется агентом для выбора действий с максимальным значением Q в текущем состоянии. Агент исследует окружающую среду, получает награды и обновляет значения Q на основе наблюдаемых наград.

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

Однако в нашем случае финансовый рынок имеет очень широкое пространство состояний, что делает использование Q-таблицы нецелесообразным. Чтобы преодолеть эту проблему, мы можем использовать глубокую нейронную сеть для прогнозирования значений Q для данного состояния. Этот подход, известный как агент DQN (агент Deep Q-Network), использует Q-сеть, где значения Q обновляются за счет минимизации потерь при обратном распространении. Функция потерь, используемая в агенте DQN, задается специальным уравнением.

Теперь, когда у нас есть хорошее представление о Q-Learning и агенте DQN, давайте приступим к реализации основных шагов обучения для агента rDQN с использованием библиотеки tf-agents.

Общий алгоритм обучения состоит из следующих шагов:

  1. Создайте среду.
  2. Создайте агента.
  3. Собирать данные из среды с помощью некоторой политики.
  4. Обучите агента, используя собранные данные.
  5. Проверьте работу агента.
  6. Повторите с шага 3.

Создание среды — непростая задача. Мы оборачиваем нашу торговую среду в TFPyEnvironment, что обеспечивает бесшовную интеграцию с tf-агентами.

Далее мы создаем Q-Network для агента DQN. Библиотека tf-agents предоставляет класс Q-Network, который мы можем использовать для определения нашей Q-сети. Мы определяем простую Q-сеть с одним скрытым полносвязным слоем, состоящим из 40 нейронов. Поскольку наше наблюдение представляет собой словарь, мы также определяем для него простой слой предварительной обработки.

Создав Q-Network, мы приступаем к созданию агента DQN. Мы создаем экземпляр класса tf_agents.agents.dqn.dqn_agent, передавая нашу Q-сеть в качестве параметра. Мы также определяем оптимизатор и функцию потерь для обучения модели.

Для обучения агента нам нужны данные из окружения. Мы собираем эти данные с помощью политики, и на этом этапе мы можем случайным образом выбирать действия. Агент DQN имеет две политики: agent.policy, которая используется для оценки и развертывания, и agent.collect_policy, которая используется для сбора данных.

Сбор данных включает в себя получение текущего состояния, выбор действия, получение следующего состояния и вознаграждения и сохранение этой информации в буфере. Мы собираем несколько шагов или эпизодов, формируя траектории. Библиотека tf-agents предоставляет драйвер DynamicEpisodeDriver, который собирает шаги до конца эпизода. Драйвер обновляет наблюдателей, включая буфер ответов.

Для хранения данных мы можем использовать обычно используемый TFUniformReplayBuffer из библиотеки tf-agents. Мы определяем спецификации элементов данных, которые будут храниться в буфере, размер пакета и максимальную длину каждого сегмента пакета.

После завершения этапа сбора данных мы можем обучить нашего агента. Агенту требуется доступ к буферу воспроизведения. Мы создаем конвейер tf.data.Dataset для передачи данных агенту. Каждая строка буфера воспроизведения хранит одну траекторию, но агенту DQN нужны как текущие, так и следующие наблюдения для вычисления потерь. Поэтому мы устанавливаем для параметра num_steps значение 2, что позволяет конвейеру набора данных выбирать две строки для каждого элемента в пакете.

На данный момент у нас есть все необходимое для обучения двух агентов DQN на одних и тех же данных и оценки их производительности. Один агент использует простую Q-сеть, а другой использует QRNNNetwork. Оба агента обучены с использованием исторических ценовых данных за 200 дней.

После 700 шагов обучения мы видим, что простой агент Q-Network мало чему научился и в основном показывает отрицательную среднюю отдачу. Однако агент QRNNNetwork в основном показывает положительную среднюю доходность. Этот результат соответствует ожиданиям, поскольку агент RNN может фиксировать некоторую динамику данных и быстрее обучаться.

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

Спасибо за просмотр, увидимся в следующем выпуске.

 

Часть IX Торговая стратегия обучения с подкреплением. DQN: тестирование торговой стратегии на основе агентской политики


Часть IX Торговая стратегия обучения с подкреплением. DQN: тестирование торговой стратегии на основе агентской политики

Я рад сообщить, что мы достигли важной вехи на нашем пути: тестирования нашей стратегии. Для этой цели мы будем использовать простую среду Python для тестирования на истории для проведения наших тестов. Для начала вы можете установить фреймворк, выполнив команду «pip install», за которой следует имя фреймворка.

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

Один интересный аспект заключается в том, что мы можем загрузить нашу сохраненную политику с помощью TensorFlow API. Поскольку мы используем QRNNNetwork, нам нужно получить начальное состояние политики. Следовательно, мы реализовали функцию инициализации. Теперь пришло время реализовать функцию «следующий», которая будет вызываться для каждого нового шага. В начале нам нужно собрать данные за первые 10 дней, а затем мы можем заполнить наш словарь наблюдений. С каждым шагом мы обновляем наблюдение и передаем его в политику.

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

Далее нам нужно обновить наши состояния позиций и выполнить действие. Наконец, в конце «следующей» функции мы увеличиваем счетчик и сбрасываем все в начальные состояния, чтобы имитировать начало нового эпизода. Большой! Мы успешно реализовали нашу стратегию. Теперь нам нужны некоторые данные для целей тестирования. Мы можем использовать библиотеку panda_datareader для получения ежедневных данных из Yahoo Finance. Давайте начнем с тестирования нашей стратегии на акциях Intel, используя исторические данные за один год.

Мы создаем объект бэктеста и начинаем тестирование. Результаты теста показывают отдачу 106%, что впечатляет. Однако важно отметить, что структура тестирования на исторических данных начинает расчеты со 100%, что означает, что наша фактическая прибыль составляет всего 6%. Тем не менее, это неплохой результат, учитывая, что наш политик не был тщательно обучен. Чтобы дать более полную оценку, давайте также протестируем нашу стратегию на акциях AMD. Как видите, результат для AMD показывает падение примерно на 40%. Таким образом, мы можем сравнить эффективность нашей стратегии на акциях AMD и Intel.

Теперь вы знаете, как использовать политику агента с платформой тестирования на истории. Точно так же, если вы используете Python для своей реальной торговой среды, вы можете использовать политику таким же образом. Однако для тех, кто использует другие языки, вы можете развернуть политику с помощью среды Flask и получить к ней доступ через REST API.

Я надеюсь, что вы нашли эти видео интересными и информативными. Если да, рассмотрите возможность подписки, и увидимся в следующем эпизоде.