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

Глава 327: Байесовские нейронные сети для трейдинга

Обзор

Байесовские нейронные сети (БНС) представляют собой парадигмальный сдвиг от традиционных нейронных сетей, рассматривая веса сети как распределения вероятностей, а не фиксированные значения. Это фундаментальное изменение обеспечивает квантификацию неопределенности - способность знать не только что предсказывает модель, но и насколько она уверена в этом предсказании. Для трейдинга эта возможность бесценна: мы можем различать сигналы высокой уверенности, на которые стоит действовать, и неопределенные предсказания, требующие осторожности.

Почему байесовские нейронные сети для трейдинга?

Проблема традиционных нейронных сетей

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

Традиционная НС: Вход → Предсказание (65% вероятность роста цены)
"Насколько вы уверены?" → "Не знаю"

Это проблематично для трейдинга, потому что:

  1. Все предсказания выглядят одинаково уверенными - даже когда модель угадывает
  2. Нет различия между известным и неизвестным - экстраполяция выглядит так же, как интерполяция
  3. Переобучение невидимо - чрезмерно уверенные предсказания на новых рыночных условиях
  4. Размер позиции произволен - нет принципиального способа масштабировать ставки по уверенности

Байесовское решение

БНС поддерживают распределения над весами, что позволяет:

Байесовская НС: Вход → Распределение предсказаний
Среднее: 65% вверх, Std: 15%
"Высокая неопределенность - уменьшите размер позиции"
vs.
Среднее: 68% вверх, Std: 3%
"Высокая уверенность - полный размер позиции"

Теоретические основы

Неопределенность весов в нейронных сетях

Традиционные нейронные сети обучают точечные оценки весов:

Стандартная НС: w = argmax P(D|w) (Максимум правдоподобия)
Байесовская НС: P(w|D) ∝ P(D|w) P(w) (Апостериорное распределение весов)

Где:

  • P(w|D) = Апостериорное распределение весов при данных
  • P(D|w) = Правдоподобие данных при весах
  • P(w) = Априорное распределение весов

Априорные распределения

Априорное распределение P(w) кодирует наши убеждения о весах до наблюдения данных:

Распространенные априорные распределения:
1. Стандартное нормальное:
P(w) = N(0, 1)
- Поощряет малые веса
- Действует как L2 регуляризация
2. Spike-and-Slab (Пик-и-плита):
P(w) = π·δ(0) + (1-π)·N(0, σ²)
- Поощряет разреженность
- Некоторые веса точно нулевые
3. Иерархическое априорное:
P(w|σ) = N(0, σ²)
P(σ) = InverseGamma(α, β)
- Обучает подходящую регуляризацию
- Автоматическое определение релевантности
4. Смесь гауссианов:
P(w) = Σᵢ πᵢ N(μᵢ, σᵢ²)
- Гибкие формы априорных
- Может захватывать мультимодальные убеждения

Байес через обратное распространение (Bayes by Backprop)

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

Истинное апостериорное: P(w|D) - невычислимо
Аппроксимация: q(w|θ) - параметризованное распределение
Цель: Найти θ, минимизирующее KL-дивергенцию:
KL[q(w|θ) || P(w|D)]

Это приводит к нижней границе доказательства (ELBO):

ELBO(θ) = E_q[log P(D|w)] - KL[q(w|θ) || P(w)]
= Член соответствия данным - Член сложности
Максимизация ELBO ≈ Минимизация KL-дивергенции к истинному апостериорному

Трюк репараметризации

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

Вместо: w ~ q(w|θ) = N(μ, σ²)
Используем: ε ~ N(0, 1)
w = μ + σ·ε
Это позволяет градиентам проходить через μ и σ!

Архитектура

