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

Глава 83: Прототипные сети для финансов

Обзор

Прототипные сети (Prototypical Networks) - это подход мета-обучения, разработанный для задач классификации с малым количеством примеров (few-shot). На финансовых рынках они отлично справляются с классификацией рыночных режимов, обнаружением торговых паттернов и адаптацией к новым рыночным условиям при минимальном количестве размеченных данных. Это особенно ценно на крипторынках, где режимы могут быстро меняться, а исторические паттерны имеют ограниченное количество примеров.

Содержание

  1. Введение
  2. Теоретические основы
  3. Компоненты архитектуры
  4. Применение на финансовых рынках
  5. Few-Shot классификация рыночных режимов
  6. Стратегия реализации
  7. Интеграция с Bybit
  8. Управление рисками
  9. Метрики производительности
  10. Ссылки

Введение

Традиционные подходы машинного обучения для трейдинга требуют большого количества размеченных данных для каждого рыночного режима или паттерна. Однако финансовые рынки представляют уникальные вызовы:

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

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

┌─────────────────────────────────────────────────────────────────────────┐
│ Проблема Few-Shot в трейдинге │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ Традиционное ML: Прототипные сети: │
│ ──────────────── ──────────────── │
│ Нужны 1000+ примеров Нужно только 5-20 примеров │
│ каждого паттерна на паттерн (support set) │
│ │
│ Проблема: Редкие события Решение: Учимся вычислять │
│ типа флэш-крэшей имеют "прототипы" из малого числа │
│ мало исторических примеров примеров и классифицировать │
│ │
│ ┌────────────┐ ┌────────────┐ │
│ │ Бычий рынок│ 1000 примеров │ Бычий рынок│ 10 примеров │
│ │ Медвежий │ 1000 примеров │ Медвежий │ 10 примеров │
│ │ Обвал │ 12 примеров ❌ │ Обвал │ 5 примеров ✓ │
│ │ Сквиз │ 8 примеров ❌ │ Сквиз │ 5 примеров ✓ │
│ └────────────┘ └────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘

Ключевые преимущества

АспектТрадиционное MLПрототипные сети
Требования к даннымВысокие (1000+ на класс)Низкие (5-20 на класс)
Адаптация к новым паттернамТребует переобученияДостаточно нескольких примеров
Обработка редких событийПлохоОтлично
Вычислительные затратыВысокие при переобученииНизкие при адаптации
ИнтерпретируемостьНизкая (чёрный ящик)Высокая (расстояния до прототипов)

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

Фреймворк прототипных сетей

Прототипная сеть изучает метрическое пространство, где классификация выполняется путём вычисления расстояний до прототипов классов (центроидов).

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

Функция эмбеддинга: $f_\phi: \mathbb{R}^D \rightarrow \mathbb{R}^M$

Отображает входные данные в M-мерное пространство эмбеддингов через нейронную сеть с параметрами $\phi$.

Вычисление прототипа: Для support set $S_k$ примеров класса $k$:

$$c_k = \frac{1}{|S_k|} \sum_{(x_i, y_i) \in S_k} f_\phi(x_i)$$

где $c_k$ - прототип (центроид) класса $k$.

Классификация: Для query точки $x$ вычисляем распределение вероятностей по классам:

$$p(y = k | x) = \frac{\exp(-d(f_\phi(x), c_k))}{\sum_{k’} \exp(-d(f_\phi(x), c_{k’}))}$$

где $d$ - функция расстояния (обычно квадрат евклидова расстояния).

Обучение через эпизоды

┌────────────────────────────────────────────────────────────────────────┐
│ Процесс эпизодического обучения │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Эпизод = Одна итерация обучения, симулирующая few-shot сценарий │
│ │
│ Шаг 1: Выбираем N классов (напр., 5 рыночных режимов) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Бычий │ Медвежий │ Боковик │ Обвал │ Восстановление │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Шаг 2: Для каждого класса выбираем K support + Q query примеров │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Бычий: [s1, s2, s3, s4, s5] | [q1, q2, q3] │ │
│ │ Медвежий: [s1, s2, s3, s4, s5] | [q1, q2, q3] │ │
│ │ ... │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ Support Set (5-shot) Query Set │
│ │
│ Шаг 3: Вычисляем прототипы из support set │
│ Шаг 4: Классифицируем query примеры по расстояниям до прототипов │
│ Шаг 5: Вычисляем loss и делаем обратное распространение │
│ │
└────────────────────────────────────────────────────────────────────────┘

