Обучение ML-модели предсказания цены криптовалют
Предсказание цен криптовалют с помощью машинного обучения — одна из наиболее сложных задач в quant finance. Рынок адаптивен: паттерн, который работал вчера, завтра может быть арбитражирован в ноль. Тем не менее, грамотно построенные модели дают статистическое преимущество на горизонте нескольких часов.
Постановка задачи
Регрессия vs классификация: предсказать точную цену (регрессия) значительно сложнее, чем предсказать направление движения (классификация). Для торговых целей чаще используется классификация: «цена вырастет на >0.5% за следующие 4h или нет?»
Временной горизонт: чем короче горизонт — тем больше сигнала теряется в шуме. Типичные горизонты: 1h, 4h, 24h. Для HFT — минуты, но там нужны другие подходы.
Target engineering: правильный таргет критичен:
- Forward return: (price[t+n] - price[t]) / price[t]
- Binary direction: sign(forward_return)
- Tercile classification: buy (top 33%), hold, sell (bottom 33%)
Feature Engineering
Качество features определяет качество модели. Для крипто price prediction:
Price-based features:
import pandas as pd
import numpy as np
import talib
def create_price_features(df):
features = pd.DataFrame(index=df.index)
# Возвраты за разные периоды
for period in [1, 4, 12, 24, 48, 168]:
features[f'return_{period}h'] = df['close'].pct_change(period)
# Технические индикаторы
features['rsi_14'] = talib.RSI(df['close'], timeperiod=14)
features['macd'], features['macd_signal'], _ = talib.MACD(df['close'])
features['bb_upper'], features['bb_mid'], features['bb_lower'] = talib.BBANDS(df['close'])
features['bb_width'] = (features['bb_upper'] - features['bb_lower']) / features['bb_mid']
features['bb_position'] = (df['close'] - features['bb_lower']) / (features['bb_upper'] - features['bb_lower'])
# Объёмные features
features['volume_ratio'] = df['volume'] / df['volume'].rolling(24).mean()
features['volume_trend'] = df['volume'].rolling(12).mean() / df['volume'].rolling(48).mean()
# Волатильность
for window in [12, 24, 72]:
log_returns = np.log(df['close']).diff()
features[f'volatility_{window}h'] = log_returns.rolling(window).std()
return features
On-chain features (для BTC/ETH):
- Exchange inflow/outflow
- Active addresses
- Hash rate (для PoW)
- Network Value to Transactions (NVT) ratio
- SOPR, NUPL
Market microstructure features:
- Bid-ask spread
- Order book imbalance (если есть доступ к depth данным)
- Funding rate (для perpetual futures)
- Open interest изменение
Cross-asset features:
- BTC dominance
- Corr с SP500 (rolling 30d)
- DXY изменение
- Gold returns
Модели и их сравнение
LightGBM / XGBoost — baseline для tabular данных. Быстрое обучение, интерпретируемость через SHAP, не требует нормализации.
import lightgbm as lgb
from sklearn.model_selection import TimeSeriesSplit
def train_lightgbm(X, y, n_splits=5):
tscv = TimeSeriesSplit(n_splits=n_splits)
models = []
params = {
'objective': 'binary',
'metric': 'auc',
'num_leaves': 31,
'learning_rate': 0.05,
'feature_fraction': 0.8,
'bagging_fraction': 0.8,
'bagging_freq': 5,
'min_child_samples': 20,
'reg_alpha': 0.1,
'reg_lambda': 0.1
}
for fold, (train_idx, val_idx) in enumerate(tscv.split(X)):
X_train, X_val = X.iloc[train_idx], X.iloc[val_idx]
y_train, y_val = y.iloc[train_idx], y.iloc[val_idx]
dtrain = lgb.Dataset(X_train, y_train)
dval = lgb.Dataset(X_val, y_val)
model = lgb.train(
params,
dtrain,
num_boost_round=1000,
valid_sets=[dval],
callbacks=[lgb.early_stopping(50), lgb.log_evaluation(100)]
)
models.append(model)
return models
Random Forest — менее склонен к переобучению, хорошо для ансамблей.
Linear models (Ridge/Logistic Regression) — полезны как baseline и компонент стекинга.
LSTM / GRU / Transformer — последовательные модели, учитывают temporal patterns. Обсуждаются в отдельных сервисах.
Критические аспекты обучения
Look-ahead bias: главная ловушка при обучении на финансовых данных. Features должны быть рассчитаны только из информации, доступной в момент t.
# НЕПРАВИЛЬНО - look-ahead
df['normalized_price'] = (df['close'] - df['close'].mean()) / df['close'].std()
# ПРАВИЛЬНО - expanding window
df['normalized_price'] = (
df['close'] - df['close'].expanding().mean()
) / df['close'].expanding().std()
Walk-forward validation: обязательна для временных рядов. Нельзя использовать random split.
Период 1: обучение 2020–2021, тест Q1 2022
Период 2: обучение 2020–Q1 2022, тест Q2 2022
...
Purging и embargoing: при перекрывающихся labels нужно "очищать" train set от samples, пересекающихся с validation периодом.
Feature Selection и dimensionality reduction
SHAP values для интерпретации важности features:
import shap
explainer = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_val)
shap.summary_plot(shap_values, X_val)
Correlation filtering: удаляем features с корреляцией > 0.95 (избыточны).
Variance Inflation Factor (VIF): выявляем мультиколлинеарность.
Production deployment
Model serving: FastAPI endpoint, который принимает текущие OHLCV данные, формирует features и возвращает предсказание (probability + signal).
Prediction pipeline:
Raw OHLCV → Feature Engineering → Preprocessing (scaler) → Model → Signal
Model registry: MLflow для хранения версий модели, параметров обучения, метрик.
Monitoring: отслеживаем distribution features (feature drift) и качество предсказаний (model performance degradation).
Разрабатываем полный pipeline: feature engineering, обучение нескольких моделей, walk-forward validation, SHAP интерпретация, production API для realtime предсказаний и MLflow tracking.







