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

Глава 326: Deep Ensembles для Трейдинга

Обзор

Deep Ensembles (Глубокие Ансамбли) - это простой, но мощный подход для оценки неопределенности в глубоком обучении. Обучая несколько нейронных сетей с различными случайными инициализациями, Deep Ensembles захватывают неопределенность модели (эпистемическую неопределенность) и обеспечивают робастные предсказания, критически важные для торговых решений с учетом риска.

Почему Deep Ensembles для Трейдинга?

Проблема Одиночных Моделей

Одиночная нейронная сеть дает точечные предсказания без какой-либо меры уверенности:

Одиночная модель: Цена → Нейросеть → Предсказание: +2.5%
(Но насколько модель уверена?)

В трейдинге это опасно, потому что:

  • Самоуверенные предсказания ведут к завышенным позициям
  • Нет оценки риска при смене рыночных режимов
  • Ошибки модели происходят тихо и катастрофично

Решение Deep Ensembles

Deep Ensembles обучают M независимых сетей и агрегируют их предсказания:

Deep Ensemble: Цена → [НС₁, НС₂, НС₃, ..., НСₘ] → Среднее: +2.5%, Стд: 0.8%
(Теперь мы знаем неопределенность!)

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

Основные Концепции

1. Разнообразие Ансамбля через Случайную Инициализацию

Нейронные сети невыпуклы. Разные случайные инициализации находят разные локальные минимумы:

Ландшафт функции потерь:
↓ Иниц. 1 ↓ Иниц. 2 ↓ Иниц. 3
\ | /
\ | /
↘ ↓ ↙
Минимум A Минимум B Минимум C
Каждый минимум дает разную (но валидную) модель!

Почему это работает:

  • Нейронные сети с разными инициализациями сходятся к разным решениям
  • Эти решения делают разные ошибки на разных входах
  • Усреднение уменьшает индивидуальные ошибки (снижение дисперсии)
  • Несогласие выявляет области, где модели неуверены

2. Декомпозиция Неопределенности

Deep Ensembles естественно разделяют неопределенность на два типа:

Общая неопределенность = Эпистемическая + Алеаторная
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ЭПИСТЕМИЧЕСКАЯ (Модельная) АЛЕАТОРНАЯ (Шум данных) │
│ ───────────────────────── ──────────────────────── │
│ • Снижается с данными • Неснижаемый шум │
│ • Высокая при несогласии • Врожденная случайность │
│ • Означает "Я не знаю" • Означает "Хаос на рынке" │
│ │
│ Оценка: Дисперсия средних Оценка: Средняя дисперсия │
│ │
└─────────────────────────────────────────────────────────────────┘

Математическая формулировка:

Для ансамбля из M моделей, предсказывающих гауссовы распределения:

  • Каждая модель m выдает: μₘ(x), σₘ²(x)
Общая дисперсия = (1/M) Σ σₘ²(x) + (1/M) Σ (μₘ(x) - μ̄(x))²
└─────────────┘ └────────────────────────┘
Алеаторная Эпистемическая
(средняя дисперсия) (дисперсия средних)

3. Правильные Функции Оценки и NLL Loss

Deep Ensembles используют Negative Log-Likelihood (NLL) loss для правильной оценки неопределенности:

# Для гауссова выхода
def nll_loss(mu, sigma, target):
"""
NLL = 0.5 * log(2π) + log(σ) + (y - μ)²/(2σ²)
"""
return 0.5 * np.log(2 * np.pi) + np.log(sigma) + 0.5 * ((target - mu) / sigma) ** 2

Почему NLL важен:

  • Правильная функция оценки: Стимулирует честные оценки неопределенности
  • Модель учит и среднее, И дисперсию
  • Самоуверенные предсказания штрафуются
  • Неуверенные предсказания тоже штрафуются

4. Несогласие Ансамбля

Несогласие ансамбля - ключевой сигнал для торговых решений:

Высокое несогласие Низкое несогласие
(Не торгуем!) (Торгуем уверенно!)
Модель 1: +5% Модель 1: +2.4%
Модель 2: -3% ← КОНФЛИКТ Модель 2: +2.6% ← СОГЛАСИЕ
Модель 3: +1% Модель 3: +2.5%
Модель 4: -2% Модель 4: +2.5%
Модель 5: +4% Модель 5: +2.4%
Среднее: +1%, Стд: 3.2% Среднее: +2.5%, Стд: 0.08%

5. Гиперпараметрические Ансамбли

