Multi-symbol валидация: проверяйте стратегию на всех парах
Статья из серии «Бэктесты без иллюзий»
Вы оптимизировали стратегию на ETHUSDT. 25 месяцев данных, 12+ параметров. Бэктест показывает PnL +55%, 500 сделок, MaxDD -0.9%, позиция открыта 15% времени. Equity curve плавно растёт. Параметры прошли plateau analysis — оптимум выглядит широким. Walk-forward даёт WFER > 0.6. Monte Carlo bootstrap показывает положительный 5-й перцентиль.
Всё идеально. Кроме одного: вы протестировали стратегию на одном инструменте.
Запускаете тот же алгоритм с теми же параметрами на BTCUSDT — PnL +8%. На SOLUSDT — PnL -12%. На DOGEUSDT — PnL -34%. Стратегия, прошедшая все проверки на ETH, оказывается убыточной на большинстве других пар.
Это не баг. Это single-symbol trap — одна из самых распространённых и коварных форм overfitting в алготрейдинге.
Ловушка одного инструмента

Оптимизация стратегии на одном символе — это, по сути, подгонка под ценовую динамику конкретного актива. Даже если вы провели walk-forward, даже если bootstrap показывает широкие доверительные интервалы — все эти проверки выполнены внутри одного временного ряда.
Walk-forward проверяет робастность по времени: работают ли параметры на будущих данных того же инструмента. Monte Carlo проверяет робастность по порядку сделок: выдержит ли стратегия иную последовательность. Но ни один из этих методов не проверяет робастность по инструменту: работает ли стратегия на других активах с другими характеристиками.
Если стратегия прибыльна только на ETHUSDT — она захватила не рыночную неэффективность, а специфическую структуру ценового ряда ETH:
- Характерные паттерны свечей, уникальные для ETH
- Конкретные уровни волатильности, под которые настроены пороги
- Специфику ликвидности и микроструктуры именно этой пары
- Корреляцию с BTC, характерную для определённого периода
Всё это — не edge. Это curve fitting на уровне инструмента.
Группы символов (tiers) на крипторынке

Не все криптовалюты одинаковы. Для осмысленной multi-symbol валидации необходимо понимать, что инструменты делятся на группы с принципиально разными характеристиками.
Tier 1: Blue chips (BTC, ETH)
Высокая ликвидность, относительно низкая волатильность, институциональный поток. Корреляция с макро (S&P 500, DXY, ставки ФРС). Глубокие стаканы, узкие спреды, стабильные funding rates. Типичная дневная волатильность: 2-4%.
Tier 2: Large caps (SOL, BNB, ADA, XRP, AVAX)
Умеренная ликвидность, повышенная волатильность. Движения часто обусловлены секторной динамикой (L1 vs L2, DeFi vs инфра). Funding rates более волатильны. Спреды шире. Типичная дневная волатильность: 4-6%.
Tier 3: Mid caps (DOGE, SHIB, PEPE, ARB, OP)
Мем-коины и нарративные токены. Высокая волатильность, низкая корреляция с фундаментальными факторами. Движения определяются социальными сетями, листингами, нарративами. Тонкие стаканы на некоторых биржах. Типичная дневная волатильность: 6-10%.
Tier 4: Low caps (новые листинги)
Экстремальная волатильность, тонкие стаканы, риск манипуляций. Часто недостаточная история для полноценного бэктеста. Типичная дневная волатильность: 10-20%+.
Сводная таблица характеристик
| Характеристика | Tier 1 | Tier 2 | Tier 3 | Tier 4 |
|---|---|---|---|---|
| Дневная волатильность | 2-4% | 4-6% | 6-10% | 10-20%+ |
| Средний спред (perps) | 0.01-0.02% | 0.02-0.05% | 0.05-0.15% | 0.1-0.5%+ |
| Глубина стакана (top 5 bps) | $5-50M | $1-10M | $100K-2M | $10K-200K |
| Funding rate (средний abs) | 0.005-0.01% | 0.01-0.03% | 0.02-0.08% | 0.05-0.2%+ |
| Корреляция с BTC | 0.85-0.95 | 0.6-0.85 | 0.3-0.7 | 0.1-0.5 |
| Минимальная история | 5+ лет | 2-5 лет | 6 мес - 3 года | < 6 мес |
Каждый тир — это отдельный «мир» с собственной микроструктурой. Стратегия, настроенная на Tier 1, попадает в чужеродную среду при переходе на Tier 3.
Методология multi-symbol валидации

