Глава 324: Ансамблевая оценка неопределенности для трейдинга
Обзор
Ансамблевые методы предоставляют мощный фреймворк для количественной оценки неопределенности в моделях машинного обучения. В отличие от одиночных моделей, которые выдают точечные предсказания, ансамбли естественным образом улавливают неопределенность модели через разногласия между своими составляющими членами. В этой главе рассматривается, как использовать ансамблевую неопределенность для более надежных торговых решений.
Почему неопределенность важна в трейдинге
Проблема точечных предсказаний
Традиционные ML-модели выдают единственное предсказание:
Модель говорит: "Цена вырастет на 2.5%"Но это ничего не говорит нам об уверенности! Что если:
- Модель уверена на 95% → Сильный сигнал, торгуем полной позицией
- Модель уверена на 51% → Слабый сигнал, возможно пропустить или уменьшить размер
- Модель никогда не видела похожих рыночных условий → Высокая неопределенность, будьте осторожны
Торговля с учетом неопределенности
Ансамбль говорит: - Предсказание: ВВЕРХ 2.5% - Эпистемическая неопределенность: 0.8% (неопределенность модели) - Алеаторная неопределенность: 1.2% (неопределенность данных) - Общая неопределенность: 1.5% - Доверительный интервал: [1.0%, 4.0%]
Торговое решение: Умеренная уверенность → Торговать 60% размера позицииТипы неопределенности
1. Эпистемическая неопределенность (неопределенность модели)
Что она отражает: Неопределенность из-за ограниченных знаний или обучающих данных.
Характеристики:
- Может быть уменьшена с большим количеством данных
- Высокая в областях далеких от обучающего распределения
- Указывает, что модель не “знает” эту ситуацию хорошо
В контексте трейдинга:
- Новые рыночные режимы (например, первый крипто бычий рынок)
- Активы с ограниченной историей
- Необычные рыночные условия
Пример:Обучающие данные: Нормальный рынок (волатильность 15-25%)Текущий рынок: Экстремальная волатильность (80%)
Эпистемическая неопределенность: ВЫСОКАЯ→ Модель не видела такого раньше, будьте осторожны!2. Алеаторная неопределенность (неопределенность данных)
Что она отражает: Неустранимый шум, присущий данным.
Характеристики:
- Не может быть уменьшена большим количеством данных
- Представляет внутреннюю случайность
- Варьируется в пространстве входных данных
В контексте трейдинга:
- Высокая вокруг важных новостных событий
- Во время объявления отчетности
- На неликвидных рынках
Пример:Предсказание цены во время запланированного объявления FOMC
Алеаторная неопределенность: ВЫСОКАЯ→ Результат фундаментально непредсказуем, уменьшите экспозицию!3. Общая неопределенность
Общая неопределенность = sqrt(Эпистемическая² + Алеаторная²)
Или более точно:Var[Y] = E[Var[Y|X]] + Var[E[Y|X]] └─────────┘ └─────────┘ Алеаторная ЭпистемическаяАнсамблевые методы для оценки неопределенности
1. Бэггинг (Bootstrap Aggregating)
Концепция: Обучение нескольких моделей на бутстрап-выборках данных.
Исходные данные: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Бутстрап выборка 1: [1, 1, 3, 4, 4, 6, 7, 8, 8, 10] → Модель 1Бутстрап выборка 2: [2, 2, 3, 5, 5, 6, 7, 9, 9, 10] → Модель 2Бутстрап выборка 3: [1, 3, 3, 4, 5, 6, 8, 8, 9, 10] → Модель 3...Предсказание и неопределенность:
predictions = [model.predict(X) for model in ensemble]mean_prediction = np.mean(predictions)uncertainty = np.std(predictions)Преимущества:
- Простота реализации
- Естественно предоставляет оценки неопределенности
- Работает с любой базовой моделью
2. Неопределенность случайного леса
Случайные леса расширяют бэггинг с рандомизацией признаков:
┌──────────────────────────────────────────────────────────────┐│ АНСАМБЛЬ СЛУЧАЙНОГО ЛЕСА │├──────────────────────────────────────────────────────────────┤│ ││ Дерево 1 Дерево 2 Дерево 3 Дерево N ││ (Признаки: (Признаки: (Признаки: (Признаки: ││ A,C,E) B,D,F) A,B,D) C,E,F) ││ │ │ │ │ ││ v v v v ││ Пред: 1.5% Пред: 2.0% Пред: 1.8% Пред: 2.2% ││ ││ Итог: Среднее = 1.875%, Std = 0.31% (неопределенность) ││ │└──────────────────────────────────────────────────────────────┘Декомпозиция дисперсии:
# Предсказания отдельных деревьевtree_predictions = [tree.predict(X) for tree in forest.estimators_]
# Среднее предсказаниеmean_pred = np.mean(tree_predictions, axis=0)
# Общая дисперсия (эпистемическая неопределенность)total_variance = np.var(tree_predictions, axis=0)
# Для регрессии: дисперсия в листьях дает алеаторную оценкуleaf_variances = [get_leaf_variance(tree, X) for tree in forest.estimators_]aleatoric_var = np.mean(leaf_variances, axis=0)
# Эпистемическая дисперсияepistemic_var = total_variance - aleatoric_var3. Бустинг с неопределенностью
Градиентный бустинг тоже может давать неопределенность:
NGBoost (Natural Gradient Boosting):- Выдает параметры распределения, а не точечные предсказания- Каждое дерево предсказывает параметры вероятностного распределения
Стандартный GBM: predict(X) → yNGBoost: predict(X) → (μ, σ) # Среднее и стандартное отклонениеКвантильный градиентный бустинг:
# Обучаем отдельные модели для разных квантилейmodel_q10 = GradientBoostingRegressor(loss='quantile', alpha=0.10)model_q50 = GradientBoostingRegressor(loss='quantile', alpha=0.50)model_q90 = GradientBoostingRegressor(loss='quantile', alpha=0.90)
# Предсказания дают доверительный интервалlower_bound = model_q10.predict(X) # 10-й перцентильmedian = model_q50.predict(X) # Медианаupper_bound = model_q90.predict(X) # 90-й перцентиль
uncertainty = (upper_bound - lower_bound) / 24. Стекинг с неопределенностью
Стекинг объединяет разнообразные модели:
┌────────────────────────────────────────────────────────────────┐│ СТЕКИНГ АНСАМБЛЬ │├────────────────────────────────────────────────────────────────┤│ ││ Уровень 0 (Базовые модели): ││ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││ │ Случайный│ │Градиент- │ │ SVM │ │ Нейро- │ ││ │ лес │ │ бустинг │ │ │ │ сеть │ ││ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ ││ │ │ │ │ ││ └────────────┴─────┬──────┴────────────┘ ││ │ ││ Уровень 1 (Мета-модель):▼ ││ ┌────────────────────────────────────────────┐ ││ │ Мета-обучатель (комбинирует предсказания)│ ││ │ Также оценивает неопределенность из │ ││ │ разногласий базовых моделей │ ││ └────────────────────────────────────────────┘ ││ │ ││ ▼ ││ Финальное предсказание + Неопределенность ││ │└────────────────────────────────────────────────────────────────┘Неопределенность из стекинга:
base_predictions = [model.predict(X) for model in base_models]
# Неопределенность на основе разнообразияuncertainty = np.std(base_predictions, axis=0)
# Взвешенное разногласие (если есть веса моделей)weighted_variance = np.sum(weights * (base_predictions - mean_pred)**2)Out-of-Bag (OOB) неопределенность
Концепция
В бэггинге каждая бутстрап-выборка оставляет ~37% данных. Мы можем использовать эти “out-of-bag” образцы для несмещенной оценки неопределенности.
Точка данных i=5:├── НЕ в бутстрап выборке 1 (OOB) → Используем предсказание Дерева 1├── В бутстрап выборке 2 (пропускаем)├── НЕ в бутстрап выборке 3 (OOB) → Используем предсказание Дерева 3├── В бутстрап выборке 4 (пропускаем)└── НЕ в бутстрап выборке 5 (OOB) → Используем предсказание Дерева 5
OOB Предсказание для i=5: mean(Дерево1, Дерево3, Дерево5)OOB Неопределенность для i=5: std(Дерево1, Дерево3, Дерево5)Реализация
def compute_oob_uncertainty(forest, X_train, y_train): n_samples = X_train.shape[0] n_trees = len(forest.estimators_)
predictions = np.zeros((n_trees, n_samples)) in_bag = np.zeros((n_trees, n_samples), dtype=bool)
for i, (tree, samples) in enumerate(zip(forest.estimators_, forest.estimators_samples_)): # Отслеживаем какие образцы были in-bag in_bag[i, samples] = True # Получаем предсказания для всех образцов predictions[i] = tree.predict(X_train)
# Для каждого образца вычисляем статистики используя только OOB деревья oob_mean = np.zeros(n_samples) oob_std = np.zeros(n_samples)
for i in range(n_samples): oob_mask = ~in_bag[:, i] if oob_mask.sum() > 0: oob_preds = predictions[oob_mask, i] oob_mean[i] = np.mean(oob_preds) oob_std[i] = np.std(oob_preds)
return oob_mean, oob_stdМетрики разногласия моделей
1. Дисперсия предсказаний
def prediction_variance(ensemble, X): """Стандартное отклонение предсказаний по членам ансамбля.""" predictions = np.array([m.predict(X) for m in ensemble]) return np.std(predictions, axis=0)2. Коэффициент вариации
def coefficient_of_variation(ensemble, X): """Относительная неопределенность: std/mean.""" predictions = np.array([m.predict(X) for m in ensemble]) mean_pred = np.mean(predictions, axis=0) std_pred = np.std(predictions, axis=0) return std_pred / (np.abs(mean_pred) + 1e-8)3. Межквартильный размах
def iqr_uncertainty(ensemble, X): """Размах между 25-м и 75-м перцентилем предсказаний.""" predictions = np.array([m.predict(X) for m in ensemble]) q25 = np.percentile(predictions, 25, axis=0) q75 = np.percentile(predictions, 75, axis=0) return q75 - q254. Энтропия (для классификации)
def prediction_entropy(ensemble, X): """Энтропия усредненных вероятностных предсказаний.""" probs = np.array([m.predict_proba(X) for m in ensemble]) mean_probs = np.mean(probs, axis=0) entropy = -np.sum(mean_probs * np.log(mean_probs + 1e-8), axis=1) return entropy5. Взаимная информация (эпистемическая неопределенность)
def mutual_information(ensemble, X): """Отражает эпистемическую неопределенность для классификации.""" probs = np.array([m.predict_proba(X) for m in ensemble]) mean_probs = np.mean(probs, axis=0)
# Общая энтропия total_entropy = -np.sum(mean_probs * np.log(mean_probs + 1e-8), axis=1)
# Ожидаемая энтропия (средняя энтропия индивидуальных предсказаний) individual_entropies = -np.sum(probs * np.log(probs + 1e-8), axis=2) expected_entropy = np.mean(individual_entropies, axis=0)
# Взаимная информация = Общая - Ожидаемая return total_entropy - expected_entropyКалибровка
Почему калибровка важна
Модель калибрована, если её предсказанные вероятности соответствуют реальным частотам:
Если модель предсказывает 70% вероятность роста для 100 ситуаций:- Хорошо калибрована: ~70 реально выросли- Переуверена: 50 реально выросли- Недоуверена: 90 реально вырослиМетрики калибровки
Ожидаемая ошибка калибровки (ECE):
def expected_calibration_error(y_true, y_prob, n_bins=10): """Вычисление ожидаемой ошибки калибровки.""" bin_boundaries = np.linspace(0, 1, n_bins + 1) ece = 0.0
for i in range(n_bins): mask = (y_prob >= bin_boundaries[i]) & (y_prob < bin_boundaries[i+1]) if mask.sum() > 0: bin_accuracy = y_true[mask].mean() bin_confidence = y_prob[mask].mean() bin_size = mask.sum() / len(y_true) ece += bin_size * np.abs(bin_accuracy - bin_confidence)
return eceМетоды калибровки
Масштабирование Платта:
from sklearn.calibration import CalibratedClassifierCV
calibrated_model = CalibratedClassifierCV(base_model, method='sigmoid', cv=5)calibrated_model.fit(X_train, y_train)calibrated_probs = calibrated_model.predict_proba(X_test)Изотоническая регрессия:
calibrated_model = CalibratedClassifierCV(base_model, method='isotonic', cv=5)Температурное масштабирование (для нейросетей):
def temperature_scaling(logits, temperature): """Масштабирование логитов температурой для калибровки.""" return logits / temperature
# Оптимизация температуры на валидационном набореoptimal_temp = optimize_temperature(val_logits, val_labels)calibrated_logits = temperature_scaling(test_logits, optimal_temp)Торговая стратегия с неопределенностью
Размер позиции на основе неопределенности
def calculate_position_size(prediction, uncertainty, base_size, max_uncertainty=0.05, min_confidence=0.6): """ Масштабирование размера позиции обратно пропорционально неопределенности.
Args: prediction: Ожидаемая доходность или вероятность uncertainty: Оценка неопределенности модели base_size: Базовый размер позиции (например, 1.0 для полной позиции) max_uncertainty: Максимально допустимая неопределенность min_confidence: Минимальная уверенность для торговли
Returns: Масштабированный размер позиции """ # Пропускаем если неопределенность слишком высока if uncertainty > max_uncertainty: return 0.0
# Оценка уверенности (обратная нормализованной неопределенности) confidence = 1.0 - (uncertainty / max_uncertainty)
# Пропускаем если уверенность слишком низкая if confidence < min_confidence: return 0.0
# Масштабируем позицию по уверенности position_size = base_size * confidence
# Дополнительно масштабируем по силе предсказания prediction_strength = min(abs(prediction) / 0.02, 1.0) # Нормализуем по 2% position_size *= prediction_strength
return position_sizeКритерий Келли с неопределенностью
def kelly_with_uncertainty(win_prob, win_size, loss_size, uncertainty): """ Скорректированный критерий Келли с учетом неопределенности.
Стандартный Келли: f* = (p*b - q) / b где p = вероятность выигрыша, q = 1-p, b = соотношение выигрыш/проигрыш
Скорректированный: уменьшаем позицию при высокой неопределенности """ # Стандартный Келли b = win_size / loss_size q = 1 - win_prob kelly = (win_prob * b - q) / b
# Корректировка на неопределенность # Высокая неопределенность → более консервативно uncertainty_factor = 1.0 / (1.0 + uncertainty * 10)
# Также используем дробный Келли (половинный Келли распространен) fractional_kelly = kelly * 0.5 * uncertainty_factor
return max(0, fractional_kelly)Голосование ансамбля с весами неопределенности
def uncertainty_weighted_vote(ensemble, X, method='inverse_variance'): """ Объединение предсказаний ансамбля с взвешиванием по неопределенности. """ predictions = np.array([m.predict(X) for m in ensemble])
if method == 'inverse_variance': # Взвешиваем модели по обратной исторической дисперсии variances = np.array([m.historical_variance for m in ensemble]) weights = 1.0 / (variances + 1e-8) weights /= weights.sum()
elif method == 'accuracy': # Взвешиваем по исторической точности accuracies = np.array([m.historical_accuracy for m in ensemble]) weights = accuracies / accuracies.sum()
weighted_prediction = np.sum(weights[:, np.newaxis] * predictions, axis=0) weighted_uncertainty = np.sqrt(np.sum(weights[:, np.newaxis]**2 * (predictions - weighted_prediction)**2, axis=0))
return weighted_prediction, weighted_uncertaintyФреймворк торговых решений
┌────────────────────────────────────────────────────────────────────┐│ ФРЕЙМВОРК ТОРГОВЫХ РЕШЕНИЙ С УЧЕТОМ НЕОПРЕДЕЛЕННОСТИ │├────────────────────────────────────────────────────────────────────┤│ ││ Шаг 1: Получить предсказание ансамбля ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ predictions = ensemble.predict(market_data) │ ││ │ mean_pred = np.mean(predictions) │ ││ │ uncertainty = np.std(predictions) │ ││ └─────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ Шаг 2: Классифицировать уровень неопределенности ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ if uncertainty < 0.01: confidence = "ВЫСОКАЯ" │ ││ │ elif uncertainty < 0.03: confidence = "СРЕДНЯЯ" │ ││ │ else: confidence = "НИЗКАЯ" │ ││ └─────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ Шаг 3: Определить действие ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ │ ││ │ ВЫСОКАЯ уверенность + Сильный сигнал: │ ││ │ → Полная позиция (100%) │ ││ │ │ ││ │ СРЕДНЯЯ уверенность + Сильный сигнал: │ ││ │ → Частичная позиция (50-70%) │ ││ │ │ ││ │ НИЗКАЯ уверенность (любой сигнал): │ ││ │ → Не торгуем или минимальная позиция (0-20%) │ ││ │ │ ││ │ Любая уверенность + Слабый сигнал: │ ││ │ → Не торгуем │ ││ │ │ ││ └─────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ Шаг 4: Управление рисками ││ ┌─────────────────────────────────────────────────────────────┐ ││ │ stop_loss = mean_pred - 2 * uncertainty │ ││ │ take_profit = mean_pred + 1.5 * uncertainty │ ││ │ (Более широкие стопы при высокой неопределенности) │ ││ └─────────────────────────────────────────────────────────────┘ ││ │└────────────────────────────────────────────────────────────────────┘Архитектура реализации
┌─────────────────────────────────────────────────────────────────────┐│ СИСТЕМА АНСАМБЛЕВОЙ НЕОПРЕДЕЛЕННОСТИ │├─────────────────────────────────────────────────────────────────────┤│ ││ СЛОЙ ДАННЫХ ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ Bybit API (через CCXT) │ ││ │ ├── OHLCV данные в реальном времени │ ││ │ ├── Снимки книги ордеров │ ││ │ └── История сделок │ ││ └────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ FEATURE ENGINEERING ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ ├── Технические индикаторы (RSI, MACD, Bollinger) │ ││ │ ├── Признаки объема │ ││ │ ├── Меры волатильности │ ││ │ └── Признаки микроструктуры рынка │ ││ └────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ СЛОЙ АНСАМБЛЯ ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ ││ │ │Случайный лес │ │ XGBoost │ │ LightGBM │ │ ││ │ │ (Бэггинг) │ │ (Бустинг) │ │ (Бустинг) │ │ ││ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ ││ │ │ │ │ │ ││ │ └────────────────┼────────────────┘ │ ││ │ │ │ ││ │ ▼ │ ││ │ ┌────────────────────┐ │ ││ │ │ Мета-обучатель │ │ ││ │ │ (Слой стекинга) │ │ ││ │ └────────────────────┘ │ ││ └────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ КВАНТИФИКАЦИЯ НЕОПРЕДЕЛЕННОСТИ ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ ├── Дисперсия предсказаний (разногласие моделей) │ ││ │ ├── OOB оценки ошибок │ ││ │ ├── Квантильные предсказания (доверительные интервалы) │ ││ │ └── Корректировка калибровки │ ││ └────────────────────────────────────────────────────────────────┘ ││ │ ││ ▼ ││ ТОРГОВЫЕ РЕШЕНИЯ ││ ┌────────────────────────────────────────────────────────────────┐ ││ │ ├── Генерация сигналов (с уверенностью) │ ││ │ ├── Размер позиции (масштабированный по неопределенности) │ ││ │ ├── Управление рисками (динамические стопы) │ ││ │ └── Исполнение ордеров │ ││ └────────────────────────────────────────────────────────────────┘ ││ │└─────────────────────────────────────────────────────────────────────┘Ключевые метрики
Метрики качества неопределенности
| Метрика | Описание | Цель |
|---|---|---|
| Ошибка калибровки | Насколько предсказанная неопределенность соответствует реальной ошибке | < 0.05 |
| Точность | Средний размер интервалов предсказаний | Минимизировать |
| Покрытие | % истинных значений в интервале предсказаний | 90-95% |
| CRPS | Continuous Ranked Probability Score | Минимизировать |
Торговые результаты с неопределенностью
| Метрика | Без неопределенности | С неопределенностью |
|---|---|---|
| Коэффициент Шарпа | 1.2 | 1.8 |
| Макс. просадка | -25% | -15% |
| Процент выигрышей | 52% | 58% |
| Средний размер позиции | 100% | 65% |
| Риск-скорректированная доходность | 1.0x | 1.5x |
Лучшие практики
1. Разнообразие ансамбля
# Хорошо: Разнообразные модели с разными индуктивными смещениямиensemble = [ RandomForestRegressor(n_estimators=100), GradientBoostingRegressor(n_estimators=100), XGBRegressor(n_estimators=100), LGBMRegressor(n_estimators=100), SVR(kernel='rbf'),]
# Плохо: Однородный ансамбльensemble = [ RandomForestRegressor(n_estimators=100), RandomForestRegressor(n_estimators=100, max_depth=5), RandomForestRegressor(n_estimators=100, max_depth=10),]2. Регулярные проверки калибровки
def monitor_calibration(predictions, uncertainties, actuals, window=100): """Мониторинг калибровки в скользящем окне.""" for i in range(len(actuals) - window): window_preds = predictions[i:i+window] window_uncert = uncertainties[i:i+window] window_actual = actuals[i:i+window]
# Проверяем попадают ли реальные значения в предсказанные интервалы z_scores = (window_actual - window_preds) / window_uncert coverage = np.mean(np.abs(z_scores) < 1.96)
if coverage < 0.90: logger.warning(f"Калибровка ухудшилась: {coverage:.2%} покрытие")3. Пороги неопределенности
UNCERTAINTY_THRESHOLDS = { 'very_low': 0.005, # < 0.5% → Очень уверен 'low': 0.01, # 0.5-1% → Уверен 'medium': 0.02, # 1-2% → Умеренно 'high': 0.03, # 2-3% → Низкая уверенность 'very_high': 0.05, # > 3% → Не торговать}Структура директорий
324_ensemble_uncertainty/├── README.md # Этот файл├── README.ru.md # Русский перевод├── readme.simple.md # Простое объяснение для начинающих├── readme.simple.ru.md # Русская версия для начинающих├── python/ # Python реализация│ ├── __init__.py│ ├── data_fetcher.py # Получение данных через CCXT│ ├── features.py # Feature engineering│ ├── ensemble.py # Модели ансамбля│ ├── uncertainty.py # Квантификация неопределенности│ ├── calibration.py # Калибровка модели│ ├── strategy.py # Торговая стратегия│ ├── backtest.py # Движок бэктестинга│ └── main.py # Главная точка входа└── rust_ensemble_uncertainty/ # Rust реализация ├── Cargo.toml ├── src/ │ ├── lib.rs │ ├── api/ # Bybit API клиент │ ├── ensemble/ # Реализации ансамбля │ ├── uncertainty/ # Метрики неопределенности │ ├── strategy/ # Торговая стратегия │ └── backtest/ # Бэктестинг └── examples/ ├── fetch_data.rs ├── train_ensemble.rs └── live_trading.rsСсылки
-
Lakshminarayanan et al. (2017) - “Simple and Scalable Predictive Uncertainty Estimation using Deep Ensembles”
-
Gal & Ghahramani (2016) - “Dropout as a Bayesian Approximation”
-
Kuleshov et al. (2018) - “Accurate Uncertainties for Deep Learning Using Calibrated Regression”
-
Duan et al. (2020) - “NGBoost: Natural Gradient Boosting for Probabilistic Prediction”
-
Breiman (2001) - “Random Forests”
Уровень сложности
От среднего до продвинутого - Требуется понимание:
- Ансамблевых методов (бэггинг, бустинг, стекинг)
- Теории вероятностей и статистики
- Концепций калибровки моделей
- Принципов управления рисками
- Программирования на Python/Rust
Отказ от ответственности
Эта глава предназначена только для образовательных целей. Торговля криптовалютой сопряжена со значительным риском. Стратегии, описанные здесь, не были проверены в реальной торговле и должны быть тщательно протестированы перед любым применением в реальном мире. Прошлые результаты не гарантируют будущих результатов. Всегда используйте надлежащее управление рисками и никогда не торгуйте на средства, которые вы не можете позволить себе потерять.