N-way K-shot классификация

  • N-way: Количество классов для различения
  • K-shot: Количество примеров на класс в support set

Для трейдинга: обычно 3-5 way (режимов) с 5-10 shot (примеров на режим)

Функции расстояния

Квадрат евклидова расстояния (по умолчанию): $$d(x, y) = |x - y|^2 = \sum_i (x_i - y_i)^2$$

Косинусное расстояние (альтернатива): $$d(x, y) = 1 - \frac{x \cdot y}{|x| |y|}$$

Расстояние Махаланобиса (учитывает ковариацию): $$d(x, y) = \sqrt{(x-y)^T \Sigma^{-1} (x-y)}$$

Компоненты архитектуры

Архитектура сети эмбеддинга

┌────────────────────────────────────────────────────────────────────────┐
│ Сеть эмбеддинга для трейдинга │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Вход: Рыночные признаки [цена, объём, волатильность, ...] │
│ Форма: (batch_size, sequence_length, feature_dim) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Блок временных свёрток │ │
│ │ ───────────────────────── │ │
│ │ Conv1D(in=features, out=64, kernel=3) → BatchNorm → ReLU │ │
│ │ Conv1D(in=64, out=128, kernel=3) → BatchNorm → ReLU │ │
│ │ Conv1D(in=128, out=128, kernel=3) → BatchNorm → ReLU │ │
│ │ MaxPool1D(kernel=2) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Блок LSTM/Transformer │ │
│ │ ───────────────────── │ │
│ │ LSTM(hidden=256, layers=2, bidirectional=True) │ │
│ │ ИЛИ │ │
│ │ TransformerEncoder(d_model=256, nhead=8, layers=2) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ Голова проекции │ │
│ │ ─────────────── │ │
│ │ Linear(in=256, out=128) → ReLU │ │
│ │ Linear(in=128, out=embedding_dim) │ │
│ │ L2 нормализация (опционально) │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ Выход: Вектор эмбеддинга формы (batch_size, embedding_dim) │
│ │
└────────────────────────────────────────────────────────────────────────┘

Инженерия признаков для трейдинга

┌────────────────────────────────────────────────────────────────────────┐
│ Входные признаки для рыночного режима │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Ценовые признаки: │
│ • Доходности (1м, 5м, 15м, 1ч, 4ч, 24ч) │
│ • Логарифмические доходности │
│ • Диапазон high-low │
│ • Позиция close в диапазоне │
│ │
│ Объёмные признаки: │
│ • Объём (нормализованный) │
│ • Изменение объёма │
│ • Соотношение Buy/Sell объёма │
│ • Профиль объёма │
│ │
│ Признаки волатильности: │
│ • Скользящая волатильность (несколько окон) │
│ • ATR (Average True Range) │
│ • Ширина полос Боллинджера │
│ • Волатильность Паркинсона │
│ │
│ Признаки структуры рынка: │
│ • RSI, MACD, Стохастик │
│ • Соотношения скользящих средних │
│ • Уровни поддержки/сопротивления │
│ • Дисбаланс ордербука │
│ │
│ Крипто-специфичные признаки: │
│ • Ставка финансирования (funding rate) │
│ • Открытый интерес (OI) │
│ • Соотношение Long/Short │
│ • Уровни ликвидаций │
│ │
└────────────────────────────────────────────────────────────────────────┘

Модуль вычисления прототипов