Шаг 1: Оптимизация на одном символе
Выберите символ для оптимизации — например, ETHUSDT. Проведите полный пайплайн: Optuna-оптимизация, plateau analysis, walk-forward. Зафиксируйте параметры.
Шаг 2: Тестирование на символах того же тира
Запустите стратегию с теми же параметрами на 5-10 символах из того же тира. Для Tier 1 это ограничено (BTC + ETH), но для Tier 2 и Tier 3 символов достаточно.
Шаг 3: Тестирование на символах других тиров
Запустите стратегию на 3-5 символах из каждого другого тира. Это самый жёсткий тест: если стратегия работает на ETHUSDT (Tier 1) и на DOGEUSDT (Tier 3), вероятность curve fitting минимальна.
Шаг 4: Анализ результатов по группам
Агрегируйте метрики по тирам и оцените cross-symbol robustness.
Метрики для каждого символа
Для каждого символа фиксируем:
- PnL — итоговая доходность
- MaxDD — максимальная просадка
- N trades — число сделок
- Win rate — доля прибыльных сделок
- PnL/active day — доходность на единицу активного времени (подробнее в PnL по активному времени)
Критерии прохождения
Стратегия проходит multi-symbol валидацию, если:
- Прибыльна на >= 60% символов того же тира
- Средний PnL по группе положительный
- MaxDD не увеличивается драматически (не более чем в 2-3 раза относительно оптимизационного символа)
- Если стратегия прибыльна ТОЛЬКО на оптимизационном символе — отклонить
Пример: три стратегии, три результата

