Перейти к содержимому

Глава 338: Энергетические модели для трейдинга

Обзор

Энергетические модели (Energy-Based Models, EBM) — это класс вероятностных моделей, которые сопоставляют скалярное значение энергии каждой конфигурации входных переменных. В отличие от традиционных дискриминативных моделей, которые напрямую вычисляют вероятности, EBM обучают функцию энергии, где низкая энергия соответствует областям с высокой вероятностью. Эта гибкость делает EBM особенно мощными для финансовых приложений, где типичны сложные мультимодальные распределения.

В трейдинге EBM превосходят в:

  • Оценка плотности: Моделирование сложных распределений доходности
  • Обнаружение аномалий: Высокая энергия = необычные состояния рынка
  • Генеративное моделирование: Генерация реалистичных рыночных сценариев
  • Гибкая классификация: Совместное моделирование признаков и меток

Ключевые концепции

Функция энергии

Ядро EBM — функция энергии E(x):

  • Низкая энергия → Высокая вероятность (вероятно/нормально)
  • Высокая энергия → Низкая вероятность (маловероятно/аномально)

Вероятность определяется через распределение Больцмана:

p(x) = exp(-E(x)) / Z

где Z — статистическая сумма (нормирующая константа).

Почему EBM для трейдинга?

  1. Нет предположений о распределении: В отличие от гауссовских моделей, EBM могут захватывать тяжёлые хвосты, асимметрию и мультимодальность
  2. Гибкое скоринг: Энергия предоставляет естественную оценку аномальности
  3. Совместное моделирование: Можно моделировать p(x,y) для признаков и целевых переменных
  4. Калибровка: Лучшая квантификация неопределённости по сравнению со стандартными классификаторами

Торговая стратегия

Основная стратегия: Определение режима и управление рисками на основе энергии

Генерация сигналов

  1. Обнаружение аномалий через энергию:

    • Вычислить энергию E(x) для текущего состояния рынка
    • Высокая энергия = необычные рыночные условия → уменьшить экспозицию
    • Низкая энергия = типичные условия → обычная торговля
  2. Классификация режимов:

    • Использовать EBM как совместный классификатор p(режим|признаки)
    • Режимы: Бычий, Медвежий, Высокая волатильность, Возврат к среднему
  3. Контртрендовые сигналы:

    • После разрешения всплеска энергии входить в контртрендовые позиции
    • Нормализация энергии = рынок возвращается к типичному состоянию

Управление рисками

Размер позиции = Базовый размер × (1 - нормализованная_энергия)
  • Выше энергия → меньше позиции
  • Обеспечивает автоматическое масштабирование рисков

Техническая спецификация

Ноутбуки для создания

#НоутбукОписание
101_ebm_fundamentals.ipynbФункции энергии и распределение Больцмана
202_contrastive_divergence.ipynbАлгоритм обучения CD
303_score_matching.ipynbАльтернативное обучение через score matching
404_noise_contrastive_estimation.ipynbNCE для обучения EBM
505_ebm_classifier.ipynbEBM как классификатор (подход JEM)
606_ebm_density_estimation.ipynbОценка плотности для доходностей
707_rbm_trading.ipynbОграниченные машины Больцмана
808_deep_ebm.ipynbГлубокие энергетические модели
909_ebm_anomaly_detection.ipynbИспользование энергии для скоринга аномалий
1010_ebm_regime_detection.ipynbКлассификация рыночных режимов
1111_trading_signals.ipynbПреобразование энергии в сигналы
1212_backtesting.ipynbПолный бэктест стратегии

Типы архитектур EBM

Типы энергетических моделей:
├── Ограниченные машины Больцмана (RBM)
│ ├── Архитектура видимый-скрытый слой
│ ├── Обучение контрастивной дивергенцией
│ └── Можно складывать в глубокие сети доверия
├── Глубокие энергетические модели
│ ├── Нейросетевая функция энергии
│ ├── Score matching / NCE обучение
│ └── Более выразительны чем RBM
├── Совместные энергетические модели (JEM)
│ ├── Классификатор как EBM
│ ├── Совместное моделирование p(x,y)
│ └── Улучшенная калибровка
└── EBM без MCMC
├── Denoising score matching
├── Sliced score matching
└── Более эффективное обучение

Реализация функции энергии

