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

Глава 351: WaveNet для Трейдинга

Обзор

WaveNet - это глубокая генеративная модель, изначально разработанная DeepMind для генерации сырого аудио. Её ключевая инновация - расширенные причинные свёртки (dilated causal convolutions) - делает её исключительно подходящей для прогнозирования финансовых временных рядов. В этой главе мы рассмотрим, как адаптировать архитектуру WaveNet для торговли криптовалютами с использованием данных биржи Bybit.

Содержание

  1. Введение
  2. Архитектура WaveNet
  3. Расширенные причинные свёртки
  4. Адаптация WaveNet для трейдинга
  5. Реализация
  6. Торговая стратегия
  7. Результаты бэктестинга
  8. Ссылки

Введение

Почему WaveNet для трейдинга?

Традиционные рекуррентные нейронные сети (RNN, LSTM, GRU) обрабатывают последовательности пошагово, что приводит к:

  • Медленным вычислениям
  • Сложностям с параллелизацией
  • Затуханию градиентов для длинных последовательностей

WaveNet решает эти проблемы с помощью расширенных причинных свёрток:

  • Параллельная обработка последовательностей (быстрое обучение)
  • Эффективный захват долгосрочных зависимостей
  • Сохранение причинности (нет утечки информации из будущего)

Ключевые концепции

КонцепцияОписание
Причинная свёрткаСвёртка, которая смотрит только на прошлые данные
Расширенная свёрткаСвёртка с пропусками между входами
Рецептивное полеКак далеко в прошлое может “видеть” сеть
Skip-соединенияПрямые пути для многомасштабного извлечения признаков
Остаточные соединенияПомогают потоку градиентов в глубоких сетях

Архитектура WaveNet

Оригинальная архитектура

Вход → Причинная Conv → [Расширенный Conv Блок] × N → Skip-соединения → Выход
Вентильная активация
(tanh ⊗ sigmoid)

Основные компоненты

  1. Причинный свёрточный слой

    • Обеспечивает отсутствие утечки информации из будущего
    • Первый слой, обрабатывающий сырой вход
  2. Блоки расширенных свёрток

    • Несколько слоёв с возрастающими коэффициентами расширения
    • Экспоненциально растущее рецептивное поле: 1, 2, 4, 8, 16, 32…
  3. Вентильные функции активации

    z = tanh(Wf * x) ⊙ sigmoid(Wg * x)
    • Wf: веса фильтра (что изучать)
    • Wg: веса ворот (что забывать)
  4. 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 для трейдинга

Модификации для финансовых временных рядов

  1. Входные признаки

    • OHLCV данные (Open, High, Low, Close, Volume)
    • Технические индикаторы (RSI, MACD, полосы Боллинджера)
    • Признаки микроструктуры рынка
  2. Выходные головы

    • Регрессия: прогноз следующей цены/доходности
    • Классификация: прогноз направления (вверх/вниз/нейтрально)
    • Вероятностный: прогноз параметров распределения
  3. Функции потерь

    • 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 преобразуются в торговые сигналы:

  1. Стратегия на основе регрессии

    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
    }
    }
  2. Стратегия на основе классификации

    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%

Результаты бэктестинга

Метрики производительности

МетрикаЗначение
Общая доходность-
Коэффициент Шарпа-
Коэффициент Сортино-
Максимальная просадка-
Процент выигрышей-
Профит-фактор-

Примечание: Запустите примеры бэктестинга, чтобы увидеть реальные результаты с текущими данными.

Запуск бэктестов

Окно терминала
# Получение данных с Bybit
cargo run --bin fetch_data -- --symbol BTCUSDT --interval 1h --days 365
# Обучение модели WaveNet
cargo run --bin train_wavenet -- --data ./data/BTCUSDT_1h.csv --epochs 100
# Запуск бэктеста
cargo run --bin backtest -- --model ./models/wavenet.bin --data ./data/BTCUSDT_1h.csv

Преимущества и ограничения

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

  1. Параллелизуемое обучение: В отличие от RNN, может обрабатывать все временные шаги одновременно
  2. Большое рецептивное поле: Эффективно захватывает долгосрочные паттерны
  3. Нет затухания градиентов: Благодаря остаточным соединениям
  4. Гибкая архитектура: Легко настраивать глубину и рецептивное поле

Ограничения

  1. Требовательность к памяти: Хранит все промежуточные активации
  2. Фиксированное рецептивное поле: Невозможно динамически настроить lookback
  3. Скорость вывода: Полная свёртка необходима для каждого прогноза
  4. Нет внимания: Не может фокусироваться на конкретных исторических событиях

Когда использовать WaveNet

Подходит для:

  • Захвата циклических паттернов (часовых, дневных, недельных)
  • Рынков с сильным моментумом/возвратом к среднему
  • Когда важна параллелизация

Не идеален для:

  • Очень длинных последовательностей (>10,000 временных шагов)
  • Когда важно внимание к конкретным событиям
  • Ограниченных вычислительных ресурсов

Ссылки

Научные статьи

  1. van den Oord, A., et al. (2016) - “WaveNet: A Generative Model for Raw Audio”

  2. Borovykh, A., Bohte, S., & Oosterlee, C. W. (2017) - “Conditional Time Series Forecasting with Convolutional Neural Networks”

  3. 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 привносит мощь расширенных причинных свёрток в финансовые временные ряды, предлагая уникальное сочетание распознавания долгосрочных паттернов и вычислительной эффективности.