Pull to refresh

Deep Q Trading: объектно-ориентированный код на R

Reading time4 min
Views1.8K
Original author: Alexey Burnakov


Привет! Это перевод еще одной моей статьи, посвященной обучению с подкреплением (reinforcement learning). Эту итерацию даже предложили запостить в блоге Веды аналитики. :)

В двух прошлых статьях на эту тему: 1 и 2 я пробовал создать и запустить обучение с подкреплением для задачи трейдинга на синтетических и реальных данных. Тогда я опубликовал код нейронной сети, чтобы помочь вам начать ваши проекты. На этот раз я публикую весь код эксперимента, который я создал, используя язык для анализа данных R, обогащенный классами R6, чтобы упростить погружение в эту тему. Даже если ваше ежедневное программирование связано с использованием Python, Java или C, вы, вероятно, найдете ООП R6 довольно удобным. Надеюсь, вам понравится высокоуровневость кода. Заходите на мой репозиторий кода, клонируйте и запустите его!

Вспомним о том, что было сделано


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

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

Экспериментальная логика


После того, как вы установили пакеты в соответствии с рекомендациями, можно запускать main.R из командной строки, консоли R или с помощью RStudio IDE. Если вам нужен полный контроль над опциями, RStudio — ваш первый выбор в качестве удобного и удобного редактора. Запуск из командной строки идет без переменных окружения.

Код
setwd('C:/R_study/reinforcement/rl_classes') # set your working directory


## Classes

source('NN_class.R')

source('DATA_class.R')

source('RB_class.R')

source('LOGS_class.R')

source('TRAIN_class.R')


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

Dat <- Data$new()


Мы создаем объект класса Data и на этом объекте вызываем метод для получения временных рядов. У вас есть несколько вариантов: синтетический шум, синтетический сигнал и реальные биржевые данные от Yahoo. По умолчанию синтетический сигнал будет вашей временной серией как игрушечная проблема.

Код
# Dat$synthetic_noise(
# 	noise_sd = 0.1
# 	, n = 20000
# )
# 
# Dat$stock_data(
# 	symbol_name = 'AAPL'
# 	, from = "2000-01-01"
# 	, to = "2020-03-01"
# 	, dat.env = new.env()
# )

Dat$synthetic_signal(
	stepsize = 0.1
	, noise_sd = 0.1
	, noise_sd2 = 0.0
	, n = 50000
	)


Вы можете создать очень простой (синусоидальный) сигнал. Сделайте более сложный сигнал, увеличив значения стандартного отклонения шума _sd.

Код
Dat$make_features(max_lag_power = 6)


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

Код
## Double neural networks

Nn <- NN$new(lstm_seq_length = 8L)

Nn$compile_nn(
	loss = 'mse'
	, metrics = 'mse'
	, optimizer = 'adam'
)

Nn2 <- Nn$clone()


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

Из-за двойной логики изучения значений q нам нужны 2 нейронные сети, которые будут запускаться случайным образом (этот код можно просмотреть в методах Train).

Код
## Replay buffer

Rb <- RB$new(
	buffer_size = 512
	, priority_alpha = 0.1
	)

Rb$init_rb()


Буфер воспроизведения (Replay buffer) — это объект-таблица data.table, который хранит прошлые траектории, а также является источником данных для обучения модели НС. Создание приоритетной выборки требует дополнительного параметра, который определяет четкость распределения вероятностей по строкам RB во время выборки.

Код
## Logging

Log <- Logs$new()


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

Tr <- Train$new()

Tr$run(
	test_mode = F
	, batch_size = 4
	, discount_factor = 0.99
	, learn_rate = 0.01
	, max_iter = 12000
	, min_trans_cost = 0
	, print_returns_every = 100
	, magic_const = 1
)


Вот так. Обучение началось. Я советую вам прочесть о параметрах Q-learning, чтобы вы свободно владели этой частью. Одним интересным параметром является print_returns_every, который определяет частоту появления промежуточного отчета об обучении в процессе. Отчет может выглядеть следующим образом, если обучение хорошо:



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



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

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

Код
## Save NN

Nn$save()


Если результат вас устраивает, вызовите метод сохранения модели.

Формирование наград и презентаций еще не было внесено в сценарий.

Напутствие


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

Посмотрите методы внутри классов, чтобы изменить архитектуру НС, подать свой собственный поток данных, сформировать входные признаки состояния или изменить логику эксперимента. Я разместил методы по классам так, чтобы ничего лишнего не «торчало», но при этом был доступ к измененным объектам, таким как НС, логи обучения и буфер.

Возможно, что запуски модели долго не будут давать хорошее решение. Сходимость довольно медленная и неустойчивая. Я наблюдаю заметные признаки того, что модель обучилась, примерно, после 10 000 итераций и более. А на реальных биржевых данных, ограниченных длиной истории, этого вообще может не произойти после полного прохода данных. Но я думаю, что, как и мне, вам может будет интересно поразбираться и потратить какое-то время на улучшение модели.

Удачи в обучении с подкреплением!
Tags:
Hubs:
Total votes 9: ↑9 and ↓0+9
Comments2

Articles