Разработка RL-агента для торговли на базе TD3

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
Разработка RL-агента для торговли на базе TD3
Сложный
~2-4 недели
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    901
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1119
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    853

Торговый агент на TD3 (Twin Delayed Deep Deterministic Policy Gradient)

TD3 — улучшенный DDPG от Scott Fujimoto (2018). Исправляет три проблемы DDPG: overestimation, высокую variance, нестабильность. Off-policy, continuous actions, детерминированная policy. Для трейдинга с непрерывным position sizing — конкурент SAC.

TD3 vs DDPG vs SAC

DDPG страдает от Q-overestimation: Q-функция завышает ожидаемые returns → policy оптимизируется под нереалистичные цели → плохое реальное поведение.

TD3 исправляет тремя трюками:

1. Twin Q-networks (double Q): Два независимых критика Q₁, Q₂. Target использует min(Q₁, Q₂):

y = r + γ · min(Q₁_target(s', π(s')), Q₂_target(s', π(s')))

Консервативная оценка → меньше overestimation.

2. Delayed policy updates: Policy обновляется каждые d шагов (d=2 по умолчанию), критики — каждый шаг. Менее стохастичные Q-оценки перед обновлением actor.

3. Target policy smoothing: Шум добавляется к target actions при вычислении Q-targets:

noise = (torch.randn_like(action) * policy_noise).clamp(-noise_clip, noise_clip)
next_action = (target_actor(next_state) + noise).clamp(-1, 1)

Регуляризация: критик не перефитирует к узким пикам Q-поверхности.

Архитектура для трейдинга

class TD3Actor(nn.Module):
    def __init__(self, state_dim, action_dim, max_action):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(state_dim, 256), nn.ReLU(),
            nn.Linear(256, 256), nn.ReLU(),
            nn.Linear(256, action_dim), nn.Tanh()
        )
        self.max_action = max_action

    def forward(self, state):
        return self.net(state) * self.max_action

class TD3Critic(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        # Q1
        self.q1 = nn.Sequential(
            nn.Linear(state_dim + action_dim, 256), nn.ReLU(),
            nn.Linear(256, 256), nn.ReLU(),
            nn.Linear(256, 1)
        )
        # Q2
        self.q2 = nn.Sequential(
            nn.Linear(state_dim + action_dim, 256), nn.ReLU(),
            nn.Linear(256, 256), nn.ReLU(),
            nn.Linear(256, 1)
        )

    def forward(self, state, action):
        sa = torch.cat([state, action], dim=1)
        return self.q1(sa), self.q2(sa)

    def q1_forward(self, state, action):
        sa = torch.cat([state, action], dim=1)
        return self.q1(sa)

Трейдинг-специфичный reward и action space

Continuous position sizing: Action [-1, 1]: -1 = 100% short, 0 = flat, +1 = 100% long. Portfolio с N активами: action ∈ [-1,1]^N, нормировать до Σ|wᵢ| ≤ 1.

Reward с учётом risk:

# Sharpe-like reward
def reward_fn(returns_series):
    if len(returns_series) < 20:
        return returns_series[-1]
    mean_r = np.mean(returns_series[-20:])
    std_r = np.std(returns_series[-20:]) + 1e-8
    sharpe = mean_r / std_r
    return sharpe * returns_series[-1]  # масштабирование

Transaction cost penalization:

position_change = np.abs(new_position - old_position)
transaction_cost = position_change * 0.001  # 0.1%
reward -= transaction_cost

Это заставляет агента избегать гиперактивной торговли.

Exploration: Ornstein-Uhlenbeck vs Gaussian

Оригинальный DDPG использует OU noise для exploration (временно коррелированный шум). TD3 переходит на простой Gaussian noise:

# Gaussian exploration (рекомендуется для TD3)
action = actor(state) + np.random.normal(0, exploration_noise, action_dim)
action = np.clip(action, -max_action, max_action)

Для трейдинга: exploration_noise = 0.1–0.3. Decay по мере обучения.

Обучение

from stable_baselines3 import TD3
from stable_baselines3.common.noise import NormalActionNoise

action_noise = NormalActionNoise(
    mean=np.zeros(n_actions),
    sigma=0.1 * np.ones(n_actions)
)

model = TD3(
    "MlpPolicy",
    env,
    action_noise=action_noise,
    learning_rate=3e-4,
    buffer_size=1_000_000,
    learning_starts=10_000,
    batch_size=256,
    tau=0.005,
    gamma=0.99,
    train_freq=(1, "episode"),
    gradient_steps=-1,          # gradient_steps = episodes collected
    policy_delay=2,             # delayed policy update
    target_policy_noise=0.2,
    target_noise_clip=0.5,
    verbose=1
)
model.learn(total_timesteps=500_000)

Когда TD3 выигрывает у SAC

TD3 — детерминированная policy (с exploration noise). SAC — stochastic policy с entropy bonus.

TD3 предпочтителен когда:

  • Нужна воспроизводимость live торговли (детерминированные сигналы)
  • Рынок с чёткими трендами (низкая энтропия оптимальна)
  • Хочется явно контролировать exploration через noise schedule

SAC предпочтителен когда:

  • Высокая неопределённость рынка
  • Нужна naturalistic diversification позиций

Сроки: 5–9 недель

TD3 baseline с continuous position sizing — 3 недели. Multi-asset, OU/adaptive noise, risk-adjusted reward, интеграция с брокерским API — 7–9 недель.