← ДокументацияDOCS / Optimization / Баланс риска и прибыли

Баланс прибыли и риска в обучении трейдингового агента

Улучшение функции награды с учётом просадок и торговых издержек

Введение: необходимость учёта просадок и издержек

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

Ключевые понятия:

  • Просадка (drawdown) — снижение капитала от предыдущего максимума до минимальной точки
  • Максимальная просадка — наибольшее процентное падение от пика до последующего дна
  • Торговые издержки — комиссии и проскальзывание, влияющие на реальную прибыль

Реальные рынки сопряжены с комиссиями и проскальзыванием. Пренебрежение этими факторами может привести к стратегиям с чрезмерной частотой торговли или неоптимальными объёмами позиций. Учёт этих факторов в функции награды обеспечивает более стабильную и реалистичную стратегию.

Бонус за снижение просадки и штраф за просадку

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

Логика применения

Поощрение за восстановление

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

Штраф за глубокую просадку

При превышении порога просадки (например, 10%) применяется штраф

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

python
# Базовая награда за шаг
reward = profit_change

# Шаг 1: штраф за просадку сверх порога
if current_drawdown > DD_THRESHOLD:
    excess = current_drawdown - DD_THRESHOLD
    reward -= PENALTY_RATE * excess * volume

# Шаг 2: бонус за сокращение просадки
if drawdown_reduced:
    reward *= (1 + K_BONUS * dd_gain_fraction)

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

Реализация логики «палка → пряник»

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

Схема расчёта награды

python
# 1. Базовая награда
total_base_reward = raw_pnl - commission - slippage

# 2. Обновление баланса и расчёт просадки
old_peak = self.peak_balance
prelim_balance = prev_balance + total_base_reward
new_peak = max(old_peak, prelim_balance)
drawdown = (new_peak - prelim_balance) / (new_peak + 1e-8) * 100

# 3. Штраф за превышение порога просадки
excess_dd_pct = max(0.0, drawdown - self.drawdown_threshold) / 100
drawdown_penalty = excess_dd_pct * operating_volume
reward_after_penalty = total_base_reward - drawdown_penalty

После применения штрафа за просадку рассчитывается бонус за её сокращение:

python
# 4. Бонус/штраф за изменение просадки
dd_before = self.last_drawdown
dd_after = drawdown
dd_gain = max(0.0, dd_before - dd_after)  # просадка ↓
dd_loss = max(0.0, dd_after - dd_before)  # просадка ↑

thr = self.drawdown_threshold + 1e-8
k_plus = self.k_bonus      # напр. 0.5
k_minus = getattr(self, "k_penalty", 0.2)  # можно добавить в config

scale_up = 1 + k_plus * (dd_gain / thr)    # 1 ... 1+k_plus
scale_down = 1 - k_minus * (dd_loss / thr) # 1 ... (1-k_minus)

# Гарантируем неотрицательный множитель
net_scale = max(scale_up * scale_down, 0.0)
reward_after_bonus = reward_after_penalty

if reward_after_bonus > 0:  # усиливаем только прибыль
    reward_after_bonus *= net_scale
else:  # а убыток можно ужесточить
    reward_after_bonus *= (1 + k_minus * (dd_loss / thr))

Дополнительно может применяться бонус за уменьшение объёма торгов:

python
# 5. Бонус за уменьшение объёма (опционально)
growth = max(prelim_balance - old_peak, 0.0)
volume_bonus = (growth if self.use_volume_decrease_bonus else 0.0) \
    * (1 / (1 + total_trade_volume / operating_volume))

total_reward = reward_after_bonus + volume_bonus
norm_total_reward = total_reward / operating_volume

Психологические преимущества:

  • Сначала показывается «кнут» — убирается фиксированная сумма за превышение порога просадки
  • Затем «пряник» — премирование за уменьшение просадки по сравнению с предыдущим шагом
  • Агент видит, что любое ухудшение просадки сразу обнуляет или съедает будущий бонус

После расчёта награды обновляются внутренние состояния агента:

python
# Обновление состояний
self.current_balance = prelim_balance + volume_bonus  # уже учли penalty/bonus
self.peak_balance = new_peak
self.last_drawdown = drawdown
self.max_drawdown = max(self.max_drawdown, drawdown)