import torch
import torch.nn as nn
class EnergyNet(nn.Module):
"""
Нейронная сеть, вычисляющая энергию E(x) для входа x
Низкая энергия = высокая вероятность (типично)
Высокая энергия = низкая вероятность (аномально)
"""
def __init__(self, input_dim, hidden_dims=[128, 64, 32]):
super().__init__()
layers = []
prev_dim = input_dim
for hidden_dim in hidden_dims:
layers.extend([
nn.Linear(prev_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.SiLU(), # Гладкая активация
])
prev_dim = hidden_dim
# Финальный слой выводит скалярную энергию
layers.append(nn.Linear(prev_dim, 1))
self.network = nn.Sequential(*layers)
def forward(self, x):
"""Вычислить энергию для входа x"""
return self.network(x).squeeze(-1)
def energy(self, x):
"""Алиас для forward"""
return self.forward(x)
def log_prob(self, x, log_z=0.0):
"""
Приближённая логарифмическая вероятность (с точностью до нормирующей константы)
log p(x) ≈ -E(x) - log(Z)
"""
return -self.energy(x) - log_z

Обучение контрастивной дивергенцией

class ContrastiveDivergenceLoss:
"""
Обучение EBM с использованием контрастивной дивергенции
Идея: Опускаем энергию реальных данных,
поднимаем энергию модельных семплов (негативных семплов)
"""
def __init__(self, model, n_steps=10, step_size=0.01, noise_scale=0.01):
self.model = model
self.n_steps = n_steps
self.step_size = step_size
self.noise_scale = noise_scale
def sample_negative(self, x_init):
"""
Генерация негативных семплов с использованием динамики Ланжевена
x_{t+1} = x_t - λ∇E(x_t) + ε, где ε ~ N(0, σ²)
"""
x = x_init.clone().requires_grad_(True)
for _ in range(self.n_steps):
energy = self.model.energy(x)
grad = torch.autograd.grad(energy.sum(), x)[0]
# Обновление Ланжевена
noise = torch.randn_like(x) * self.noise_scale
x = x - self.step_size * grad + noise
x = x.detach().requires_grad_(True)
return x.detach()
def __call__(self, x_real):
"""
Вычисление CD-лосса
L = E[E(x_real)] - E[E(x_negative)]
Мы хотим минимизировать энергию реальных данных
и максимизировать энергию негативных семплов
"""
# Энергия реальных данных
energy_real = self.model.energy(x_real)
# Генерация негативных семплов
x_init = torch.randn_like(x_real)
x_negative = self.sample_negative(x_init)
# Энергия негативных семплов
energy_negative = self.model.energy(x_negative)
# CD лосс: опускаем реальные, поднимаем негативные
loss = energy_real.mean() - energy_negative.mean()
# Добавляем регуляризацию для предотвращения коллапса энергии
reg = 0.01 * (energy_real**2 + energy_negative**2).mean()
return loss + reg

Совместная энергетическая модель (JEM) для классификации

class JointEnergyModel(nn.Module):
"""
Совместная энергетическая модель: Ваш классификатор — скрытая энергетическая модель
Ключевое наблюдение: Логиты классификатора определяют функцию энергии
E(x) = -LogSumExp(logits(x))
Это позволяет совместно моделировать p(x,y) и улучшает калибровку
"""
def __init__(self, input_dim, n_classes, hidden_dims=[128, 64]):
super().__init__()
layers = []
prev_dim = input_dim
for hidden_dim in hidden_dims:
layers.extend([
nn.Linear(prev_dim, hidden_dim),
nn.LayerNorm(hidden_dim),
nn.SiLU(),
])
prev_dim = hidden_dim
layers.append(nn.Linear(prev_dim, n_classes))
self.network = nn.Sequential(*layers)
def logits(self, x):
"""Получить логиты классов"""
return self.network(x)
def energy(self, x):
"""
Энергия = -LogSumExp(logits)
Низкая энергия = классификатор уверен в каком-то классе
Высокая энергия = классификатор не уверен (вне распределения)
"""
logits = self.logits(x)
return -torch.logsumexp(logits, dim=-1)
def classify(self, x):
"""Стандартная классификация"""
logits = self.logits(x)
return logits.argmax(dim=-1)
def anomaly_score(self, x):
"""
Использование энергии как оценки аномальности
Высокая энергия = аномалия (вне распределения)
"""
return self.energy(x)

Торговые сигналы на основе энергии

class EBMTradingStrategy:
"""
Торговая стратегия на основе энергетической модели
"""
def __init__(self, model, energy_threshold=2.0, lookback=20):
self.model = model
self.energy_threshold = energy_threshold
self.lookback = lookback
self.energy_history = []
def compute_signal(self, features):
"""
Генерация торговых сигналов на основе энергии
"""
with torch.no_grad():
energy = self.model.energy(features).item()
self.energy_history.append(energy)
if len(self.energy_history) > self.lookback:
self.energy_history.pop(0)
# Нормализация энергии относительно недавней истории
if len(self.energy_history) >= 5:
mean_energy = np.mean(self.energy_history)
std_energy = np.std(self.energy_history) + 1e-8
normalized_energy = (energy - mean_energy) / std_energy
else:
normalized_energy = 0.0
signal = {
'energy': energy,
'normalized_energy': normalized_energy,
'is_anomaly': normalized_energy > self.energy_threshold,
'position_scale': max(0.0, 1.0 - normalized_energy / self.energy_threshold),
}
# Определение режима
if normalized_energy < -1.0:
signal['regime'] = 'спокойный'
elif normalized_energy < 1.0:
signal['regime'] = 'нормальный'
elif normalized_energy < 2.0:
signal['regime'] = 'повышенный'
else:
signal['regime'] = 'кризис'
return signal

Ограниченная машина Больцмана (RBM)

class RBM(nn.Module):
"""
Ограниченная машина Больцмана
Двухслойная сеть с видимыми и скрытыми юнитами
Энергия: E(v,h) = -v·W·h - a·v - b·h
"""
def __init__(self, n_visible, n_hidden):
super().__init__()
# Веса и смещения
self.W = nn.Parameter(torch.randn(n_visible, n_hidden) * 0.01)
self.a = nn.Parameter(torch.zeros(n_visible)) # смещение видимых
self.b = nn.Parameter(torch.zeros(n_hidden)) # смещение скрытых
def energy(self, v, h):
"""Вычислить энергию E(v, h)"""
return -torch.mm(v, self.W).sum() - torch.mv(v, self.a).sum() - torch.mv(h, self.b).sum()
def free_energy(self, v):
"""
Свободная энергия: F(v) = -log Σ_h exp(-E(v,h))
Используется для обучения, так как маргинализируем по скрытым юнитам
"""
wx_b = torch.mm(v, self.W) + self.b
hidden_term = torch.log(1 + torch.exp(wx_b)).sum(dim=1)
visible_term = torch.mv(v, self.a)
return -visible_term - hidden_term
def sample_hidden(self, v):
"""Семплирование скрытых юнитов при заданных видимых"""
prob_h = torch.sigmoid(torch.mm(v, self.W) + self.b)
return prob_h, torch.bernoulli(prob_h)
def sample_visible(self, h):
"""Семплирование видимых юнитов при заданных скрытых"""
prob_v = torch.sigmoid(torch.mm(h, self.W.t()) + self.a)
return prob_v, torch.bernoulli(prob_v)

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

Входные данные рынка
┌──────┴──────┐
▼ ▼
┌─────────────┐ ┌─────────────┐
│ OHLCV данные│ │ Стакан │
│ (Bybit API) │ │ (опц.) │
└──────┬──────┘ └──────┬──────┘
│ │
└───────┬───────┘
┌─────────────────┐
│ Извлечение │
│ признаков │
├─────────────────┤
│ - Доходности │
│ - Волатильность │
│ - Объём │
│ - Технические │
└────────┬────────┘
┌─────────────────────────┐
│ Энергетическая модель │
├─────────────────────────┤
│ │
│ ┌─────────────────┐ │
│ │ Energy Net │ │
│ │ E(x) → ℝ │ │
│ └────────┬────────┘ │
│ │ │
│ p(x) = exp(-E(x))/Z │
│ │
└────────────┬────────────┘
┌─────────────┼─────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Оценка │ │ Определение │ │ Обнаружение │
│ энергии │ │ режима │ │ аномалий │
│ │ │ │ │ │
│ Низкая = │ │ - Спокойный │ │ Высокая E →│
│ безопасно │ │ - Обычный │ │ аномалия │
│ Высокая = │ │ - Волатильн │ │ │
│ риск │ │ │ │ │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
└───────────────┼───────────────┘
┌─────────────────┐
│ Генератор │
│ сигналов │
├─────────────────┤
│ - Размер позиции│
│ - Вход/Выход │
│ - Скейлинг риска│
└────────┬────────┘
┌─────────────────┐
│ Исполнение │
│ ордеров │
│ (Bybit API) │
└─────────────────┘

Сравнение подходов к обучению

МетодПлюсыМинусыЛучше всего для
Контрастивная дивергенцияПростой, широко используетсяСмещённые градиентыRBM, быстрое прототипирование
Score MatchingНе нужен MCMCЗатратен по памятиВысокоразмерные данные
NCEСтабильное обучениеТребует дизайна шумаМодели среднего масштаба
Langevin MCMCАсимптотически корректенМедленный, коллапс модИсследования, точность

Требования к данным

Исторические OHLCV данные:
├── Минимум: 6 месяцев почасовых данных
├── Рекомендуется: 2+ года для надёжного обучения
├── Частота: От 1-минутной до дневной
└── Источник: Bybit API (криптовалюты)
Обязательные поля:
├── timestamp
├── open, high, low, close
├── volume
└── Опционально: количество сделок, ставка фандинга
Разбиение данных для обучения:
├── Train: 70% (старейшие данные)
├── Validation: 15%
└── Test: 15% (самые недавние)

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

Метрики модели

  • Log-likelihood: Вероятность тестовых данных по модели
  • Распределение энергии: Должно быть ниже для реальных данных
  • Качество семплов: Для оценки генеративных возможностей

Торговые метрики

  • Sharpe Ratio: Доходность с учётом риска
  • Sortino Ratio: Доходность с учётом только отрицательного риска
  • Maximum Drawdown: Максимальная просадка от пика до дна
  • Calmar Ratio: Доходность / Макс. просадка
  • Win Rate: Процент прибыльных сделок
  • Profit Factor: Валовая прибыль / Валовой убыток

Метрики обнаружения аномалий

  • AUROC: Площадь под ROC-кривой
  • Precision@K: Точность для топ-K значений энергии
  • Латентность обнаружения: Время до обнаружения смены режима

Зависимости

# Основные
pandas>=1.5.0
numpy>=1.23.0
scipy>=1.10.0
# Глубокое обучение
torch>=2.0.0
pytorch-lightning>=2.0.0
# Машинное обучение
scikit-learn>=1.2.0
# Визуализация
matplotlib>=3.6.0
seaborn>=0.12.0
plotly>=5.10.0
# Рыночные данные
ccxt>=4.0.0
websocket-client>=1.4.0
# Прогресс и логирование
tqdm>=4.64.0
tensorboard>=2.12.0

Ожидаемые результаты

  1. Оценка плотности на основе энергии для распределений доходности
  2. Определение режима с использованием пороговых значений энергии
  3. Скоринг аномалий для необычных состояний рынка
  4. Размер позиции с учётом риска на основе уровней энергии
  5. Результаты бэктеста: Улучшение на 20-40% доходности с учётом риска

Научные публикации

  1. Your Classifier is Secretly an Energy Based Model and You Should Treat it Like One (Grathwohl et al., 2019)

    • URL: https://arxiv.org/abs/1912.03263
    • Ключевое наблюдение: Классификаторы можно интерпретировать как EBM
  2. A Tutorial on Energy-Based Learning (LeCun et al., 2006)

  3. How to Train Your Energy-Based Models (Song & Kingma, 2021)

Реализация на Rust

Эта глава включает полную реализацию на Rust для высокопроизводительной торговли на основе EBM с данными криптовалют от Bybit. См. директорию rust_ebm_crypto/.

Возможности:

  • Получение данных в реальном времени от Bybit
  • Обнаружение аномалий на основе энергии
  • Множество подходов к обучению (Score Matching, подход NCE)
  • Модульный и расширяемый дизайн
  • Высокопроизводительный инференс

Уровень сложности

⭐⭐⭐⭐⭐ (Эксперт)

Требуется понимание: Теория вероятностей, Статистическая механика, Глубокое обучение, Методы MCMC, Финансовые рынки