Глава 338: Энергетические модели для трейдинга
Обзор
Энергетические модели (Energy-Based Models, EBM) — это класс вероятностных моделей, которые сопоставляют скалярное значение энергии каждой конфигурации входных переменных. В отличие от традиционных дискриминативных моделей, которые напрямую вычисляют вероятности, EBM обучают функцию энергии, где низкая энергия соответствует областям с высокой вероятностью. Эта гибкость делает EBM особенно мощными для финансовых приложений, где типичны сложные мультимодальные распределения.
В трейдинге EBM превосходят в:
- Оценка плотности: Моделирование сложных распределений доходности
- Обнаружение аномалий: Высокая энергия = необычные состояния рынка
- Генеративное моделирование: Генерация реалистичных рыночных сценариев
- Гибкая классификация: Совместное моделирование признаков и меток
Ключевые концепции
Функция энергии
Ядро EBM — функция энергии E(x):
- Низкая энергия → Высокая вероятность (вероятно/нормально)
- Высокая энергия → Низкая вероятность (маловероятно/аномально)
Вероятность определяется через распределение Больцмана:
p(x) = exp(-E(x)) / Zгде Z — статистическая сумма (нормирующая константа).
Почему EBM для трейдинга?
- Нет предположений о распределении: В отличие от гауссовских моделей, EBM могут захватывать тяжёлые хвосты, асимметрию и мультимодальность
- Гибкое скоринг: Энергия предоставляет естественную оценку аномальности
- Совместное моделирование: Можно моделировать p(x,y) для признаков и целевых переменных
- Калибровка: Лучшая квантификация неопределённости по сравнению со стандартными классификаторами
Торговая стратегия
Основная стратегия: Определение режима и управление рисками на основе энергии
Генерация сигналов
-
Обнаружение аномалий через энергию:
- Вычислить энергию E(x) для текущего состояния рынка
- Высокая энергия = необычные рыночные условия → уменьшить экспозицию
- Низкая энергия = типичные условия → обычная торговля
-
Классификация режимов:
- Использовать EBM как совместный классификатор p(режим|признаки)
- Режимы: Бычий, Медвежий, Высокая волатильность, Возврат к среднему
-
Контртрендовые сигналы:
- После разрешения всплеска энергии входить в контртрендовые позиции
- Нормализация энергии = рынок возвращается к типичному состоянию
Управление рисками
Размер позиции = Базовый размер × (1 - нормализованная_энергия)- Выше энергия → меньше позиции
- Обеспечивает автоматическое масштабирование рисков
Техническая спецификация
Ноутбуки для создания
| # | Ноутбук | Описание |
|---|---|---|
| 1 | 01_ebm_fundamentals.ipynb | Функции энергии и распределение Больцмана |
| 2 | 02_contrastive_divergence.ipynb | Алгоритм обучения CD |
| 3 | 03_score_matching.ipynb | Альтернативное обучение через score matching |
| 4 | 04_noise_contrastive_estimation.ipynb | NCE для обучения EBM |
| 5 | 05_ebm_classifier.ipynb | EBM как классификатор (подход JEM) |
| 6 | 06_ebm_density_estimation.ipynb | Оценка плотности для доходностей |
| 7 | 07_rbm_trading.ipynb | Ограниченные машины Больцмана |
| 8 | 08_deep_ebm.ipynb | Глубокие энергетические модели |
| 9 | 09_ebm_anomaly_detection.ipynb | Использование энергии для скоринга аномалий |
| 10 | 10_ebm_regime_detection.ipynb | Классификация рыночных режимов |
| 11 | 11_trading_signals.ipynb | Преобразование энергии в сигналы |
| 12 | 12_backtesting.ipynb | Полный бэктест стратегии |
Типы архитектур EBM
Типы энергетических моделей:├── Ограниченные машины Больцмана (RBM)│ ├── Архитектура видимый-скрытый слой│ ├── Обучение контрастивной дивергенцией│ └── Можно складывать в глубокие сети доверия├── Глубокие энергетические модели│ ├── Нейросетевая функция энергии│ ├── Score matching / NCE обучение│ └── Более выразительны чем RBM├── Совместные энергетические модели (JEM)│ ├── Классификатор как EBM│ ├── Совместное моделирование p(x,y)│ └── Улучшенная калибровка└── EBM без MCMC ├── Denoising score matching ├── Sliced score matching └── Более эффективное обучениеРеализация функции энергии
import torchimport 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.0numpy>=1.23.0scipy>=1.10.0
# Глубокое обучениеtorch>=2.0.0pytorch-lightning>=2.0.0
# Машинное обучениеscikit-learn>=1.2.0
# Визуализацияmatplotlib>=3.6.0seaborn>=0.12.0plotly>=5.10.0
# Рыночные данныеccxt>=4.0.0websocket-client>=1.4.0
# Прогресс и логированиеtqdm>=4.64.0tensorboard>=2.12.0Ожидаемые результаты
- Оценка плотности на основе энергии для распределений доходности
- Определение режима с использованием пороговых значений энергии
- Скоринг аномалий для необычных состояний рынка
- Размер позиции с учётом риска на основе уровней энергии
- Результаты бэктеста: Улучшение на 20-40% доходности с учётом риска
Научные публикации
-
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
-
A Tutorial on Energy-Based Learning (LeCun et al., 2006)
- URL: http://yann.lecun.com/exdb/publis/pdf/lecun-06.pdf
- Всестороннее введение в EBM
-
How to Train Your Energy-Based Models (Song & Kingma, 2021)
- URL: https://arxiv.org/abs/2101.03288
- Современные техники обучения EBM
Реализация на Rust
Эта глава включает полную реализацию на Rust для высокопроизводительной торговли на основе EBM с данными криптовалют от Bybit. См. директорию rust_ebm_crypto/.
Возможности:
- Получение данных в реальном времени от Bybit
- Обнаружение аномалий на основе энергии
- Множество подходов к обучению (Score Matching, подход NCE)
- Модульный и расширяемый дизайн
- Высокопроизводительный инференс
Уровень сложности
⭐⭐⭐⭐⭐ (Эксперт)
Требуется понимание: Теория вероятностей, Статистическая механика, Глубокое обучение, Методы MCMC, Финансовые рынки