> Go Батя

Как не утонуть в 79-мерном гиперкубе — иерархическая оптимизация торгового бота

#биржа #genetic-algorithm #автоматизация #робот

Когда я начал настраивать торгового бота, у меня было 79 параметров. Не пять, не десять — семьдесят девять. Непрерывные float64, целые числа, коррелирующие друг с другом самым неочевидным образом. Каждый индикатор, каждая стратегия, каждый порог в ансамбле.

Можно ли скормить все 79 параметров одному генетическому алгоритму и получить работающего бота? Технически — да. Практически — нет. Проклятие размерности ударит со всей силы: популяция в 5000+ особей, 500+ поколений, миллионы вызовов fitness-функции и чёрный ящик на выходе, идеально подогнанный под исторический шум.

Я пошёл другим путём.

Четыре слоя вместо одного гиперкуба

Вместо оптимизации всего сразу — разбиение на четыре иерархических слоя. Каждый решает свою подзадачу, результат нижележащего слоя фиксируется перед переходом к следующему.

Слой 1: Индикаторы (33 параметра)

На этом уровне вопрос не «заработает ли стратегия?», а «даёт ли индикатор осмысленный сигнал сам по себе?».

Каждый индикатор прогоняется изолированно на эталонной стратегии. MACD оптимизируется по качеству crossover + histogram, Bollinger — по %B, CCI — по пересечению уровня ±100. Метрика простая: средняя корреляция сигнала индикатора с последующим движением цены.

На выходе — зафиксированные параметры: period=14, multiplier=2.5 для Bollinger. Индикаторы работают. Движемся дальше.

Слой 2: Стратегии (25 параметров)

Индикаторы дают чистый сигнал — настраиваем 11 стратегий, которые на них опираются. Каждая тренируется независимо, со своим мини-генетическим алгоритмом.

Ichimoku подбирает веса компонентов (tenkan/kijun, cloud, chikou) и минимальный порог уверенности. EMACross ищет оптимальный min_norm и conf_multiplier. SuperTrend — просто порог confidence.

Метрика: точность направления × средняя уверенность при правильных сигналах. Никакого портфельного эффекта — только качество каждой стратегии по отдельности.

Слой 3: Ансамбль + детектор режима (11 параметров)

Все 11 стратегий откалиброваны, индикаторы настроены. Теперь решаем, как их комбинировать и в каких рыночных режимах.

Ансамблевый слой подбирает learning rate, начальные и минимальные веса стратегий. Детектор режима настраивает пороги ADX для разделения рынка на трендовый и флэтовый, параметры fallback-детектора на SMA, чувствительность к волатильности.

Метрика резко меняется: теперь это Sharpe ratio и Profit Factor итогового совета. Оцениваем не отдельные стратегии, а их комбинацию.

Опционально — feature selection: какие стратегии оставить, от каких отказаться.

Слой 4: Риск-менеджмент (9 параметров)

У нас есть ансамбль, который говорит «покупай» с уверенностью 0.73. Как реагировать?

Последний слой решает сугубо практические вопросы: процент капитала на сделку, когда фиксировать прибыль, максимальный дневной убыток, количество одновременных лотов.

Метрика — итоговая кривая equity: максимальная просадка, Sharpe, Sortino.

Что это дало на практике?

Параметр Один GA (79 генов) Иерархический (4×~20)
Размер популяции 5000+ 200–500 на слой
Поколений до сходимости 500–1000 50–100 на слой
Вызовов fitness ~5×10⁶ ~10⁵ (в 50× меньше)
Переобучение Высокое Низкое
Прозрачность Чёрный ящик Понятно, что работает

Но главное — интерпретируемость. Когда что-то идёт не так (а в торговле всё идёт не так), я знаю, какой слой виноват:

  • Индикаторы дают мусор? → Слой 1
  • Стратегии перестали угадывать направление? → Слой 2
  • Ансамбль размазал уверенность? → Слой 3
  • Риск-менеджмент режет всё подряд? → Слой 4

79-мерный гиперкуб превратился в четыре последовательных пространства по 15–33 измерения. Каждое решается простым GA, байесовской оптимизацией или даже grid search для 2–3 ключевых параметров.

Про альтернативы

Байесовская оптимизация хороша для 20–30 параметров, но для 79 — те же проблемы, что и у GA.

Sensitivity screening (прогон каждого параметра по одному через random search) — планирую как первый шаг перед иерархической оптимизацией: оставить топ-15–20 влиятельных генов и сократить размерность ещё до разбиения на слои.

Регуляризация (fitness = raw_pnl — λ × N_active_genes) — хороший способ бороться с переобучением независимо от схемы оптимизации.

Фиксация коррелированных групп (MACD(12, 26, 9) как единый предварительно настроенный юнит) — ещё один способ уменьшить размерность без потери качества.

Но иерархический подход оказался самым прагматичным: выигрыш в скорости на порядок и, что важнее, прозрачная логика на каждом этапе.