Рассмотрим конкретный пример. Три стратегии (Strategy A, Strategy B, Strategy C), оптимизированные на ETHUSDT, протестированы на 12 символах из четырёх тиров.
Strategy A (оптимизирована на ETHUSDT)
Параметры: PnL +55%, ~500 сделок, ~15% active time, MaxDD ~0.9%.
| Символ | Tier | PnL | MaxDD | N trades | Win rate | PnL/active day |
|---|---|---|---|---|---|---|
| ETHUSDT* | 1 | +55.2% | -0.9% | 491 | 52.1% | 0.48% |
| BTCUSDT | 1 | +31.4% | -1.8% | 478 | 50.8% | 0.27% |
| SOLUSDT | 2 | +22.7% | -3.1% | 512 | 49.2% | 0.18% |
| BNBUSDT | 2 | +18.3% | -2.7% | 467 | 48.9% | 0.16% |
| AVAXUSDT | 2 | +8.1% | -4.5% | 498 | 47.6% | 0.07% |
| ADAUSDT | 2 | -3.2% | -6.1% | 445 | 46.1% | -0.03% |
| DOGEUSDT | 3 | -12.8% | -9.4% | 531 | 44.3% | -0.10% |
| SHIBUSDT | 3 | -18.7% | -12.1% | 487 | 43.1% | -0.16% |
| PEPEUSDT | 3 | -24.3% | -14.8% | 556 | 42.7% | -0.18% |
| ARBUSDT | 3 | -7.4% | -7.2% | 419 | 45.8% | -0.07% |
| OPUSDT | 3 | -5.1% | -6.8% | 402 | 46.2% | -0.05% |
* — символ оптимизации
Результат по тирам:
| Tier | Символов | Прибыльных | Средний PnL | Средний MaxDD |
|---|---|---|---|---|
| Tier 1 | 2 | 2 (100%) | +43.3% | -1.4% |
| Tier 2 | 4 | 3 (75%) | +11.5% | -4.1% |
| Tier 3 | 5 | 0 (0%) | -13.7% | -10.1% |
Вердикт: Strategy A работает на Tier 1-2, но полностью провалена на Tier 3. Это типичная стратегия, настроенная под низковолатильную среду. Для портфеля из blue chips и large caps — допустимо. Для универсального использования — нет.
Strategy B (оптимизирована на ETHUSDT)
Параметры: PnL +25%, ~40 сделок, ~5% active time.
| Символ | Tier | PnL | MaxDD | N trades | Win rate |
|---|---|---|---|---|---|
| ETHUSDT* | 1 | +25.1% | -2.3% | 38 | 57.9% |
| BTCUSDT | 1 | +21.8% | -2.8% | 41 | 56.1% |
| SOLUSDT | 2 | +19.4% | -3.5% | 44 | 54.5% |
| BNBUSDT | 2 | +16.7% | -3.1% | 37 | 54.1% |
| AVAXUSDT | 2 | +12.3% | -4.2% | 42 | 52.4% |
| ADAUSDT | 2 | +8.9% | -4.8% | 39 | 51.3% |
| DOGEUSDT | 3 | +4.2% | -6.7% | 48 | 47.9% |
| SHIBUSDT | 3 | -1.3% | -8.4% | 45 | 46.7% |
| PEPEUSDT | 3 | -3.8% | -9.1% | 52 | 46.2% |
| ARBUSDT | 3 | +6.1% | -5.8% | 40 | 50.0% |
| OPUSDT | 3 | +3.7% | -6.2% | 38 | 50.0% |
Результат по тирам:
| Tier | Символов | Прибыльных | Средний PnL | Средний MaxDD |
|---|---|---|---|---|
| Tier 1 | 2 | 2 (100%) | +23.5% | -2.6% |
| Tier 2 | 4 | 4 (100%) | +14.3% | -3.9% |
| Tier 3 | 5 | 3 (60%) | +1.8% | -7.2% |
Вердикт: Strategy B прибыльна на 9 из 11 символов (82%). Средний PnL положительный во всех тирах. MaxDD растёт предсказуемо с тиром. Это робастная стратегия с реальным рыночным edge. Несмотря на более скромный PnL на оптимизационном символе (+25% vs +55%), Strategy B значительно надёжнее Strategy A.
Strategy C (оптимизирована на ETHUSDT)
Параметры: PnL +300%, ~400 сделок, ~45% active time, MaxDD ~17%.
| Символ | Tier | PnL | MaxDD | N trades | Win rate |
|---|---|---|---|---|---|
| ETHUSDT* | 1 | +301.2% | -17.1% | 418 | 53.8% |
| BTCUSDT | 1 | +42.7% | -28.4% | 395 | 48.6% |
| SOLUSDT | 2 | -18.3% | -41.2% | 456 | 44.1% |
| BNBUSDT | 2 | +12.1% | -33.7% | 387 | 46.8% |
| AVAXUSDT | 2 | -31.4% | -52.8% | 471 | 42.3% |
| ADAUSDT | 2 | -44.7% | -58.1% | 412 | 40.5% |
| DOGEUSDT | 3 | -67.2% | -74.3% | 528 | 38.1% |
| PEPEUSDT | 3 | -72.1% | -81.6% | 574 | 37.4% |
Вердикт: Strategy C — классический overfitting. +301% на ETHUSDT, но катастрофические убытки на большинстве других пар. MaxDD на Tier 3 превышает 70% — это уничтожение капитала. Стратегия захватила уникальные паттерны ETH, а не рыночную неэффективность. Отклонить.
Почему стратегии ломаются на других символах