Помимо случайной инициализации, можно создавать ансамбли по гиперпараметрам:

Разнообразие гиперпараметров:
├── Архитектура: [64-32, 128-64, 256-128-64]
├── Learning rate: [0.001, 0.0005, 0.0001]
├── Dropout: [0.1, 0.2, 0.3]
├── Активация: [ReLU, GELU, SiLU]
└── Batch size: [32, 64, 128]
Результат: Более разнообразный ансамбль = Лучшие оценки неопределенности

6. Параллелизация

Deep Ensembles тривиально параллелизуются:

┌─────────────────────────────────────────────────────────────┐
│ ПАРАЛЛЕЛЬНОЕ ОБУЧЕНИЕ │
├─────────────────────────────────────────────────────────────┤
│ │
│ GPU 0: Обучение модели 1 ────────────→ Веса модели 1 │
│ GPU 1: Обучение модели 2 ────────────→ Веса модели 2 │
│ GPU 2: Обучение модели 3 ────────────→ Веса модели 3 │
│ GPU 3: Обучение модели 4 ────────────→ Веса модели 4 │
│ GPU 4: Обучение модели 5 ────────────→ Веса модели 5 │
│ │
│ Все обучаются одновременно! Коммуникация не нужна. │
└─────────────────────────────────────────────────────────────┘

Параллелизация инференса:

Батч данных → Параллельный forward pass на всех моделях → Агрегация предсказаний
(Можно использовать model parallelism или разбиение батча)

Архитектура Модели

┌─────────────────────────────────────────────────────────────────┐
│ МОДЕЛЬ DEEP ENSEMBLE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ВХОД: Рыночные признаки [batch, features] │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ ЧЛЕНЫ АНСАМБЛЯ (M независимых сетей) │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Модель 1 │ │ Модель 2 │ │ Модель 3 │ ... │ Модель M │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ Linear │ │ Linear │ │ Linear │ │ Linear │ │ │
│ │ │ ReLU │ │ ReLU │ │ ReLU │ │ ReLU │ │ │
│ │ │ Dropout │ │ Dropout │ │ Dropout │ │ Dropout │ │ │
│ │ │ Linear │ │ Linear │ │ Linear │ │ Linear │ │ │
│ │ │ ReLU │ │ ReLU │ │ ReLU │ │ ReLU │ │ │
│ │ │ Linear │ │ Linear │ │ Linear │ │ Linear │ │ │
│ │ │ (μ, σ) │ │ (μ, σ) │ │ (μ, σ) │ │ (μ, σ) │ │ │
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │
│ │ │ │ │ │ │ │
│ └───────┼────────────┼────────────┼────────────────┼────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ СЛОЙ АГРЕГАЦИИ │ │
│ │ │ │
│ │ μ_ансамбля = (1/M) Σ μₘ │ │
│ │ σ²_эпистемич = (1/M) Σ (μₘ - μ_ансамбля)² │ │
│ │ σ²_алеаторная = (1/M) Σ σₘ² │ │
│ │ σ²_общая = σ²_эпистемич + σ²_алеаторная │ │
│ │ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ВЫХОД: (μ_ансамбля, σ_общая, σ_эпистемич, σ_алеаторная) │
│ │
└─────────────────────────────────────────────────────────────────┘

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

Генерация Сигналов с Учетом Неопределенности

def generate_signals(ensemble, features, threshold=0.6):
"""
Генерация торговых сигналов с учетом неопределенности для размера позиции.
"""
# Получаем предсказания ансамбля
mean_pred, total_std, epistemic_std, aleatoric_std = ensemble.predict(features)
# Вычисляем силу сигнала
signal_strength = mean_pred / total_std # Отношение типа Шарпа
signals = []
for i in range(len(mean_pred)):
# Проверяем уверенность предсказания
if epistemic_std[i] > threshold * total_std[i]:
# Высокая модельная неопределенность - не торгуем
signals.append(Signal("HOLD", confidence=0))
continue
# Генерируем сигнал на основе предсказания
if signal_strength[i] > 1.5:
confidence = min(0.95, 1 - epistemic_std[i] / total_std[i])
signals.append(Signal("LONG", confidence=confidence))
elif signal_strength[i] < -1.5:
confidence = min(0.95, 1 - epistemic_std[i] / total_std[i])
signals.append(Signal("SHORT", confidence=confidence))
else:
signals.append(Signal("HOLD", confidence=0))
return signals

Размер Позиции на Основе Неопределенности