┌─────────────────────────────────────────────────────────────────────┐
│ БАЙЕСОВСКАЯ НЕЙРОННАЯ СЕТЬ │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ВХОДНОЙ СЛОЙ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Рыночные признаки: │ │
│ │ - Доходности (1м, 5м, 15м, 1ч, 4ч, 1д) │ │
│ │ - Метрики объема (соотношение, отклонение от VWAP) │ │
│ │ - Признаки книги ордеров (спред, дисбаланс, глубина) │ │
│ │ - Технические индикаторы (RSI, MACD, Боллинджер, ATR) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ БАЙЕСОВСКИЕ ПОЛНОСВЯЗНЫЕ СЛОИ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Слой 1: BayesianLinear(input_dim, 256) │ │
│ │ - Распределение весов: N(μ_w, σ_w²) │ │
│ │ - Распределение смещений: N(μ_b, σ_b²) │ │
│ │ - Локальная репараметризация для эффективности │ │
│ │ - Активация: LeakyReLU │ │
│ │ - Dropout: 0.2 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Слой 2: BayesianLinear(256, 128) │ │
│ │ - То же байесовское обращение │ │
│ │ - Активация: LeakyReLU │ │
│ │ - Dropout: 0.2 │ │
│ └────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Слой 3: BayesianLinear(128, 64) │ │
│ │ - То же байесовское обращение │ │
│ │ - Активация: LeakyReLU │ │
│ └────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ВЫХОДНЫЕ ГОЛОВЫ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Голова направления: BayesianLinear(64, 3) │ │
│ │ - Выход: P(вверх), P(нейтрально), P(вниз) │ │
│ │ - Активация Softmax │ │
│ │ │ │
│ │ Голова доходности: BayesianLinear(64, 2) │ │
│ │ - Выход: μ_return, σ_return (распред. предсказанной дох.) │ │
│ │ - Гетероскедастическая неопределенность │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ КВАНТИФИКАЦИЯ НЕОПРЕДЕЛЕННОСТИ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Монте-Карло выборка (N=100 прямых проходов): │ │
│ │ - Эпистемическая неопределенность: дисперсия от выборки │ │
│ │ - Алеаторная неопределенность: предсказанная дисперсия │ │
│ │ - Общая неопределенность: Эпистемическая + Алеаторная │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘

Типы неопределенности

Эпистемическая неопределенность (Неопределенность модели)

То, чего модель не знает - уменьшается с большим количеством данных:

Источники:
- Ограниченные обучающие данные
- Неправильная спецификация модели
- Входы вне распределения
В БНС: Захватывается дисперсией распределений весов
Высокая дисперсия весов → Высокая эпистемическая неопределенность
Торговые последствия:
- Новый рыночный режим → Высокая эпистемическая неопределенность → Уменьшить экспозицию
- Больше обучающих данных → Меньше эпистемической неопределенности

Алеаторная неопределенность (Неопределенность данных)

Присущая случайность в данных - неустранимый шум:

Источники:
- Шум микроструктуры рынка
- Новостные события
- Случайные флуктуации
В БНС: Захватывается гетероскедастическим выходным слоем
Предсказывает и среднее И дисперсию доходности
Торговые последствия:
- Периоды высокой волатильности → Высокая алеаторная неопределенность
- Нельзя уменьшить большим количеством данных
- Принять или хеджировать

Разделение двух типов

# Монте-Карло вывод
predictions = []
for _ in range(100):
pred_mean, pred_var = model.forward(x, sample=True) # Выборка весов
predictions.append((pred_mean, pred_var))
# Эпистемическая неопределенность: дисперсия средних
epistemic = np.var([p[0] for p in predictions])
# Алеаторная неопределенность: среднее дисперсий
aleatoric = np.mean([p[1] for p in predictions])
# Общая неопределенность
total = epistemic + aleatoric

Реализация байесовского слоя

Слой BayesianLinear