/// Вычисление прототипов из эмбеддингов support set
pub struct PrototypeComputer {
/// Тип функции расстояния
distance_type: DistanceType,
/// Опциональное уточнение прототипов
refine_prototypes: bool,
}
impl PrototypeComputer {
/// Вычислить прототипы классов из support эмбеддингов
pub fn compute_prototypes(
&self,
support_embeddings: &Array2<f32>, // (n_support, embed_dim)
support_labels: &Array1<usize>, // (n_support,)
n_classes: usize,
) -> Array2<f32> { // (n_classes, embed_dim)
let embed_dim = support_embeddings.ncols();
let mut prototypes = Array2::zeros((n_classes, embed_dim));
let mut counts = vec![0usize; n_classes];
// Суммируем эмбеддинги по классам
for (i, &label) in support_labels.iter().enumerate() {
prototypes.row_mut(label).add_assign(&support_embeddings.row(i));
counts[label] += 1;
}
// Усредняем для получения прототипов
for (class_idx, count) in counts.iter().enumerate() {
if *count > 0 {
prototypes.row_mut(class_idx).mapv_inplace(|x| x / *count as f32);
}
}
prototypes
}
/// Классифицировать query точки по расстояниям до прототипов
pub fn classify(
&self,
query_embeddings: &Array2<f32>, // (n_query, embed_dim)
prototypes: &Array2<f32>, // (n_classes, embed_dim)
) -> (Array1<usize>, Array2<f32>) { // (предсказания, вероятности)
let n_query = query_embeddings.nrows();
let n_classes = prototypes.nrows();
// Вычисляем расстояния до всех прототипов
let mut distances = Array2::zeros((n_query, n_classes));
for i in 0..n_query {
for j in 0..n_classes {
distances[[i, j]] = self.compute_distance(
&query_embeddings.row(i),
&prototypes.row(j),
);
}
}
// Преобразуем в вероятности через softmax от отрицательных расстояний
let neg_distances = -&distances;
let probabilities = softmax(&neg_distances);
// Получаем предсказания (argmax)
let predictions = probabilities
.outer_iter()
.map(|row| row.iter()
.enumerate()
.max_by(|a, b| a.1.partial_cmp(b.1).unwrap())
.unwrap().0)
.collect();
(Array1::from_vec(predictions), probabilities)
}
}

Применение на финансовых рынках

Классификация рыночных режимов

┌────────────────────────────────────────────────────────────────────────┐
│ Классы рыночных режимов │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Класс 0: СИЛЬНЫЙ_ВОСХОДЯЩИЙ_ТРЕНД │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Характеристики: │ │
│ │ • Устойчивые положительные доходности (>2% в день в ср.) │ │
│ │ • Растущие максимумы, растущие минимумы │ │
│ │ • Объём подтверждает движения │ │
│ │ • Положительная ставка финансирования │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ Класс 1: СЛАБЫЙ_ВОСХОДЯЩИЙ_ТРЕНД │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Характеристики: │ │
│ │ • Умеренные положительные доходности (0.5-2% в день) │ │
│ │ • Волатильное движение с восходящим уклоном │ │
│ │ • Смешанные сигналы по объёму │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ Класс 2: БОКОВИК / КОНСОЛИДАЦИЯ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Характеристики: │ │
│ │ • Доходности около нуля │ │
│ │ • Цена отскакивает между поддержкой/сопротивлением │ │
│ │ • Снижающаяся волатильность │ │
│ │ • Низкий объём │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ Класс 3: СЛАБЫЙ_НИСХОДЯЩИЙ_ТРЕНД │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Характеристики: │ │
│ │ • Умеренные отрицательные доходности (-0.5 до -2%) │ │
│ │ • Формируется паттерн снижающихся максимумов │ │
│ │ • Отрицательная ставка финансирования │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
│ Класс 4: СИЛЬНЫЙ_НИСХОДЯЩИЙ_ТРЕНД / ОБВАЛ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ Характеристики: │ │
│ │ • Резкие отрицательные доходности (<-2% в день) │ │
│ │ • Всплеск волатильности │ │
│ │ • Высокий объём на падениях │ │
│ │ • Каскады ликвидаций │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────┘

Торговая стратегия на основе режимов

