Глава 327: Байесовские нейронные сети для трейдинга
Обзор
Байесовские нейронные сети (БНС) представляют собой парадигмальный сдвиг от традиционных нейронных сетей, рассматривая веса сети как распределения вероятностей, а не фиксированные значения. Это фундаментальное изменение обеспечивает квантификацию неопределенности - способность знать не только что предсказывает модель, но и насколько она уверена в этом предсказании. Для трейдинга эта возможность бесценна: мы можем различать сигналы высокой уверенности, на которые стоит действовать, и неопределенные предсказания, требующие осторожности.
Почему байесовские нейронные сети для трейдинга?
Проблема традиционных нейронных сетей
Стандартные нейронные сети производят точечные оценки - единичные предсказания без какой-либо меры уверенности:
Традиционная НС: Вход → Предсказание (65% вероятность роста цены) "Насколько вы уверены?" → "Не знаю"Это проблематично для трейдинга, потому что:
- Все предсказания выглядят одинаково уверенными - даже когда модель угадывает
- Нет различия между известным и неизвестным - экстраполяция выглядит так же, как интерполяция
- Переобучение невидимо - чрезмерно уверенные предсказания на новых рыночных условиях
- Размер позиции произволен - нет принципиального способа масштабировать ставки по уверенности
Байесовское решение
БНС поддерживают распределения над весами, что позволяет:
Байесовская НС: Вход → Распределение предсказаний Среднее: 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 lossKL отжиг (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 отдельных обучений |
| Качество неопределенности | Хорошее | Очень хорошее |
| Память | 2x | Nx |
| Интерпретируемость | Анализ апостериорного | Подсчет голосов |
Когда использовать БНС
Используйте БНС когда:✓ Квантификация неопределенности критична✓ Данных мало✓ Ожидаются новые/необычные входы✓ Размер позиции должен быть принципиальным✓ Важно понимание уверенности модели
Рассмотрите альтернативы когда:✗ Вычислительные ресурсы ограничены✗ Доступны большие наборы данных (меньше пользы от неопределенности)✗ Скорость критична (вывод медленнее)✗ Простота реализации приоритетнаПродакшн развертывание
Пайплайн вывода
Реал-тайм торговый пайплайн:├── Сбор данных│ └── 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Ссылки
-
Weight Uncertainty in Neural Networks (Blundell et al., 2015)
- https://arxiv.org/abs/1505.05424
- Оригинальная статья Bayes by Backprop
-
Dropout as a Bayesian Approximation (Gal & Ghahramani, 2016)
- https://arxiv.org/abs/1506.02142
- MC Dropout как аппроксимация вывода
-
What Uncertainties Do We Need in Bayesian Deep Learning? (Kendall & Gal, 2017)
- https://arxiv.org/abs/1703.04977
- Эпистемическая vs. алеаторная неопределенность
-
Practical Variational Inference for Neural Networks (Graves, 2011)
- https://papers.nips.cc/paper/4329-practical-variational-inference-for-neural-networks
- Ранняя работа по вариационным БНС
-
Deep Ensemble (Lakshminarayanan et al., 2017)
- https://arxiv.org/abs/1612.01474
- Сравнительный подход для неопределенности
Уровень сложности
Продвинутый - Требует понимания:
- Байесовской статистики и теории вероятностей
- Архитектур нейронных сетей
- Вариационного вывода
- Методов Монте-Карло
- Финансового риск-менеджмента
Отказ от ответственности
Эта глава предназначена только для образовательных целей. Торговля криптовалютами сопряжена со значительным риском потерь. Стратегии и модели, описанные здесь, не были проверены в реальной торговле и должны быть тщательно протестированы перед любым применением в реальном мире. Прошлые результаты не гарантируют будущих результатов. Всегда торгуйте ответственно и никогда не рискуйте больше, чем можете позволить себе потерять.