1. Volatility mismatch
Самая распространённая причина. Параметры стратегии настроены под конкретный уровень волатильности. Если стратегия использует порог входа в 2% — для ETH с дневной волатильностью 3% это разумный фильтр. Для DOGE с дневной волатильностью 8% — этот порог срабатывает слишком часто, генерируя массу ложных сигналов.
Аналогично, стоп-лосс на 1% адекватен для ETH, но для PEPE это нормальный «шум», и стоп выбивается десятки раз в день.
2. Различия в ликвидности
Стратегия предполагает мгновенное исполнение ордеров по текущей цене. На BTCUSDT с глубиной стакана 200K — ваш ордер на $10K сдвинет цену, и реальное исполнение будет хуже на 0.05-0.2%. За 500 сделок это 25-100% потерь только на slippage.
3. Микроструктура рынка
Каждый инструмент имеет свою микроструктуру:
- Funding rates: на BTC funding стабильно положительный в бычьем рынке (+0.01% каждые 8 часов). На мем-коинах funding может скакать от -0.3% до +0.5%. Подробнее — в Funding rates убивают ваш leverage.
- Спред: на Tier 1 спред — 0.01%, на Tier 4 — 0.5%. Стратегия с мелкими тейк-профитами не может быть прибыльной при спреде, превышающем размер тейка.
- Паттерны манипуляций: wicks, spoofing, wash trading — на каждом тире проявляются по-разному.
4. Режимная чувствительность
Альткоины ведут себя по-разному в разных фазах рынка:
- В бычьем тренде альткоины обгоняют BTC (beta > 1)
- В медвежьем тренде альткоины падают сильнее BTC
- В боковике альткоины могут коррелировать с BTC или двигаться по собственным нарративам
Стратегия, оптимизированная в одной фазе на одном символе, может быть оптимально настроена на лаг/лид именно этого символа относительно BTC — и этот лаг/лид изменится при смене режима.
Adaptive parameter scaling

Запускать стратегию с идентичными параметрами на всех символах — некорректно. Но полная переоптимизация на каждом символе обесценивает саму идею multi-symbol валидации (параметры станут «свои» для каждого символа).
Компромисс — нормализация параметров по волатильности:
import numpy as np
def scale_params_by_volatility(
base_params: dict,
optimization_symbol_vol: float,
target_symbol_vol: float,
vol_sensitive_params: list[str],
) -> dict:
"""
Масштабирование параметров стратегии по волатильности целевого символа.
Args:
base_params: параметры, оптимизированные на исходном символе
optimization_symbol_vol: дневная волатильность символа оптимизации
target_symbol_vol: дневная волатильность целевого символа
vol_sensitive_params: список параметров, чувствительных к волатильности
"""
vol_ratio = target_symbol_vol / optimization_symbol_vol
adjusted = base_params.copy()
for param in vol_sensitive_params:
if param in adjusted:
adjusted[param] = adjusted[param] * vol_ratio
return adjusted
base_params = {
"entry_threshold": 0.02, # 2% — порог входа
"stop_loss": 0.01, # 1% — стоп-лосс
"take_profit": 0.03, # 3% — тейк-профит
"trailing_stop": 0.008, # 0.8% — трейлинг-стоп
"atr_multiplier": 2.5, # множитель ATR (не масштабируем)
"rsi_period": 14, # период RSI (не масштабируем)
"ma_fast": 10, # быстрая MA (не масштабируем)
"ma_slow": 50, # медленная MA (не масштабируем)
}
vol_sensitive = ["entry_threshold", "stop_loss", "take_profit", "trailing_stop"]
eth_vol = 0.032 # 3.2%
doge_vol = 0.081 # 8.1%
doge_params = scale_params_by_volatility(
base_params, eth_vol, doge_vol, vol_sensitive
)
print("ETH params:", {k: f"{v:.4f}" for k, v in base_params.items() if k in vol_sensitive})
print("DOGE params:", {k: f"{v:.4f}" for k, v in doge_params.items() if k in vol_sensitive})
Вывод:
ETH params: {'entry_threshold': '0.0200', 'stop_loss': '0.0100', 'take_profit': '0.0300', 'trailing_stop': '0.0080'}
DOGE params: {'entry_threshold': '0.0506', 'stop_loss': '0.0253', 'take_profit': '0.0759', 'trailing_stop': '0.0203'}
Стоп-лосс увеличился с 1% до 2.53% — адекватно для дневной волатильности DOGE в 8.1%. Без масштабирования стоп на 1% выбивался бы по «шуму» десятки раз.
Важно: масштабируйте только ценовые пороги (входы, стопы, тейки). Периоды индикаторов (RSI, MA) и множители (ATR multiplier) обычно не масштабируются — они уже нормализованы по волатильности через сам индикатор.
Два режима валидации
-
Strict mode (без масштабирования): запуск с идентичными параметрами. Тест на абсолютную робастность. Если стратегия прибыльна — edge сильный.
-
Adaptive mode (с масштабированием): запуск с нормализованными параметрами. Тест на робастность логики стратегии, с допущением, что уровни волатильности различаются.
Рекомендуем проводить оба теста. Strict mode — для оценки «силы» edge. Adaptive mode — для практического применения.
Cross-symbol robustness score

