Торговый агент на PPO (Proximal Policy Optimization)
PPO — наиболее распространённый алгоритм для торговых RL-агентов. On-policy, стабильный, хорошо работает с continuous action spaces, устойчив к гиперпараметрам. Разработан OpenAI (2017), де-факто стандарт для portfolio management задач.
Почему PPO для трейдинга
PPO ограничивает размер обновлений policy через clip ratio (ε). Это предотвращает деструктивные обновления, которые в финансовых средах ведут к "забыванию" рабочих стратегий после одного плохого батча.
L_CLIP = E[min(r_t(θ) * A_t, clip(r_t(θ), 1-ε, 1+ε) * A_t)]
r_t(θ) = π_new(a|s) / π_old(a|s) — probability ratio. При ε=0.2: обновление не превышает 20% изменения вероятности действия.
Архитектура Policy Network
Actor-Critic:
import torch
import torch.nn as nn
class TradingActorCritic(nn.Module):
def __init__(self, state_dim, action_dim):
super().__init__()
# Shared feature extractor
self.shared = nn.Sequential(
nn.Linear(state_dim, 256),
nn.Tanh(),
nn.Linear(256, 256),
nn.Tanh()
)
# Actor head: mean + log_std для Gaussian policy
self.actor_mean = nn.Linear(256, action_dim)
self.actor_log_std = nn.Parameter(torch.zeros(action_dim))
# Critic head: state value V(s)
self.critic = nn.Linear(256, 1)
def forward(self, state):
feat = self.shared(state)
mean = self.actor_mean(feat)
std = self.actor_log_std.exp()
value = self.critic(feat)
return mean, std, value
LSTM расширение: Для учёта temporal dependencies рынка — LSTM вместо MLP в shared слое. Скрытое состояние передаётся между шагами эпизода.
Transformer: Market Transformer: multi-head attention над историей цен (lookback window 60 дней). Attention heads учатся смотреть на разные временные паттерны.
Настройка гиперпараметров для трейдинга
| Параметр | Типичный RL | Трейдинг |
|---|---|---|
| clip_range ε | 0.2 | 0.1–0.15 (консервативнее) |
| learning_rate | 3e-4 | 1e-4 – 3e-4 |
| n_steps | 2048 | 252 (торговых дней) |
| batch_size | 64 | 32–64 |
| n_epochs | 10 | 4–6 |
| gamma (discount) | 0.99 | 0.95–0.99 |
| gae_lambda | 0.95 | 0.9–0.95 |
| ent_coef | 0.0 | 0.001–0.01 |
ent_coef важен: небольшая entropy regularization предотвращает схлопывание policy в один детерминированный паттерн (overfitting к конкретному паттерну рынка).
Кастомная торговая среда
import gymnasium as gym
import numpy as np
class PPOTradingEnv(gym.Env):
def __init__(self, df, initial_capital=100_000):
self.df = df
self.capital = initial_capital
n_features = 20 # OHLCV + indicators
self.observation_space = gym.spaces.Box(
low=-np.inf, high=np.inf,
shape=(n_features,), dtype=np.float32)
# непрерывные действия: [-1, 1] для каждого актива
self.action_space = gym.spaces.Box(
low=-1, high=1,
shape=(n_assets,), dtype=np.float32)
def step(self, action):
# перевод action [-1,1] в целевые веса портфеля
weights = self._softmax_allocation(action)
# ребалансировка с учётом transaction costs
pnl = self._rebalance(weights)
obs = self._get_obs()
reward = np.log(1 + pnl / self.portfolio_value)
done = self.current_step >= len(self.df) - 1
return obs, reward, done, False, {}
Обучение и валидация
from stable_baselines3 import PPO
from stable_baselines3.common.vec_env import SubprocVecEnv
# параллельные среды для ускорения сбора данных
def make_env(df): return lambda: PPOTradingEnv(df)
vec_env = SubprocVecEnv([make_env(train_df)] * 8)
model = PPO(
"MlpPolicy",
vec_env,
learning_rate=2e-4,
n_steps=252,
batch_size=64,
n_epochs=5,
clip_range=0.1,
ent_coef=0.005,
verbose=1,
tensorboard_log="./ppo_tb/"
)
model.learn(total_timesteps=2_000_000)
Walk-forward validation: Обучение 2015–2020 → тест 2021 → сдвиг: обучение 2016–2021 → тест 2022. Средняя производительность по всем окнам — реальная метрика.
Сроки: 6–12 недель
Базовый PPO агент на акциях/фьючерсах — 4–6 недель. LSTM/Transformer policy, multi-asset с корреляциями, интеграция с live брокером — 10–12 недель.