┌────────────────────────────────────────────────────────────────────────┐
│ Торговые сигналы по режимам │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Пайплайн определения режима: │
│ ──────────────────────────── │
│ 1. Собрать последние рыночные данные (напр., за 24 часа) │
│ 2. Извлечь признаки для текущего окна │
│ 3. Получить эмбеддинг через обученную сеть │
│ 4. Вычислить расстояния до прототипов режимов │
│ 5. Классифицировать текущий режим с уверенностью │
│ 6. Сгенерировать торговый сигнал на основе режима │
│ │
│ Маппинг Режим → Сигнал: │
│ ┌─────────────────┬──────────────────────────────────────────┐ │
│ │ Режим │ Действие │ │
│ ├─────────────────┼──────────────────────────────────────────┤ │
│ │ СИЛЬНЫЙ_ВВЕРХ │ Лонг с трейлинг-стопом, докупать на │ │
│ │ │ просадках │ │
│ │ СЛАБЫЙ_ВВЕРХ │ Лёгкий лонг, жёсткие стопы │ │
│ │ БОКОВИК │ Mean reversion, торговля в диапазоне │ │
│ │ СЛАБЫЙ_ВНИЗ │ Лёгкий шорт или оставаться вне рынка │ │
│ │ СИЛЬНЫЙ_ВНИЗ │ Шорт с защитой, хеджировать лонги │ │
│ └─────────────────┴──────────────────────────────────────────┘ │
│ │
│ Размер позиции по уверенности: │
│ ────────────────────────────── │
│ размер_позиции = базовый_размер × уверенность_классификации │
│ │
│ Если уверенность < 0.6: Уменьшить позицию или не торговать │
│ Если уверенность > 0.8: Полный размер позиции │
│ │
└────────────────────────────────────────────────────────────────────────┘

Few-Shot классификация рыночных режимов

Генерация эпизодов для обучения

# Псевдокод генерации эпизода
def generate_episode(dataset, n_way=5, k_shot=5, n_query=10):
"""
Генерация одного обучающего эпизода для прототипной сети.
Args:
dataset: Исторические рыночные данные с метками режимов
n_way: Количество классов режимов в эпизоде
k_shot: Количество support примеров на класс
n_query: Количество query примеров на класс
Returns:
support_set: тензор (n_way * k_shot, features)
support_labels: тензор (n_way * k_shot,)
query_set: тензор (n_way * n_query, features)
query_labels: тензор (n_way * n_query,)
"""
# Выбираем n_way классов из доступных классов режимов
available_classes = dataset.get_regime_classes()
sampled_classes = random.sample(available_classes, n_way)
support_set = []
support_labels = []
query_set = []
query_labels = []
for class_idx, regime_class in enumerate(sampled_classes):
# Получаем все примеры для этого режима
class_samples = dataset.get_samples_for_regime(regime_class)
# Выбираем k_shot + n_query примеров
sampled_indices = random.sample(
range(len(class_samples)),
k_shot + n_query
)
# Разделяем на support и query
support_indices = sampled_indices[:k_shot]
query_indices = sampled_indices[k_shot:]
support_set.extend([class_samples[i] for i in support_indices])
support_labels.extend([class_idx] * k_shot)
query_set.extend([class_samples[i] for i in query_indices])
query_labels.extend([class_idx] * n_query)
return (
torch.stack(support_set),
torch.tensor(support_labels),
torch.stack(query_set),
torch.tensor(query_labels)
)

Стратегии разметки режимов

┌────────────────────────────────────────────────────────────────────────┐
│ Автоматическая разметка режимов │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ Метод 1: Квантили по доходностям │
│ ─────────────────────────────── │
│ Разметка по кумулятивной доходности за окно: │
│ • Топ 20%: СИЛЬНЫЙ_ВОСХОДЯЩИЙ │
│ • 20-40%: СЛАБЫЙ_ВОСХОДЯЩИЙ │
│ • 40-60%: БОКОВИК │
│ • 60-80%: СЛАБЫЙ_НИСХОДЯЩИЙ │
│ • Нижние 20%: СИЛЬНЫЙ_НИСХОДЯЩИЙ │
│ │
│ Метод 2: Доходность с поправкой на волатильность │
│ ─────────────────────────────────────────────── │
│ risk_adjusted_return = return / volatility │
│ Разметка по порогам с поправкой на риск │
│ │
│ Метод 3: Скрытая марковская модель (HMM) │
│ ──────────────────────────────────────── │
│ Обучаем HMM для обнаружения латентных режимов │
│ Используем состояния HMM как метки │
│ │
│ Метод 4: На основе кластеризации │
│ ───────────────────────────────── │
│ Извлекаем признаки → K-means → Кластеры как режимы │
│ │
│ Метод 5: Ручная экспертная разметка (Золотой стандарт) │
│ ─────────────────────────────────────────────────── │
│ Эксперты размечают ключевые периоды рынка │
│ Используется для валидации и примеров редких событий │
│ │
└────────────────────────────────────────────────────────────────────────┘