Для количественной оценки multi-symbol робастности вводим составную метрику — Cross-Symbol Robustness Score (CSRS).
Формула
где:
- — доля прибыльных символов:
- — нормализованный средневзвешенный PnL (взвешенный по ликвидности):
где — ликвидность символа (средний дневной объём).
- — бонус за кросс-тировую консистентность:
- — штраф за высокую дисперсию PnL между символами:
Веса по умолчанию
| Компонент | Вес | Обоснование |
|---|---|---|
| (доля прибыльных) | 0.35 | Самый важный: стратегия должна работать на большинстве |
| (средний PnL) | 0.25 | Абсолютная доходность |
| (кросс-тировая) | 0.25 | Бонус за универсальность |
| (штраф за дисперсию) | 0.15 | Штраф за нестабильность |
Интерпретация CSRS
| CSRS | Интерпретация |
|---|---|
| > 0.7 | Отличная робастность. Стратегия работает на большинстве инструментов. |
| 0.5 — 0.7 | Хорошая робастность. Стратегия работает в своём тире и частично в других. |
| 0.3 — 0.5 | Пограничная. Стратегия работает на узком наборе символов. |
| < 0.3 | Низкая робастность. Вероятен curve fitting на уровне инструмента. |
Полная реализация: multi-symbol validation pipeline