def calculate_position_size(signal, uncertainty, max_position=0.1):
"""
Размер позиции обратно пропорционален неопределенности.
Размер по Келли с поправкой на неопределенность.
"""
if signal.type == "HOLD":
return 0
# Базовая доля по Келли
kelly_fraction = signal.confidence / (1 + uncertainty["total_std"])
# Уменьшаем позицию при высокой эпистемической неопределенности
epistemic_penalty = 1 - min(1, uncertainty["epistemic_std"] / uncertainty["total_std"])
# Итоговая позиция
position = kelly_fraction * epistemic_penalty * max_position
return position if signal.type == "LONG" else -position

Детекция Режима через Неопределенность

def detect_regime(ensemble_predictions, window=20):
"""
Детекция смены рыночного режима через динамику неопределенности.
"""
recent_epistemic = epistemic_std[-window:]
recent_aleatoric = aleatoric_std[-window:]
epistemic_trend = np.polyfit(range(window), recent_epistemic, 1)[0]
aleatoric_trend = np.polyfit(range(window), recent_aleatoric, 1)[0]
if epistemic_trend > 0.1:
return "REGIME_CHANGE" # Модель становится неуверенной
elif aleatoric_trend > 0.1:
return "VOLATILITY_SPIKE" # Рынок становится хаотичным
elif np.mean(recent_epistemic) < 0.1 and np.mean(recent_aleatoric) < 0.1:
return "STABLE"
else:
return "NORMAL"

Детали Реализации

Конфигурация Обучения

ensemble:
num_models: 5
architecture:
hidden_dims: [256, 128, 64]
activation: "relu"
dropout: 0.2
output_type: "gaussian" # Выход (μ, σ)
training:
batch_size: 64
learning_rate: 0.001
weight_decay: 0.0001
max_epochs: 100
early_stopping_patience: 10
loss: "nll" # Negative log-likelihood
data:
train_split: 0.7
val_split: 0.15
test_split: 0.15
sequence_length: 60
prediction_horizon: 5
features:
- returns_1m
- returns_5m
- returns_15m
- returns_1h
- volume_ratio
- volatility
- rsi_14
- macd_signal
- spread_bps

Инженерия Признаков

features = {
# Ценовые признаки
'returns_1m': log_return(close, 1),
'returns_5m': log_return(close, 5),
'returns_15m': log_return(close, 15),
'returns_1h': log_return(close, 60),
'returns_4h': log_return(close, 240),
# Признаки волатильности
'volatility_1h': rolling_std(returns, 60),
'volatility_24h': rolling_std(returns, 1440),
'volatility_ratio': volatility_1h / volatility_24h,
# Признаки объема
'volume_ratio': volume / volume_ma_20,
'vwap_deviation': (close - vwap) / vwap,
# Технические индикаторы
'rsi_14': rsi(close, 14),
'macd_signal': macd(close) - macd_signal(close),
'bb_position': (close - bb_lower) / (bb_upper - bb_lower),
# Признаки книги ордеров
'spread_bps': (ask - bid) / mid * 10000,
'depth_imbalance': (bid_depth - ask_depth) / (bid_depth + ask_depth),
}

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

Качество Модели

МетрикаОписаниеЦель
NLLNegative log-likelihoodМеньше лучше
Calibration ErrorНасколько неопределенность соответствует ошибкам< 0.1
SharpnessСредняя предсказанная неопределенностьБаланс с калибровкой
CRPSContinuous Ranked Probability ScoreМеньше лучше

Торговое Качество

МетрикаОписаниеЦель
Sharpe RatioДоходность с учетом риска> 2.0
Sortino RatioС учетом нисходящего риска> 2.5
Max DrawdownМаксимальная просадка< 10%
Win Rate% прибыльных сделок> 55%
Profit FactorВаловая прибыль / Валовый убыток> 1.5
Uncertainty-Adjusted ReturnДоходность / Средняя неопределенностьВыше лучше

Метрики Калибровки

def calibration_error(predictions, actuals, num_bins=10):
"""
Expected Calibration Error (ECE)
Для хорошо откалиброванных предсказаний, X% исходов должны
попадать в X% доверительные интервалы.
"""
confidences = 1 - predictions['std'] / predictions['std'].max()
accuracies = np.abs(predictions['mean'] - actuals) < predictions['std']
ece = 0
for bin_lower in np.linspace(0, 1, num_bins):
bin_upper = bin_lower + 1/num_bins
in_bin = (confidences > bin_lower) & (confidences <= bin_upper)
if in_bin.sum() > 0:
avg_confidence = confidences[in_bin].mean()
avg_accuracy = accuracies[in_bin].mean()
ece += np.abs(avg_accuracy - avg_confidence) * in_bin.mean()
return ece