Обработка дисбаланса классов

Финансовые рынки естественно имеют несбалансированное распределение режимов:

  • Бычий/Медвежий рынки: Часто
  • Обвалы: Редко, но критически важны
Стратегии для несбалансированного Few-Shot обучения:
1. Взвешенное вычисление прототипов
- Даём больше веса примерам редких классов
- prototype_k = weighted_mean(support_k, weights)
2. Генерация синтетических примеров
- Генерируем синтетические примеры обвалов/сквизов
- Используем аугментацию данных для редких режимов
3. Стратегия семплирования эпизодов
- Чаще семплируем эпизоды с редкими классами
- Обеспечиваем равное появление всех классов
4. Масштабирование расстояний
- Масштабируем расстояния обратно пропорционально частоте класса
- Редкие классы имеют меньшие расстояния (легче классифицировать)

Стратегия реализации

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

83_prototypical_networks_finance/
├── Cargo.toml
├── README.md
├── README.ru.md
├── readme.simple.md
├── readme.simple.ru.md
├── src/
│ ├── lib.rs # Корень библиотеки
│ ├── network/
│ │ ├── mod.rs # Модуль сети
│ │ ├── embedding.rs # Сеть эмбеддинга
│ │ ├── prototype.rs # Вычисление прототипов
│ │ └── distance.rs # Функции расстояния
│ ├── training/
│ │ ├── mod.rs # Модуль обучения
│ │ ├── episode.rs # Генерация эпизодов
│ │ ├── trainer.rs # Цикл обучения
│ │ └── scheduler.rs # Планирование learning rate
│ ├── data/
│ │ ├── mod.rs # Модуль данных
│ │ ├── bybit.rs # Клиент API Bybit
│ │ ├── features.rs # Инженерия признаков
│ │ ├── regime.rs # Разметка режимов
│ │ └── types.rs # Типы данных
│ ├── strategy/
│ │ ├── mod.rs # Модуль стратегии
│ │ ├── classifier.rs # Классификатор режимов
│ │ ├── signals.rs # Генерация сигналов
│ │ └── execution.rs # Исполнение ордеров
│ └── utils/
│ ├── mod.rs # Утилиты
│ └── metrics.rs # Метрики производительности
├── examples/
│ ├── basic_prototypical.rs # Базовый пример
│ ├── regime_trading.rs # Торговля по режимам
│ └── backtest.rs # Бэктестинг
├── python/
│ ├── prototypical_network.py # Реализация на PyTorch
│ ├── train.py # Скрипт обучения
│ └── notebooks/
│ └── example.ipynb # Jupyter notebook пример
└── tests/
└── integration.rs # Интеграционные тесты

Ключевые принципы проектирования

  1. Модульность: Каждый компонент (эмбеддинг, прототип, расстояние) независим
  2. Типобезопасность: Использование системы типов Rust для целостности финансовых данных
  3. Производительность: Эффективные batch-операции для инференса в реальном времени
  4. Гибкость: Поддержка разных функций расстояния и архитектур эмбеддинга
  5. Тестируемость: Полное покрытие unit и интеграционными тестами

Основные типы в Rust

