Глава 296: DQN для управления портфелем
Введение
Глубокие Q-сети (DQN) фундаментально трансформировали обучение с подкреплением с момента их знакового успеха в обучении игре в Atari непосредственно по пиксельным изображениям. Ключевая идея — нейронная сеть может аппроксимировать функцию ценности действий Q(s, a) для выбора оптимальных действий — естественно распространяется на управление портфелем, где агент должен решать, как распределять капитал между несколькими активами на каждом временном шаге.
Традиционные методы оптимизации портфеля, такие как оптимизация средне-дисперсионная (MVO), опираются на оценки распределений доходности, которые, как известно, нестабильны. Стратегии паритета риска и минимальной дисперсии обходят оценку доходности, но игнорируют потенциальные альфа-сигналы. Портфельная торговля на основе DQN предлагает принципиально иной подход: агент обучает оптимальную политику распределения непосредственно по рыночным данным путём проб и ошибок взаимодействия с моделируемой торговой средой, не требуя явных прогнозов доходности.
При управлении портфелем агент DQN наблюдает состояние, включающее недавние движения цен, текущие веса портфеля и потенциально вспомогательные признаки. Он выбирает дискретное действие ребалансировки — например, «увеличить вес BTC на 10% и уменьшить вес ETH на 10%» — и получает вознаграждение на основе доходности портфеля за вычетом транзакционных издержек. За тысячи эпизодов агент обнаруживает стратегии распределения, адаптирующиеся к изменяющимся рыночным режимам.
В этой главе реализована полная система портфельной торговли на основе DQN на языке Rust, включающая три основных улучшения, особенно важных для финансовых приложений: Double DQN для уменьшения смещения переоценки, архитектуру Dueling-сети для разделения ценности состояния от преимуществ действий и приоритизированный воспроизведение опыта (PER) для эффективного обучения на редких, но важных рыночных событиях. Мы получаем реальные мультиактивные данные с Bybit (BTC, ETH, SOL) и обучаем агента, который учится динамически ребалансировать между этими активами.
Математические основы
Пространство состояний
Состояние на временном шаге t кодирует информацию, необходимую агенту для принятия решений о распределении. Вектор состояния определяется как конкатенация:
Ценовые признаки для каждого актива i в юниверсе из N активов:
$$s_t^{price} = \left[ r_{t-k,i}, r_{t-k+1,i}, \ldots, r_{t-1,i} \right]_{i=1}^{N}$$
где $r_{t,i} = \frac{p_{t,i} - p_{t-1,i}}{p_{t-1,i}}$ — логарифмическая доходность актива i в момент t, а k — окно ретроспективного анализа.
Текущие веса портфеля:
$$s_t^{weights} = \left[ w_{t,1}, w_{t,2}, \ldots, w_{t,N} \right]$$
где $w_{t,i} \geq 0$ и $\sum_{i=1}^{N} w_{t,i} = 1$.
Признаки волатильности (скользящее стандартное отклонение доходности):
$$\sigma_{t,i} = \sqrt{ \frac{1}{k-1} \sum_{j=0}^{k-1} (r_{t-j,i} - \bar{r}_{t,i})^2 }$$
Полный вектор состояния:
$$s_t = \left[ s_t^{price}, s_t^{weights}, \sigma_{t,1}, \ldots, \sigma_{t,N} \right] \in \mathbb{R}^{d}$$
где $d = N \cdot k + N + N = N(k + 2)$.
Пространство действий
Для вычислительной управляемости мы дискретизируем непрерывное пространство весов портфеля. Определяем набор дискретных действий ребалансировки. При N активах каждое действие задаёт сдвиг веса для каждого актива с шагом $\delta$:
$$a \in \mathcal{A} = { (\Delta w_1, \Delta w_2, \ldots, \Delta w_N) \mid \Delta w_i \in {-\delta, 0, +\delta}, \sum_i \Delta w_i = 0 }$$
Ограничение $\sum_i \Delta w_i = 0$ обеспечивает сохранение нормализации весов. После применения действия a новые веса:
$$w_{t+1,i} = \text{clip}(w_{t,i} + \Delta w_i, 0, 1)$$
с последующей ренормализацией, чтобы $\sum_i w_{t+1,i} = 1$.
Для 3 активов с шагом $\delta = 0.1$ это даёт управляемое пространство действий из примерно 19 различных действий (включая действие «удержания», где все сдвиги равны нулю).
Функция вознаграждения
Вознаграждение отражает доходность портфеля с учётом транзакционных издержек:
$$r_t = \sum_{i=1}^{N} w_{t,i} \cdot R_{t,i} - c \sum_{i=1}^{N} |w_{t,i} - w_{t-1,i}|$$
где $R_{t,i}$ — доходность актива i в момент t, а c — коэффициент транзакционных издержек.
Уравнение Беллмана и Q-обучение
Оптимальная функция ценности действий удовлетворяет уравнению оптимальности Беллмана:
$$Q^(s, a) = \mathbb{E}\left[ r + \gamma \max_{a’} Q^(s’, a’) \mid s, a \right]$$
где $\gamma \in [0, 1)$ — коэффициент дисконтирования. DQN аппроксимирует $Q^*$ нейронной сетью с параметрами $\theta$:
$$Q(s, a; \theta) \approx Q^*(s, a)$$
Функция потерь для обучения:
$$\mathcal{L}(\theta) = \mathbb{E}{(s,a,r,s’) \sim \mathcal{D}} \left[ \left( r + \gamma \max{a’} Q(s’, a’; \theta^{-}) - Q(s, a; \theta) \right)^2 \right]$$
где $\theta^{-}$ — параметры периодически обновляемой целевой сети, а $\mathcal{D}$ — буфер воспроизведения опыта.
Улучшения DQN для финансов
Double DQN
Стандартный DQN имеет тенденцию переоценивать Q-значения, поскольку одна и та же сеть выбирает и оценивает действия. В финансах переоценка приводит к чрезмерно уверенному распределению в волатильные активы. Double DQN разделяет выбор и оценку:
$$y_t^{DDQN} = r_t + \gamma Q(s_{t+1}, \arg\max_{a’} Q(s_{t+1}, a’; \theta); \theta^{-})$$
Онлайн-сеть $\theta$ выбирает лучшее действие, но целевая сеть $\theta^{-}$ его оценивает. Это даёт более консервативные и стабильные портфельные распределения.
Архитектура Dueling-сети
Архитектура dueling разделяет Q-функцию на функцию ценности состояния $V(s)$ и функцию преимущества $A(s, a)$:
$$Q(s, a; \theta, \alpha, \beta) = V(s; \theta, \beta) + \left( A(s, a; \theta, \alpha) - \frac{1}{|\mathcal{A}|} \sum_{a’} A(s, a’; \theta, \alpha) \right)$$
Для управления портфелем это особенно ценно. Поток ценности обучается определять, какие рыночные состояния в целом благоприятны (трендовые рынки, режимы низкой волатильности), тогда как поток преимущества обучается определять, какие конкретные действия ребалансировки лучше среднего в каждом состоянии. Это разложение ускоряет обучение, поскольку функция ценности может обновляться из каждого опыта, независимо от выбранного действия.
Приоритизированное воспроизведение опыта
Финансовые рынки характеризуются редкими, но критическими событиями — внезапные обвалы, развороты трендов, смены режимов. Стандартная равномерная выборка из буфера воспроизведения недооценивает эти переходы. Приоритизированное воспроизведение опыта (PER) выбирает переходы пропорционально их ошибке временной разности (TD):
$$P(i) = \frac{p_i^{\alpha}}{\sum_k p_k^{\alpha}}$$
где $p_i = |\delta_i| + \epsilon$ — приоритет перехода i, $\delta_i$ — ошибка TD, а $\alpha$ контролирует степень приоритизации. Веса importance sampling корректируют смещение:
$$w_i = \left( \frac{1}{N \cdot P(i)} \right)^{\beta}$$
где $\beta$ постепенно увеличивается от начального значения к 1 в процессе обучения.
Для торговли PER обеспечивает, что агент повторно посещает и обучается на экстремальных рыночных движениях и других высокоэффективных событиях, непропорционально важных для управления рисками.
Реализация на Rust
Наша реализация на Rust предоставляет несколько преимуществ для производственных торговых систем. Абстракции с нулевой стоимостью Rust обеспечивают производительность, близкую к C, для вычислительно интенсивных прямых и обратных проходов нейронной сети. Система владения предотвращает гонки данных при потенциальном многопоточном обучении. А строгая система типов обнаруживает несоответствия размерностей во время компиляции.
Обзор архитектуры
Реализация состоит из следующих основных компонентов:
-
MultiAssetState— Кодирует истории цен, текущие веса портфеля и признаки волатильности в плоский вектор состояния, подходящий для входа нейронной сети. -
ActionSpace— Перечисляет все допустимые дискретные действия ребалансировки, сохраняющие ограничение нормализации весов. -
DuelingNetwork— Сеть прямого распространения с общими слоями признаков, разделяющимися на потоки ценности и преимущества, реализующая архитектуру dueling. -
ReplayBuffer— Хранит кортежи опыта $(s, a, r, s’, done)$ с приоритетами на основе TD-ошибки для приоритизированной выборки. -
DQNAgent— Координирует обучение с epsilon-жадным исследованием, обновлениями целевой сети Double DQN и периодической синхронизацией целевой сети. -
BybitClient— Получает исторические данные OHLCV для нескольких активов через REST API Bybit.
Ключевые проектные решения
- Нормализация состояния: Доходности и волатильности нормализуются по z-оценке с использованием скользящей статистики для улучшения стабильности обучения.
- Маскирование действий: Действия, которые привели бы к отрицательным весам, маскируются перед argmax, предотвращая недопустимые портфели.
- Мягкие обновления целевой сети: Вместо периодического жёсткого копирования используется усреднение Поляка: $\theta^{-} \leftarrow \tau \theta + (1 - \tau) \theta^{-}$ с $\tau = 0.005$.
- Формирование вознаграждения: Используются доходности с поправкой на риск (типа Шарпа), а не сырые доходности для поощрения осознанного отношения к риску.
Данные Bybit по нескольким активам
Мы используем API Bybit для получения исторических данных свечей по трём основным криптовалютным активам:
- BTC/USDT — Биткойн, доминирующая криптовалюта с высокой ликвидностью
- ETH/USDT — Ethereum, второй по величине актив, часто коррелированный, но с отличающейся динамикой
- SOL/USDT — Solana, актив с более высокой бетой, предлагающий возможности диверсификации
Конечная точка REST API Bybit /v5/market/kline предоставляет данные OHLCV с различными интервалами. Мы получаем часовые свечи для достаточной гранулярности при управляемой длине эпизодов.
Конвейер данных
- Получение: Извлечение 1000 часовых свечей для каждого актива параллельно
- Выравнивание: Обеспечение совпадения временных меток по всем активам
- Вычисление доходностей: Расчёт логарифмических доходностей по ценам закрытия
- Скользящая статистика: Вычисление скользящей волатильности и параметров z-нормализации
- Построение эпизодов: Разделение выровненных данных на обучающие и оценочные эпизоды
Обучение агента DQN
Цикл обучения следует стандартной процедуре DQN с описанными выше улучшениями:
for episode in 1..num_episodes: state = env.reset() for step in 1..max_steps: action = agent.act(state, epsilon) // epsilon-жадная стратегия next_state, reward, done = env.step(action) agent.store(state, action, reward, next_state, done) if agent.buffer_size() >= min_replay: agent.train_step(batch_size) // выборка из PER agent.soft_update_target() // усреднение Поляка state = next_state if done: break epsilon = max(epsilon_min, epsilon * epsilon_decay)Гиперпараметры
| Параметр | Значение | Обоснование |
|---|---|---|
| Скорость обучения | 0.001 | Стандарт для DQN с Adam |
| Коэффициент дисконтирования (gamma) | 0.99 | Долгосрочная оптимизация портфеля |
| Epsilon начальный | 1.0 | Полное исследование на старте |
| Epsilon конечный | 0.01 | Поддержание лёгкого исследования |
| Затухание epsilon | 0.995 | Постепенное снижение за ~1000 эпизодов |
| Размер пакета | 64 | Баланс между стабильностью и скоростью |
| Размер буфера воспроизведения | 100 000 | Хранение разнообразных рыночных условий |
| Обновление целевой сети (tau) | 0.005 | Медленно движущаяся цель для стабильности |
| Скрытые слои | [128, 64] | Достаточная ёмкость для задачи с 3 активами |
| Шаг веса (delta) | 0.1 | 10% приращения для ребалансировки |
Сравнение с равновесным эталоном
Портфель с равными весами (1/N) служит удивительно сильным эталоном. Исследование DeMiguel et al. (2009) показало, что 1/N превосходит многие методы оптимизации на данных вне выборки благодаря ошибкам оценки в матрицах доходности и ковариации. Наш агент DQN должен продемонстрировать явные преимущества для оправдания своей сложности:
- Адаптация к режимам: Агент DQN может уменьшать экспозицию к активам, входящим в нисходящие тренды, тогда как равновесный портфель сохраняет фиксированные распределения при всех рыночных условиях.
- Таргетирование волатильности: Включая признаки волатильности в состояние, агент обучается уменьшать распределение в активы, испытывающие всплески волатильности.
- Захват импульса: Агент может научиться увеличивать веса активов с положительной недавней доходностью, захватывая межактивный моментум.
Ключевые выводы
-
DQN естественно распространяется на управление портфелем, рассматривая распределение активов как задачу последовательного принятия решений. Состояние захватывает рыночные признаки и текущие позиции; действия — дискретные корректировки весов; вознаграждения — доходности с поправкой на риск.
-
Double DQN необходим для финансовых приложений, поскольку смещение переоценки стандартного DQN приводит к чрезмерно концентрированным портфелям. Механизм разделённого выбора-оценки даёт более консервативные и стабильные распределения.
-
Архитектура dueling ускоряет обучение, разделяя «хорошо ли это рыночное состояние?» (поток ценности) от «какое действие ребалансировки лучше здесь?» (поток преимущества). Это разложение особенно естественно для управления портфелем.
-
Приоритизированное воспроизведение опыта повышает эффективность выборки для редких событий. Финансовые рынки характеризуются толстохвостыми распределениями, где экстремальные события оказывают непропорциональное влияние. PER обеспечивает обучение агента на этих критических переходах.
-
Дискретные пространства действий — практический компромисс. Хотя непрерывные пространства действий (через DDPG или SAC) теоретически привлекательны, дискретные действия с шагами весов 5-10% достаточны для управления портфелем.
-
Транзакционные издержки фундаментально формируют изученные политики. Без штрафов за издержки агент учится агрессивно торговать, создавая стратегии, прибыльные в симуляции, но неработающие на практике.
-
Равновесный эталон трудно стабильно превзойти. Агенты DQN могут превосходить в трендовых рынках и при сменах режимов, но простота портфеля 1/N делает его конкурентоспособным на риск-скорректированной основе.
-
Rust обеспечивает производительность производственного уровня для вычислительно интенсивного цикла обучения. Крейт ndarray обеспечивает эффективные матричные операции, а система типов Rust обнаруживает несоответствия размерностей во время компиляции.