Глава 351: WaveNet для Трейдинга
Обзор
WaveNet - это глубокая генеративная модель, изначально разработанная DeepMind для генерации сырого аудио. Её ключевая инновация - расширенные причинные свёртки (dilated causal convolutions) - делает её исключительно подходящей для прогнозирования финансовых временных рядов. В этой главе мы рассмотрим, как адаптировать архитектуру WaveNet для торговли криптовалютами с использованием данных биржи Bybit.
Содержание
- Введение
- Архитектура WaveNet
- Расширенные причинные свёртки
- Адаптация WaveNet для трейдинга
- Реализация
- Торговая стратегия
- Результаты бэктестинга
- Ссылки
Введение
Почему WaveNet для трейдинга?
Традиционные рекуррентные нейронные сети (RNN, LSTM, GRU) обрабатывают последовательности пошагово, что приводит к:
- Медленным вычислениям
- Сложностям с параллелизацией
- Затуханию градиентов для длинных последовательностей
WaveNet решает эти проблемы с помощью расширенных причинных свёрток:
- Параллельная обработка последовательностей (быстрое обучение)
- Эффективный захват долгосрочных зависимостей
- Сохранение причинности (нет утечки информации из будущего)
Ключевые концепции
| Концепция | Описание |
|---|---|
| Причинная свёртка | Свёртка, которая смотрит только на прошлые данные |
| Расширенная свёртка | Свёртка с пропусками между входами |
| Рецептивное поле | Как далеко в прошлое может “видеть” сеть |
| Skip-соединения | Прямые пути для многомасштабного извлечения признаков |
| Остаточные соединения | Помогают потоку градиентов в глубоких сетях |
Архитектура WaveNet
Оригинальная архитектура
Вход → Причинная Conv → [Расширенный Conv Блок] × N → Skip-соединения → Выход ↓ Вентильная активация (tanh ⊗ sigmoid)Основные компоненты
-
Причинный свёрточный слой
- Обеспечивает отсутствие утечки информации из будущего
- Первый слой, обрабатывающий сырой вход
-
Блоки расширенных свёрток
- Несколько слоёв с возрастающими коэффициентами расширения
- Экспоненциально растущее рецептивное поле: 1, 2, 4, 8, 16, 32…
-
Вентильные функции активации
z = tanh(Wf * x) ⊙ sigmoid(Wg * x)- Wf: веса фильтра (что изучать)
- Wg: веса ворот (что забывать)
-
Skip и остаточные соединения
- Skip: агрегация информации со всех слоёв
- Остаточные: обеспечивают поток градиентов в глубоких сетях
Расчёт рецептивного поля
Для расширенных свёрток с коэффициентами расширения [1, 2, 4, 8, 16, …]:
Рецептивное поле = (размер_ядра - 1) × Σ(коэффициенты_расширения) + 1Пример: При размере ядра 2 и 10 слоях:
- Коэффициенты расширения: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
- Рецептивное поле = (2-1) × 1023 + 1 = 1024 временных шага
Это означает, что при часовых данных модель может “видеть” ~42 дня истории!
Расширенные причинные свёртки
Почему расширенные?
Стандартные свёртки имеют линейную зависимость между рецептивным полем и глубиной:
- Рецептивное поле N требует N слоёв
- 1000 временных шагов потребуют 1000 слоёв!
Расширенные свёртки обеспечивают экспоненциальный рост:
- Рецептивное поле N требует только log₂(N) слоёв
- 1024 временных шага требуют только 10 слоёв!
Визуальное представление
Расширение = 1: ●─●─●─● │ │ │ │ [Conv слой]
Расширение = 2: ●───●───●───● │ │ │ │ [Conv слой]
Расширение = 4: ●───────●───────●───────● │ │ │ │ [Conv слой]Причинное дополнение (Causal Padding)
Для сохранения причинности используется асимметричное дополнение:
- Дополнение только слева
- Гарантирует, что output[t] зависит только от input[0:t]
// Причинное дополнение для 1D свёрткиfn causal_pad(input: &[f64], padding: usize) -> Vec<f64> { let mut padded = vec![0.0; padding]; padded.extend_from_slice(input); padded}Адаптация WaveNet для трейдинга
Модификации для финансовых временных рядов
-
Входные признаки
- OHLCV данные (Open, High, Low, Close, Volume)
- Технические индикаторы (RSI, MACD, полосы Боллинджера)
- Признаки микроструктуры рынка
-
Выходные головы
- Регрессия: прогноз следующей цены/доходности
- Классификация: прогноз направления (вверх/вниз/нейтрально)
- Вероятностный: прогноз параметров распределения
-
Функции потерь
- MSE/MAE для регрессии
- Кросс-энтропия для классификации
- Пользовательские торговые потери (учитывающие Sharpe)
Архитектура для трейдинга
Входные признаки (OHLCV + Индикаторы) ↓ Проекция входа (Linear) ↓ ┌─────────────────────────┐ │ WaveNet блоки (×N) │ │ ├─ Расширенная Conv │ │ ├─ Вентильная активация│ │ ├─ Остаточное соединение│ │ └─ Skip-соединение │ └─────────────────────────┘ ↓ Агрегация Skip (Sum) ↓ Выходные слои (Dense) ↓ Прогнозы (Цена/Направление)Реализация
Структура Rust-реализации
351_wavenet_trading/├── README.md├── README.ru.md├── readme.simple.md├── readme.simple.ru.md└── rust/ ├── Cargo.toml └── src/ ├── lib.rs ├── api/ # Клиент Bybit API │ ├── mod.rs │ ├── bybit.rs │ └── storage.rs ├── models/ # Модель WaveNet │ ├── mod.rs │ ├── wavenet.rs │ ├── layers.rs │ └── activations.rs ├── trading/ # Торговая логика │ ├── mod.rs │ ├── strategy.rs │ ├── signals.rs │ └── backtest.rs ├── analysis/ # Анализ данных │ ├── mod.rs │ ├── features.rs │ └── indicators.rs └── bin/ # Исполняемые файлы ├── fetch_data.rs ├── train_wavenet.rs ├── predict.rs └── backtest.rsКлючевые детали реализации
1. Расширенная свёртка
pub struct DilatedConv1D { weights: Vec<Vec<f64>>, bias: Vec<f64>, kernel_size: usize, dilation: usize, channels_in: usize, channels_out: usize,}
impl DilatedConv1D { pub fn forward(&self, input: &[Vec<f64>]) -> Vec<Vec<f64>> { let seq_len = input[0].len(); let mut output = vec![vec![0.0; seq_len]; self.channels_out];
for t in 0..seq_len { for c_out in 0..self.channels_out { let mut sum = self.bias[c_out];
for k in 0..self.kernel_size { let idx = t as i64 - (k * self.dilation) as i64; if idx >= 0 { for c_in in 0..self.channels_in { sum += self.weights[c_out][c_in * self.kernel_size + k] * input[c_in][idx as usize]; } } }
output[c_out][t] = sum; } }
output }}2. Вентильная активация
pub fn gated_activation(filter: &[f64], gate: &[f64]) -> Vec<f64> { filter.iter() .zip(gate.iter()) .map(|(f, g)| f.tanh() * sigmoid(*g)) .collect()}
fn sigmoid(x: f64) -> f64 { 1.0 / (1.0 + (-x).exp())}3. Блок WaveNet
pub struct WaveNetBlock { filter_conv: DilatedConv1D, gate_conv: DilatedConv1D, residual_conv: Conv1D, skip_conv: Conv1D,}
impl WaveNetBlock { pub fn forward(&self, input: &[Vec<f64>]) -> (Vec<Vec<f64>>, Vec<Vec<f64>>) { // Расширенные свёртки let filter = self.filter_conv.forward(input); let gate = self.gate_conv.forward(input);
// Вентильная активация let activated: Vec<Vec<f64>> = filter.iter() .zip(gate.iter()) .map(|(f, g)| gated_activation(f, g)) .collect();
// Остаточное соединение let residual = self.residual_conv.forward(&activated); let residual_out: Vec<Vec<f64>> = input.iter() .zip(residual.iter()) .map(|(i, r)| i.iter().zip(r.iter()).map(|(a, b)| a + b).collect()) .collect();
// Skip-соединение let skip = self.skip_conv.forward(&activated);
(residual_out, skip) }}Торговая стратегия
Генерация сигналов
Выходы модели WaveNet преобразуются в торговые сигналы:
-
Стратегия на основе регрессии
pub fn generate_signal(predicted_return: f64, threshold: f64) -> Signal {if predicted_return > threshold {Signal::Buy} else if predicted_return < -threshold {Signal::Sell} else {Signal::Hold}} -
Стратегия на основе классификации
pub fn generate_signal(probabilities: [f64; 3]) -> Signal {let (max_idx, _) = probabilities.iter().enumerate().max_by(|a, b| a.1.partial_cmp(b.1).unwrap()).unwrap();match max_idx {0 => Signal::Sell,1 => Signal::Hold,2 => Signal::Buy,_ => unreachable!()}}
Расчёт размера позиции
Использование размера позиции, скорректированного на волатильность:
pub fn calculate_position_size( capital: f64, volatility: f64, risk_per_trade: f64, max_position: f64,) -> f64 { let vol_adjusted = risk_per_trade / volatility; (capital * vol_adjusted).min(capital * max_position)}Управление рисками
- Стоп-лосс: Динамический, основанный на ATR (Average True Range)
- Тейк-профит: Соотношение риск/прибыль 1:2 или 1:3
- Максимальная просадка: Сокращение позиции при просадке 10%
Результаты бэктестинга
Метрики производительности
| Метрика | Значение |
|---|---|
| Общая доходность | - |
| Коэффициент Шарпа | - |
| Коэффициент Сортино | - |
| Максимальная просадка | - |
| Процент выигрышей | - |
| Профит-фактор | - |
Примечание: Запустите примеры бэктестинга, чтобы увидеть реальные результаты с текущими данными.
Запуск бэктестов
# Получение данных с Bybitcargo run --bin fetch_data -- --symbol BTCUSDT --interval 1h --days 365
# Обучение модели WaveNetcargo run --bin train_wavenet -- --data ./data/BTCUSDT_1h.csv --epochs 100
# Запуск бэктестаcargo run --bin backtest -- --model ./models/wavenet.bin --data ./data/BTCUSDT_1h.csvПреимущества и ограничения
Преимущества
- Параллелизуемое обучение: В отличие от RNN, может обрабатывать все временные шаги одновременно
- Большое рецептивное поле: Эффективно захватывает долгосрочные паттерны
- Нет затухания градиентов: Благодаря остаточным соединениям
- Гибкая архитектура: Легко настраивать глубину и рецептивное поле
Ограничения
- Требовательность к памяти: Хранит все промежуточные активации
- Фиксированное рецептивное поле: Невозможно динамически настроить lookback
- Скорость вывода: Полная свёртка необходима для каждого прогноза
- Нет внимания: Не может фокусироваться на конкретных исторических событиях
Когда использовать WaveNet
✅ Подходит для:
- Захвата циклических паттернов (часовых, дневных, недельных)
- Рынков с сильным моментумом/возвратом к среднему
- Когда важна параллелизация
❌ Не идеален для:
- Очень длинных последовательностей (>10,000 временных шагов)
- Когда важно внимание к конкретным событиям
- Ограниченных вычислительных ресурсов
Ссылки
Научные статьи
-
van den Oord, A., et al. (2016) - “WaveNet: A Generative Model for Raw Audio”
-
Borovykh, A., Bohte, S., & Oosterlee, C. W. (2017) - “Conditional Time Series Forecasting with Convolutional Neural Networks”
-
Chen, W., et al. (2020) - “WaveNet-based Deep Learning for Financial Time Series”
- Применение к прогнозированию цен акций
Связанные архитектуры
- Temporal Convolutional Networks (TCN): Упрощённый WaveNet для моделирования последовательностей
- Temporal Fusion Transformers: Комбинация внимания с временными паттернами
- N-BEATS: Интерпретируемое прогнозирование временных рядов
Использование
Предварительные требования
- Rust 1.70+
- Подключение к интернету для Bybit API
Быстрый старт
cd 351_wavenet_trading/rust
# Сборка проектаcargo build --release
# Получение данныхcargo run --bin fetch_data -- --symbol BTCUSDT --interval 1h --days 30
# Обучение модели (демо)cargo run --bin train_wavenet
# Генерация прогнозовcargo run --bin predict
# Запуск бэктестаcargo run --bin backtestСтруктура файлов
| Файл | Описание |
|---|---|
README.md | Основная документация на английском |
README.ru.md | Этот файл - русская версия |
readme.simple.md | Простое объяснение для начинающих |
readme.simple.ru.md | Простое объяснение на русском |
rust/ | Реализация на Rust |
WaveNet привносит мощь расширенных причинных свёрток в финансовые временные ряды, предлагая уникальное сочетание распознавания долгосрочных паттернов и вычислительной эффективности.