import numpy as np
import pandas as pd
from dataclasses import dataclass, field
from typing import Callable, Optional
@dataclass
class SymbolResult:
"""Результат стратегии на одном символе."""
symbol: str
tier: int
pnl: float
max_dd: float
n_trades: int
win_rate: float
pnl_per_active_day: float
avg_daily_volume: float # ликвидность
@dataclass
class TierResult:
"""Агрегированный результат по тиру."""
tier: int
symbols: list[SymbolResult]
n_symbols: int
n_profitable: int
profit_ratio: float
avg_pnl: float
avg_max_dd: float
pnl_std: float
@dataclass
class MultiSymbolResult:
"""Полный результат multi-symbol валидации."""
symbol_results: list[SymbolResult]
tier_results: list[TierResult]
csrs: float
passed: bool
optimization_symbol: str
report: str
SYMBOL_TIERS = {
1: ["BTCUSDT", "ETHUSDT"],
2: ["SOLUSDT", "BNBUSDT", "ADAUSDT", "XRPUSDT", "AVAXUSDT"],
3: ["DOGEUSDT", "SHIBUSDT", "PEPEUSDT", "ARBUSDT", "OPUSDT"],
}
SYMBOL_VOLATILITY = {
"BTCUSDT": 0.028, "ETHUSDT": 0.032,
"SOLUSDT": 0.052, "BNBUSDT": 0.038, "ADAUSDT": 0.048,
"XRPUSDT": 0.045, "AVAXUSDT": 0.055,
"DOGEUSDT": 0.081, "SHIBUSDT": 0.092, "PEPEUSDT": 0.105,
"ARBUSDT": 0.068, "OPUSDT": 0.063,
}
SYMBOL_VOLUME = {
"BTCUSDT": 15e9, "ETHUSDT": 8e9,
"SOLUSDT": 2e9, "BNBUSDT": 1.5e9, "ADAUSDT": 800e6,
"XRPUSDT": 1.2e9, "AVAXUSDT": 500e6,
"DOGEUSDT": 1e9, "SHIBUSDT": 400e6, "PEPEUSDT": 600e6,
"ARBUSDT": 300e6, "OPUSDT": 250e6,
}
def run_multi_symbol_validation(
strategy_fn: Callable,
base_params: dict,
optimization_symbol: str,
data_loader: Callable,
vol_sensitive_params: list[str],
adaptive: bool = True,
csrs_weights: tuple = (0.35, 0.25, 0.25, 0.15),
min_profit_ratio: float = 0.6,
) -> MultiSymbolResult:
"""
Полный пайплайн multi-symbol валидации.
Args:
strategy_fn: функция стратегии (data, params) -> (pnl, max_dd, n_trades, win_rate, returns)
base_params: параметры, оптимизированные на optimization_symbol
optimization_symbol: символ оптимизации
data_loader: функция загрузки данных (symbol) -> np.ndarray
vol_sensitive_params: параметры для масштабирования по волатильности
adaptive: использовать масштабирование волатильности
csrs_weights: веса (w1, w2, w3, w4) для CSRS
min_profit_ratio: минимальная доля прибыльных символов в тире
"""
w1, w2, w3, w4 = csrs_weights
opt_vol = SYMBOL_VOLATILITY.get(optimization_symbol, 0.03)
symbol_results = []
for tier, symbols in SYMBOL_TIERS.items():
for symbol in symbols:
data = data_loader(symbol)
if data is None or len(data) < 100:
continue
if adaptive and symbol != optimization_symbol:
sym_vol = SYMBOL_VOLATILITY.get(symbol, 0.05)
params = scale_params_by_volatility(
base_params, opt_vol, sym_vol, vol_sensitive_params
)
else:
params = base_params.copy()
pnl, max_dd, n_trades, win_rate, returns = strategy_fn(data, params)
active_days = max(n_trades * 0.5, 1) # грубая оценка
pnl_per_day = pnl / active_days
symbol_results.append(SymbolResult(
symbol=symbol,
tier=tier,
pnl=pnl,
max_dd=max_dd,
n_trades=n_trades,
win_rate=win_rate,
pnl_per_active_day=pnl_per_day,
avg_daily_volume=SYMBOL_VOLUME.get(symbol, 1e6),
))
tier_results = []
tiers_present = sorted(set(r.tier for r in symbol_results))
for tier in tiers_present:
tier_symbols = [r for r in symbol_results if r.tier == tier]
n_profitable = sum(1 for r in tier_symbols if r.pnl > 0)
pnls = [r.pnl for r in tier_symbols]
tier_results.append(TierResult(
tier=tier,
symbols=tier_symbols,
n_symbols=len(tier_symbols),
n_profitable=n_profitable,
profit_ratio=n_profitable / len(tier_symbols) if tier_symbols else 0,
avg_pnl=np.mean(pnls),
avg_max_dd=np.mean([r.max_dd for r in tier_symbols]),
pnl_std=np.std(pnls),
))
all_pnls = [r.pnl for r in symbol_results]
all_volumes = [r.avg_daily_volume for r in symbol_results]
n_total = len(symbol_results)
n_profitable = sum(1 for r in symbol_results if r.pnl > 0)
r_profit = n_profitable / n_total if n_total > 0 else 0
total_vol = sum(all_volumes)
r_pnl_raw = sum(r.pnl * r.avg_daily_volume for r in symbol_results) / total_vol
r_pnl = 1 / (1 + np.exp(-r_pnl_raw * 5))
profitable_tiers = sum(1 for tr in tier_results if tr.avg_pnl > 0)
p_consistency = profitable_tiers / len(tier_results) if tier_results else 0
pnl_std = np.std(all_pnls) if len(all_pnls) > 1 else 0
pnl_mean = np.mean(all_pnls) if all_pnls else 0.01
p_variance = pnl_std / max(abs(pnl_mean), 0.01)
p_variance = min(p_variance, 5.0) # ограничиваем штраф
csrs = w1 * r_profit + w2 * r_pnl + w3 * p_consistency - w4 * (p_variance / 5.0)
csrs = max(0, min(1, csrs)) # clamp to [0, 1]
opt_tier = None
for tier, symbols in SYMBOL_TIERS.items():
if optimization_symbol in symbols:
opt_tier = tier
break
same_tier_result = next((tr for tr in tier_results if tr.tier == opt_tier), None)
passed = (
csrs >= 0.5
and (same_tier_result is None or same_tier_result.profit_ratio >= min_profit_ratio)
and np.mean(all_pnls) > 0
)
report = _generate_report(
symbol_results, tier_results, csrs, passed,
optimization_symbol, adaptive
)
return MultiSymbolResult(
symbol_results=symbol_results,
tier_results=tier_results,
csrs=csrs,
passed=passed,
optimization_symbol=optimization_symbol,
report=report,
)
def _generate_report(
symbol_results, tier_results, csrs, passed,
opt_symbol, adaptive
) -> str:
"""Генерация текстового отчёта."""
lines = []
lines.append("=" * 60)
lines.append("MULTI-SYMBOL VALIDATION REPORT")
lines.append(f"Optimization symbol: {opt_symbol}")
lines.append(f"Mode: {'adaptive' if adaptive else 'strict'}")
lines.append(f"CSRS: {csrs:.3f}")
lines.append(f"Passed: {'YES' if passed else 'NO'}")
lines.append("=" * 60)
for tr in tier_results:
lines.append(f"\n--- Tier {tr.tier} ---")
lines.append(f" Symbols: {tr.n_symbols}, Profitable: {tr.n_profitable} "
f"({tr.profit_ratio:.0%})")
lines.append(f" Avg PnL: {tr.avg_pnl:.2%}, Avg MaxDD: {tr.avg_max_dd:.2%}")
lines.append(f" PnL StdDev: {tr.pnl_std:.2%}")
for sr in tr.symbols:
marker = "*" if sr.symbol == opt_symbol else " "
status = "+" if sr.pnl > 0 else "-"
lines.append(
f" {marker} [{status}] {sr.symbol:12s} "
f"PnL={sr.pnl:+.2%} MaxDD={sr.max_dd:.2%} "
f"Trades={sr.n_trades:4d} WR={sr.win_rate:.1%}"
)
lines.append("\n" + "=" * 60)
return "\n".join(lines)
Пример использования pipeline
def my_strategy(data, params):
"""Ваша стратегия. Возвращает (pnl, max_dd, n_trades, win_rate, returns)."""
pass
def load_ohlcv(symbol):
"""Загрузка OHLCV данных для символа."""
pass
base_params = {
"entry_threshold": 0.02,
"stop_loss": 0.01,
"take_profit": 0.03,
"trailing_stop": 0.008,
"atr_multiplier": 2.5,
"rsi_period": 14,
"ma_fast": 10,
"ma_slow": 50,
}
result = run_multi_symbol_validation(
strategy_fn=my_strategy,
base_params=base_params,
optimization_symbol="ETHUSDT",
data_loader=load_ohlcv,
vol_sensitive_params=["entry_threshold", "stop_loss", "take_profit", "trailing_stop"],
adaptive=True,
)
print(result.report)
print(f"\nCSRS: {result.csrs:.3f}")
print(f"Passed: {result.passed}")
Когда single-symbol валидация допустима