/// Перечисление рыночных режимов
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MarketRegime {
StrongUptrend, // Сильный восходящий тренд
WeakUptrend, // Слабый восходящий тренд
Sideways, // Боковик
WeakDowntrend, // Слабый нисходящий тренд
StrongDowntrend, // Сильный нисходящий тренд
}
impl MarketRegime {
/// Получить торговый уклон для этого режима
pub fn trading_bias(&self) -> TradingBias {
match self {
Self::StrongUptrend => TradingBias::StrongLong,
Self::WeakUptrend => TradingBias::WeakLong,
Self::Sideways => TradingBias::Neutral,
Self::WeakDowntrend => TradingBias::WeakShort,
Self::StrongDowntrend => TradingBias::StrongShort,
}
}
}
/// Типы функций расстояния
#[derive(Debug, Clone, Copy)]
pub enum DistanceType {
Euclidean, // Евклидово
SquaredEuclidean, // Квадрат евклидова
Cosine, // Косинусное
Mahalanobis, // Махаланобиса
}
/// Конфигурация прототипной сети
#[derive(Debug, Clone)]
pub struct PrototypicalConfig {
/// Размерность эмбеддинга
pub embedding_dim: usize,
/// Количество классов (режимов)
pub n_classes: usize,
/// Количество shot для support set
pub k_shot: usize,
/// Количество query примеров
pub n_query: usize,
/// Тип функции расстояния
pub distance_type: DistanceType,
/// Температура для softmax
pub temperature: f32,
/// Размерность входных признаков
pub input_dim: usize,
/// Длина последовательности для временных признаков
pub sequence_length: usize,
}
impl Default for PrototypicalConfig {
fn default() -> Self {
Self {
embedding_dim: 128,
n_classes: 5,
k_shot: 5,
n_query: 15,
distance_type: DistanceType::SquaredEuclidean,
temperature: 1.0,
input_dim: 32,
sequence_length: 48, // напр., 48 часов почасовых данных
}
}
}

Интеграция с Bybit

Пайплайн сбора данных

┌────────────────────────────────────────────────────────────────────────┐
│ Пайплайн данных Bybit │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Сбор исторических данных (Обучение) │
│ ────────────────────────────────────── │
│ GET /v5/market/kline → Свечи для нескольких таймфреймов │
│ GET /v5/market/tickers → Текущее состояние рынка │
│ GET /v5/market/funding/history → Исторические funding rates │
│ GET /v5/market/open-interest → История открытого интереса │
│ │
│ 2. Данные реального времени (Инференс) │
│ ────────────────────────────────────── │
│ WebSocket подписка: │
│ • kline.{interval}.{symbol} → Свечи в реальном времени │
│ • ticker.{symbol} → Обновления цен │
│ • liquidation.{symbol} → События ликвидаций │
│ │
│ 3. Вычисление признаков │
│ ────────────────────── │
│ Сырые данные → Экстрактор признаков → Нормализованные признаки │
│ │
│ 4. Классификация режима │
│ ─────────────────────── │
│ Признаки → Сеть эмбеддинга → Расстояния до прототипов → Режим │
│ │
│ 5. Торговый сигнал │
│ ────────────────── │
│ Режим + Уверенность → Размер позиции → Отправка ордера │
│ │
└────────────────────────────────────────────────────────────────────────┘

Интеграция клиента Bybit

use crate::data::{BybitClient, Kline, FundingRate};
/// Получение и обработка данных для прототипной сети
pub async fn collect_training_data(
client: &BybitClient,
symbols: &[&str],
start_time: u64,
end_time: u64,
) -> Result<TrainingDataset, BybitError> {
let mut all_features = Vec::new();
let mut all_labels = Vec::new();
for symbol in symbols {
// Получаем свечи
let klines = client.get_klines(
symbol,
"1h",
1000 // Максимальный лимит
).await?;
// Получаем ставки финансирования
let funding = client.get_funding_rate(symbol).await?;
// Извлекаем признаки для каждого окна
for window in klines.windows(48) { // 48-часовые окна
let features = extract_features(window, &funding)?;
let label = compute_regime_label(window)?;
all_features.push(features);
all_labels.push(label);
}
}
Ok(TrainingDataset::new(all_features, all_labels))
}

Управление рисками

Контроль рисков по режимам