Преимущества Deep Ensembles

АспектОдиночная модельDeep Ensemble
Оценка неопределенностиНетВстроенная
РобастностьСклонна к переобучениюБолее робастна
КалибровкаЧасто самоувереннаЛучше откалибрована
КачествоОдин оптимумАгрегация оптимумов
ИнтерпретируемостьЧерный ящикНесогласие = неопределенность
МасштабируемостьН/ДТривиально параллелится

Сравнение с Другими Методами

vs. Байесовские Нейронные Сети (BNN)

BNN:
+ Принципиальная неопределенность из апостериора
- Сложно обучать
- Дорогой инференс
- Требует аппроксимаций (VI, MCMC)
Deep Ensembles:
+ Просто реализовать
+ Параллельное обучение
+ Часто лучше калибровка
- Требует M forward passes
- Нет интерпретации апостериора

vs. MC Dropout

MC Dropout:
+ Одна модель, много проходов
+ Экономия памяти
- Недооценивает неопределенность
- Зависит от dropout rate
Deep Ensembles:
+ Лучшие оценки неопределенности
+ Более разнообразные предсказания
- Больше памяти (M моделей)
- Больше время обучения

vs. Одиночная Модель с Калибровкой Softmax

Калибровка Softmax:
+ Одна модель
+ Post-hoc калибровка
- Только классификация
- Ограниченные типы неопределенности
Deep Ensembles:
+ Работает для регрессии
+ Разделение эпистемич/алеаторной
- Выше вычислительные затраты

Продакшн Соображения

Пайплайн инференса:
├── Сбор данных (Bybit WebSocket)
│ └── Real-time OHLCV + обновления книги ордеров
├── Вычисление признаков
│ └── Расчеты скользящих окон
├── Инференс ансамбля
│ ├── Параллельный forward pass (M моделей)
│ ├── Агрегация (среднее, стд)
│ └── Декомпозиция неопределенности
├── Генерация сигналов
│ ├── Фильтрация по уверенности
│ └── Размер позиции
└── Исполнение ордеров
└── Интеграция с риск-менеджментом
Бюджет задержки:
├── Сбор данных: ~10мс (WebSocket)
├── Вычисление признаков: ~5мс
├── Инференс ансамбля: ~20мс (параллельно, GPU)
├── Генерация сигналов: ~2мс
└── Итого: ~40мс (без учета исполнения)

Структура Директории

326_deep_ensembles_trading/
├── README.md # Английская версия
├── README.ru.md # Этот файл
├── readme.simple.md # Простое объяснение
├── readme.simple.ru.md # Простое объяснение на русском
├── python/ # Python реализация
│ ├── requirements.txt # Зависимости Python
│ ├── deep_ensemble.py # Основная модель ансамбля
│ ├── data_fetcher.py # Получение данных с Bybit и инженерия признаков
│ ├── strategy.py # Торговая стратегия с учетом неопределенности
│ ├── backtest.py # Фреймворк бэктестинга
│ └── example.py # Полный пример
└── rust_deep_ensembles/ # Rust реализация
├── Cargo.toml
├── src/
│ ├── lib.rs # Точка входа библиотеки
│ ├── api/ # Клиент API Bybit
│ ├── ensemble/ # Реализация Deep Ensemble
│ ├── features/ # Инженерия признаков
│ ├── strategy/ # Торговая стратегия
│ └── backtest/ # Движок бэктестинга
└── examples/
├── fetch_data.rs
├── train_ensemble.rs
├── backtest.rs
└── live_signals.rs

Ссылки

  1. Simple and Scalable Predictive Uncertainty Estimation using Deep Ensembles (Lakshminarayanan et al., 2017)

  2. Deep Ensembles: A Loss Landscape Perspective (Fort et al., 2019)

  3. Uncertainty Quantification in Deep Learning (Abdar et al., 2021)

  4. Can You Trust Your Model’s Uncertainty? (Ovadia et al., 2019)

  5. Hyperparameter Ensembles (Wenzel et al., 2020)

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

Средний - Требует понимания:

  • Обучения нейронных сетей
  • Вероятностных распределений (гауссово)
  • Основ оценки неопределенности
  • Основ трейдинга

Дисклеймер

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