Не каждая стратегия должна работать на множестве инструментов. Есть легитимные случаи, когда single-symbol — нормальный подход:
Market making на конкретном стакане
Стратегия маркет-мейкинга (например, по модели Avellaneda-Stoikov) по определению привязана к конкретному стакану. Параметры зависят от конкретной микроструктуры: глубины, spread, queue position, fill rate. Тестирование на другом символе не имеет смысла — это другой стакан.
Арбитраж между конкретными парами
Funding rate арбитраж или кросс-биржевой арбитраж по определению привязан к конкретным парам инструментов. Валидация здесь — на других биржах с теми же парами, а не на других символах.
Стратегии, явно использующие уникальные свойства актива
Если стратегия основана на специфическом свойстве одного актива (например, корреляция BTC с хэшрейтом или ETH с gas fees), multi-symbol валидация неприменима. Но таких стратегий — единицы.
Во всех остальных случаях — если стратегия основана на «общих» сигналах (MA crossover, RSI, momentum, mean reversion) — multi-symbol валидация обязательна. Если generic-стратегия работает только на одном символе, это не edge — это overfitting.
Связь с другими методами валидации

Multi-symbol валидация — это один из трёх ортогональных методов out-of-sample тестирования:
| Метод | Ось проверки | Что выявляет |
|---|---|---|
| Walk-Forward | Время | Переобучение на конкретном периоде |
| Multi-symbol | Инструмент | Переобучение на конкретном активе |
| Monte Carlo Bootstrap | Порядок сделок | Зависимость от конкретной последовательности |
Каждый метод проверяет робастность по своей оси. Стратегия может пройти walk-forward, но провалиться на multi-symbol (curve fitted к инструменту). Может пройти multi-symbol, но провалиться на Monte Carlo (зависит от удачного порядка сделок).
Максимальная защита от overfitting: использовать все три метода.
Полный пайплайн валидации:
- Оптимизация параметров на одном символе
- Plateau analysis — проверка устойчивости оптимума
- Walk-forward — проверка по времени (WFER > 0.5)
- Multi-symbol — проверка по инструменту (CSRS > 0.5)
- Monte Carlo bootstrap — доверительные интервалы (5th percentile > 0)
- Учёт funding rates и асимметрии убытков
Стратегия, прошедшая все шесть проверок, имеет минимальную вероятность оказаться артефактом overfitting.
Расширения: корреляция символов и cascade-стратегии