class BayesianLinear(nn.Module):
def __init__(self, in_features, out_features, prior_sigma=1.0):
super().__init__()
# Параметры весов (среднее и логарифм дисперсии)
self.weight_mu = nn.Parameter(torch.zeros(out_features, in_features))
self.weight_rho = nn.Parameter(torch.ones(out_features, in_features) * -3)
# Параметры смещений
self.bias_mu = nn.Parameter(torch.zeros(out_features))
self.bias_rho = nn.Parameter(torch.ones(out_features) * -3)
# Априорное распределение
self.prior_sigma = prior_sigma
# Инициализация
nn.init.kaiming_normal_(self.weight_mu)
def forward(self, x, sample=True):
if sample:
# Трюк репараметризации
weight_sigma = F.softplus(self.weight_rho)
weight = self.weight_mu + weight_sigma * torch.randn_like(weight_sigma)
bias_sigma = F.softplus(self.bias_rho)
bias = self.bias_mu + bias_sigma * torch.randn_like(bias_sigma)
else:
# Использовать средние веса (без выборки)
weight = self.weight_mu
bias = self.bias_mu
return F.linear(x, weight, bias)
def kl_divergence(self):
"""KL-дивергенция от апостериорного к априорному"""
weight_sigma = F.softplus(self.weight_rho)
bias_sigma = F.softplus(self.bias_rho)
# KL для весов
kl_weight = self._kl_normal(self.weight_mu, weight_sigma, 0, self.prior_sigma)
# KL для смещений
kl_bias = self._kl_normal(self.bias_mu, bias_sigma, 0, self.prior_sigma)
return kl_weight + kl_bias
def _kl_normal(self, mu1, sigma1, mu2, sigma2):
"""KL-дивергенция между двумя нормальными распределениями"""
return 0.5 * torch.sum(
2 * torch.log(sigma2 / sigma1)
+ (sigma1**2 + (mu1 - mu2)**2) / sigma2**2
- 1
)

Обучение с ELBO

Функция потерь

def elbo_loss(model, x, y, n_samples=1, beta=1.0):
"""
Потеря на основе нижней границы доказательства (ELBO)
Аргументы:
model: БНС модель
x: Входные признаки
y: Целевые метки
n_samples: Количество MC выборок
beta: Коэффициент взвешивания KL (для KL отжига)
Возвращает:
loss: -ELBO (для минимизации)
"""
# Член правдоподобия (соответствие данным)
log_likelihood = 0
for _ in range(n_samples):
output = model(x, sample=True)
log_likelihood += F.cross_entropy(output, y, reduction='sum')
log_likelihood /= n_samples
# Член KL-дивергенции (штраф за сложность)
kl_div = model.kl_divergence()
# ELBO = E[log p(D|w)] - KL[q(w|θ) || p(w)]
# Мы минимизируем отрицательный ELBO
loss = log_likelihood + beta * kl_div
return loss

KL отжиг (KL Annealing)

# Постепенно увеличиваем вес KL во время обучения
# Предотвращает коллапс апостериорного в начале обучения
def get_beta(epoch, warmup_epochs=10):
"""Расписание KL отжига"""
if epoch < warmup_epochs:
return epoch / warmup_epochs
return 1.0

Торговая стратегия с учетом неопределенности

Генерация сигналов с уверенностью

def generate_signals(model, features, threshold=0.6, uncertainty_scale=True):
"""
Генерация торговых сигналов с размером позиции на основе неопределенности
Аргументы:
model: Обученная БНС
features: Рыночные признаки
threshold: Минимальная уверенность для сигнала
uncertainty_scale: Масштабировать позицию по неопределенности
Возвращает:
signals: Список торговых сигналов
"""
# Монте-Карло вывод
n_samples = 100
predictions = []
for _ in range(n_samples):
logits = model(features, sample=True)
probs = F.softmax(logits, dim=-1)
predictions.append(probs)
predictions = torch.stack(predictions)
# Среднее предсказание
mean_probs = predictions.mean(dim=0)
# Эпистемическая неопределенность (дисперсия предсказаний)
epistemic_unc = predictions.var(dim=0).sum(dim=-1)
signals = []
for i in range(len(features)):
prob_up = mean_probs[i, 0].item()
prob_down = mean_probs[i, 2].item()
uncertainty = epistemic_unc[i].item()
# Преобразование неопределенности в уверенность
confidence = 1.0 / (1.0 + uncertainty)
if prob_up > threshold:
position_size = confidence if uncertainty_scale else 1.0
signals.append(Signal(
direction="LONG",
probability=prob_up,
uncertainty=uncertainty,
position_size=position_size
))
elif prob_down > threshold:
position_size = confidence if uncertainty_scale else 1.0
signals.append(Signal(
direction="SHORT",
probability=prob_down,
uncertainty=uncertainty,
position_size=position_size
))
return signals