Детали симметричного штрафа за рост просадки

Симметричный штраф за увеличение просадки реализуется через параметр k_penalty, который можно добавить в конфигурацию с значением по умолчанию 0.2-0.3.

Примеры работы штрафа:

  • Если просадка выросла на 50% от порога при k_penalty = 0.2, множитель ≈ 0.9 (награда ↓ на 10%)
  • Если просадка превысила порог полностью (dd_loss / thr ≥ 1), награда на этом шаге обнуляется
  • Сверхпороговые значения дополнительно штрафуются через drawdown_penalty

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

Симметричный штраф за увеличение просадки

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

Проблема традиционного подхода:

Отсутствие штрафа за увеличение просадки может поощрять рискованное поведение в надежде на последующее восстановление и получение бонуса.

Симметричный подход предполагает штраф за рост просадки, аналогичный бонусу за её сокращение:

python
# Штраф за увеличение просадки
if drawdown_increased:
    reward *= (1 - K_PENALTY * dd_loss_fraction)
    # где dd_loss_fraction = на сколько выросла просадка

Важно: Баланс между поощрением и штрафом требует тщательной настройки. Слишком сильный штраф может сделать агента излишне консервативным.

Учёт оборота и проскальзывания: нелинейные торговые издержки

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

Квадратичный закон влияния

Исследования показывают, что влияние сделки на цену масштабируется по закону квадратного корня:

формула
impact ≈ C · σ · √(Q/V)

где:
Q — объём сделки
V — типичный объём (дневной оборот)
σ — волатильность
C — константа

Реализация нелинейных издержек в функции награды:

python
linear_cost = COMM_RATE * volume
impact_cost = IMPACT_COEFF * sqrt(volume_ratio)
total_cost = linear_cost + impact_cost
reward = profit_change - total_cost

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

Расширенные критерии отбора лучшей модели

При обучении агента периодически сохраняется «лучшая» модель на основе определённых критериев. Традиционно таким критерием служила суммарная прибыль (PNL), но комплексная оценка требует учёта риска и эффективности.

Ключевые метрики оценки

Коэффициент Шарпа

Измеряет доходность на единицу принятого риска (волатильности доходности)

Оборачиваемость капитала

Количество сделок и связанные с ними издержки

Максимальная просадка

Наибольшее падение капитала от пика до минимума

Коэффициент Кальмара

Отношение доходности к максимальной просадке

Композиционный критерий отбора модели:

python
def is_better_model(new, best):
    # Проверка основной доходности
    if new.profit > best.profit * (1 + 0.01):
        return True
    
    # При равной прибыли сравниваем риски
    if abs(new.profit - best.profit) < best.profit * 0.01:
        if new.max_drawdown < best.max_drawdown * 0.9:
            return True  # просадка существенно ниже
        if new.turnover < best.turnover * 0.7:
            return True  # оборот значительно ниже
        if new.sharpe > best.sharpe:
            return True  # лучший коэффициент Шарпа
    
    return False

Дополнительные метрики оценки

Помимо коэффициента Шарпа существуют другие метрики для оценки качества стратегий:

МетрикаФормулаОсобенности
Коэффициент Сортино(R - Rf) / σdУчитывает только нижнюю полуволатильность, сильнее штрафует за просадки
Коэффициент КальмараГодовая доходность / Max DDПрямое отношение доходности к максимальной просадке
Коэффициент Стерлинга(R - Rf) / (Max DD - 10%)Учитывает минимальную просадку в 10% как базовый риск

Заключение: ценность комплексного подхода

Внедрение рассмотренных методов обеспечивает следующие преимущества:

Ограничение рисков просадки

Просадки становятся «дорогими» в функции награды, что приближает поведение агента к поведению опытного трейдера, ценящего сохранение капитала

Учёт реальных издержек

Нелинейный штраф за оборот имитирует рыночный импакт, делая стратегии более реалистичными

Повышение устойчивости

Стратегии становятся более устойчивыми к рыночным шокам и изменениям условий торговли

Комплексная оценка качества

Расширенные критерии отбора обеспечивают выбор стратегий с оптимальным соотношением риск-доходность

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

QUANT LAB — Документация