Multi-symbol валидация раскрывает ещё один аспект: корреляции между символами. Если стратегия прибыльна на BTC и ETH, но убыточна на всех альткоинах — это информация о том, что edge привязан к высокой корреляции BTC-ETH. Подробный анализ корреляционных структур — в статье Корреляция сигналов и парный трейдинг.
Для портфелей стратегий multi-symbol результаты определяют, на каких инструментах стратегию стоит запускать. Strategy A из примера выше — только Tier 1-2. Strategy B — Tier 1-3. Это входные данные для каскадной оркестрации, где разные стратегии запускаются на разных инструментах в зависимости от их robustness profile.
Заключение
Multi-symbol валидация — не опция, а обязательный шаг для любой стратегии, претендующей на обобщённый рыночный edge. Ключевые выводы:
-
Стратегия, работающая только на одном символе, скорее всего переобучена на специфику этого символа. Исключения: маркет-мейкинг, арбитраж, стратегии на уникальных свойствах актива.
-
Группировка по тирам обязательна. Нельзя сравнивать результат на BTC (Tier 1) с результатом на PEPE (Tier 3) без понимания разницы в волатильности, ликвидности и микроструктуре.
-
Adaptive parameter scaling — масштабирование порогов по волатильности — значительно повышает реалистичность multi-symbol тестирования.
-
CSRS > 0.5 — разумный минимальный порог. Стратегия должна быть прибыльна на >= 60% символов того же тира, а средний PnL по всем символам — положительный.
-
Walk-forward + Multi-symbol + Monte Carlo — три ортогональных оси валидации. Каждый метод ловит то, что пропускают другие. Используйте все три.
Стратегия с PnL +25% и CSRS 0.72 надёжнее стратегии с PnL +300% и CSRS 0.18. Первая зарабатывает на рыночной неэффективности. Вторая — на запоминании одного ценового ряда.
Полезные ссылки
- Lopez de Prado, M. — Advances in Financial Machine Learning (Wiley)
- Pardo, R. — The Evaluation and Optimization of Trading Strategies (Wiley)
- Bailey, D.H. et al. — The Probability of Backtest Overfitting
- Aronson, D.R. — Evidence-Based Technical Analysis
- Kevin Davey — Building Winning Algorithmic Trading Systems (Wiley)
- Harvey, C.R. & Liu, Y. — Backtesting (2015)
- Chan, E. — Algorithmic Trading: Winning Strategies and Their Rationale (Wiley)
- Binance Research — Cryptocurrency Correlation Analysis
- NumPy — numpy.random.choice
- Pandas — DataFrame
Цитирование
@article{soloviov2026multisymbolvalidation,
author = {Soloviov, Eugen},
title = {Multi-symbol валидация: проверяйте стратегию на всех парах},
year = {2026},
url = {https://marketmaker.cc/ru/blog/post/multi-symbol-validation},
version = {0.1.0},
description = {Почему стратегия, оптимизированная на ETHUSDT, может провалиться на альткоинах. Как правильно тестировать по группам пар (blue chips, large caps, шиткоины) и какой cross-symbol robustness score считать достаточным.}
}
MarketMaker.cc Team
Количественные исследования и стратегии