Размер позиции по неопределенности

def kelly_criterion_bayesian(prob_win, uncertainty, win_size, loss_size):
"""
Модифицированный критерий Келли с учетом неопределенности
Стандартный Келли: f = (p*b - q) / b
Байесовский Келли: f = (p*b - q) / b * (1 - штраф_неопределенности)
Аргументы:
prob_win: Оцененная вероятность выигрыша
uncertainty: Неопределенность модели (от 0 до 1)
win_size: Ожидаемая сумма выигрыша
loss_size: Ожидаемая сумма проигрыша
Возвращает:
fraction: Оптимальный размер позиции (от 0 до 1)
"""
# Стандартный Келли
b = win_size / loss_size # Коэффициенты
q = 1 - prob_win
kelly = (prob_win * b - q) / b
# Штраф за неопределенность
# Выше неопределенность → меньше позиция
uncertainty_penalty = uncertainty ** 0.5 # Корень для плавного масштабирования
adjusted_kelly = kelly * (1 - uncertainty_penalty)
# Ограничение [0, 0.25] (никогда не ставить больше 25%)
return max(0, min(0.25, adjusted_kelly))

Выбор гиперпараметров

Выбор априорного распределения

prior_options:
# Для регуляризации, похожей на L2
standard_gaussian:
sigma: 1.0
use_case: "По умолчанию, общего назначения"
# Для разреженных сетей
spike_and_slab:
spike_prob: 0.5
slab_sigma: 1.0
use_case: "Отбор признаков, интерпретируемость"
# Для адаптивной регуляризации
hierarchical:
alpha: 1.0
beta: 1.0
use_case: "Автоматическое определение релевантности"

Соображения по архитектуре

architecture:
# Меньше слоев, чем в стандартной НС (каждый слой имеет 2x параметров)
num_layers: 3-4
# Умеренная ширина (оценка неопределенности масштабируется с параметрами)
hidden_dims: [256, 128, 64]
# Конфигурация выхода
output_type: "heteroscedastic" # Предсказывать среднее и дисперсию
# MC выборки для вывода
mc_samples_train: 1-5
mc_samples_inference: 50-200

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

training:
# Меньшая скорость обучения (больше параметров для оценки)
learning_rate: 0.0001
# Более длительное обучение (сходимость медленнее)
epochs: 200
# KL отжиг предотвращает коллапс апостериорного
kl_warmup_epochs: 20
# Финальный вес KL
kl_weight: 1.0
# Размер батча (больший помогает с шумом градиента)
batch_size: 128

Сравнение с альтернативами

БНС vs. MC Dropout

АспектБНСMC Dropout
Параметры2x (среднее + дисперсия)1x
ОбучениеСложнееСтандартное + dropout
ВыводВыборка весовDropout активен
Качество неопределенностиЛучше откалиброваноЧасто чрезмерно уверено
Вычислительная стоимостьВышеНиже
РеализацияСложнаяПростая

БНС vs. Глубокие ансамбли

АспектБНСГлубокие ансамбли
Параметры2x на сетьNx на сеть (N моделей)
РазнообразиеРаспределения весовРазные инициализации
ОбучениеОдна модельN отдельных обучений
Качество неопределенностиХорошееОчень хорошее
Память2xNx
ИнтерпретируемостьАнализ апостериорногоПодсчет голосов

Когда использовать БНС

Используйте БНС когда:
✓ Квантификация неопределенности критична
✓ Данных мало
✓ Ожидаются новые/необычные входы
✓ Размер позиции должен быть принципиальным
✓ Важно понимание уверенности модели
Рассмотрите альтернативы когда:
✗ Вычислительные ресурсы ограничены
✗ Доступны большие наборы данных (меньше пользы от неопределенности)
✗ Скорость критична (вывод медленнее)
✗ Простота реализации приоритетна

Продакшн развертывание

Пайплайн вывода