┌────────────────────────────────────────────────────────────────────────┐
│ Управление рисками по режимам │
├────────────────────────────────────────────────────────────────────────┤
│ │
│ СИЛЬНЫЙ_ВОСХОДЯЩИЙ: │
│ • Макс. позиция: 100% от аллокации │
│ • Стоп-лосс: 5% трейлинг │
│ • Тейк-профит: Дать прибыли расти │
│ • Плечо: До 3x │
│ │
│ СЛАБЫЙ_ВОСХОДЯЩИЙ: │
│ • Макс. позиция: 60% от аллокации │
│ • Стоп-лосс: 3% фиксированный │
│ • Тейк-профит: Цель 5-8% │
│ • Плечо: До 2x │
│ │
│ БОКОВИК: │
│ • Макс. позиция: 40% от аллокации │
│ • Стоп-лосс: 2% фиксированный │
│ • Тейк-профит: Границы диапазона │
│ • Плечо: Только 1x │
│ │
│ СЛАБЫЙ_НИСХОДЯЩИЙ: │
│ • Макс. позиция: 30% шорт или 20% хедж │
│ • Стоп-лосс: 3% фиксированный │
│ • Тейк-профит: Цель 5-8% │
│ • Плечо: До 2x │
│ │
│ СИЛЬНЫЙ_НИСХОДЯЩИЙ: │
│ • Макс. позиция: 50% шорт │
│ • Стоп-лосс: 5% трейлинг │
│ • Тейк-профит: Уровни паники │
│ • Плечо: До 3x (с осторожностью) │
│ │
└────────────────────────────────────────────────────────────────────────┘

Пороги уверенности классификации

/// Параметры риска на основе уверенности классификации
pub struct RiskParameters {
pub position_size_multiplier: f32,
pub max_leverage: f32,
pub stop_loss_pct: f32,
pub take_profit_pct: Option<f32>,
}
impl RiskParameters {
pub fn from_confidence(confidence: f32, regime: MarketRegime) -> Self {
let base = Self::base_for_regime(regime);
// Масштабируем размер позиции по уверенности
let size_mult = if confidence < 0.6 {
0.25 // Очень неуверенно - минимальная позиция
} else if confidence < 0.75 {
0.5 // Умеренно уверенно
} else if confidence < 0.9 {
0.75 // Уверенно
} else {
1.0 // Очень уверенно - полная позиция
};
Self {
position_size_multiplier: base.position_size_multiplier * size_mult,
max_leverage: base.max_leverage,
stop_loss_pct: base.stop_loss_pct,
take_profit_pct: base.take_profit_pct,
}
}
}

Автоматические выключатели

  1. Падение уверенности: Если уверенность классификации падает ниже 0.5, закрыть позиции
  2. Частая смена режимов: Если режим меняется > 3 раз за 4 часа, снизить экспозицию
  3. Всплеск расстояния: Если мин. расстояние до всех прототипов превышает порог - неизвестный режим
  4. Лимит просадки: Если просадка стратегии > 10%, приостановить торговлю

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

Метрики оценки модели

МетрикаОписаниеЦель
AccuracyОбщая точность классификации> 70%
F1-Score (macro)Сбалансированная точность по режимам> 0.65
F1-Score (crash)Обнаружение обвалов специфически> 0.80
AUC-ROCСпособность различения> 0.85
Ошибка калибровкиНадёжность уверенности< 0.10

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

МетрикаОписаниеЦель
Коэффициент ШарпаДоходность с поправкой на риск> 2.0
Коэффициент СортиноС поправкой на нисходящий риск> 2.5
Макс. просадкаНаибольшая просадка от пика< 15%
Доля выигрышейПрибыльные сделки> 55%
Profit FactorВаловая прибыль / Валовой убыток> 1.5
Задержка определения режимаВремя на обнаружение смены режима< 4 часа

Бюджет задержки

┌─────────────────────────────────────────────────┐
│ Требования к задержке │
├─────────────────────────────────────────────────┤
│ Вычисление признаков: < 10мс │
│ Forward pass эмбеддинга: < 20мс │
│ Расстояние до прототипов: < 5мс │
│ Классификация: < 5мс │
├─────────────────────────────────────────────────┤
│ Общий инференс: < 40мс │
└─────────────────────────────────────────────────┘

Ссылки

  1. Prototypical Networks for Few-shot Learning

  2. Matching Networks for One Shot Learning

  3. Meta-Learning for Semi-Supervised Few-Shot Classification

  4. Meta-Learning: A Survey

  5. Few-Shot Learning for Financial Time Series

    • Современные применения мета-обучения в трейдинге
  6. Market Regime Detection

    • Nystrup, P., et al. (2020). “Learning Hidden Markov Models with Persistent States”

Следующие шаги


Глава 83 из Machine Learning for Trading