Реал-тайм торговый пайплайн:
├── Сбор данных
│ └── Bybit WebSocket → OHLCV + Книга ордеров
├── Инженерия признаков
│ └── Технические индикаторы + Рыночные признаки
├── Байесовский вывод
│ └── MC выборка (100 прямых проходов)
├── Вычисление неопределенности
│ └── Разложение на эпистемическую + алеаторную
├── Генерация сигналов
│ └── Направление + Уверенность + Размер позиции
├── Риск-менеджмент
│ └── Размер позиции с учетом неопределенности
└── Исполнение ордеров
└── Размер на основе уверенности

Соображения по задержке

Бюджет задержки:
├── Сбор данных: ~10мс
├── Вычисление признаков: ~5мс
├── MC вывод (100 выборок): ~50-100мс
│ └── Можно параллелить на GPU
├── Вычисление неопределенности: ~5мс
├── Генерация сигналов: ~2мс
└── Итого: ~70-120мс
Стратегии оптимизации:
- Меньше MC выборок в продакшне (50 vs 200)
- Батчинг нескольких активов
- Кэширование аппроксимаций апостериорного
- Использовать среднее предсказание для скрининга, полный MC для финальных сигналов

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

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

  • ELBO: Целевая функция обучения (выше лучше)
  • Ошибка калибровки: Соответствует ли предсказанная неопределенность реальной ошибке?
  • Отрицательное логарифмическое правдоподобие: Качество предсказания с неопределенностью

Качество неопределенности

  • Покрытие: % истинных значений внутри предсказанных интервалов
  • Острота: Узость интервалов предсказания
  • Правильные правила оценки: Оценка Брайера, CRPS

Торговая эффективность

  • Коэффициент Шарпа: Доходность с поправкой на риск
  • Шарп с учетом неопределенности: Шарп с учетом уверенности предсказаний
  • Максимальная просадка: Наибольшее падение от пика до дна
  • Процент выигрышей по уверенности: Процент выигрышей, стратифицированный по уровню неопределенности

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

327_bayesian_neural_network/
├── README.md # Английская версия
├── README.ru.md # Этот файл
├── README.specify.md # Исходная спецификация
├── readme.simple.md # Простое объяснение (англ.)
├── readme.simple.ru.md # Простое объяснение (рус.)
├── python/ # Python реализация
│ ├── requirements.txt
│ ├── bnn/
│ │ ├── __init__.py
│ │ ├── layers.py # Байесовские слои
│ │ ├── model.py # Модель БНС
│ │ ├── loss.py # Потеря ELBO
│ │ └── inference.py # MC вывод
│ ├── data/
│ │ ├── __init__.py
│ │ └── bybit_fetcher.py # Получение данных через CCXT
│ ├── features/
│ │ ├── __init__.py
│ │ └── engineering.py # Инженерия признаков
│ ├── strategy/
│ │ ├── __init__.py
│ │ └── trading.py # Торговая стратегия
│ └── examples/
│ ├── __init__.py
│ ├── train_bnn.py
│ ├── backtest.py
│ └── fetch_data.py
└── rust_bnn/ # Rust реализация
├── Cargo.toml
├── README.md
├── src/
│ ├── lib.rs
│ ├── api/ # Клиент Bybit API
│ ├── bnn/ # Реализация БНС
│ ├── features/ # Инженерия признаков
│ ├── strategy/ # Торговая стратегия
│ └── backtest/ # Бэктестинг
└── examples/
├── fetch_data.rs
├── train_bnn.rs
└── backtest.rs

Ссылки

  1. Weight Uncertainty in Neural Networks (Blundell et al., 2015)

  2. Dropout as a Bayesian Approximation (Gal & Ghahramani, 2016)

  3. What Uncertainties Do We Need in Bayesian Deep Learning? (Kendall & Gal, 2017)

  4. Practical Variational Inference for Neural Networks (Graves, 2011)

  5. Deep Ensemble (Lakshminarayanan et al., 2017)

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

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

  • Байесовской статистики и теории вероятностей
  • Архитектур нейронных сетей
  • Вариационного вывода
  • Методов Монте-Карло
  • Финансового риск-менеджмента

Отказ от ответственности

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