Multi-symbol validatie: test je strategie op alle paren
Artikel uit de reeks "Backtests zonder illusies"
Je hebt een strategie geoptimaliseerd op ETHUSDT. 25 maanden aan data, 12+ parameters. De backtest laat een PnL van +55%, 500 trades, MaxDD van -0,9% zien, positie 15% van de tijd open. De equity-curve stijgt gestaag. De parameters zijn geslaagd voor de plateau-analyse — het optimum ziet er breed uit. Walk-forward levert een WFER > 0,6 op. Monte Carlo bootstrap toont een positief 5e percentiel.
Alles is perfect. Op één ding na: je hebt de strategie op één enkel instrument getest.
Je start hetzelfde algoritme met dezelfde parameters op BTCUSDT — PnL +8%. Op SOLUSDT — PnL -12%. Op DOGEUSDT — PnL -34%. De strategie die alle controles op ETH doorstond, blijkt op de meeste andere paren onrendabel.
Dit is geen bug. Dit is de single-symbol-val — een van de meest voorkomende en verraderlijke vormen van overfitting in algotrading.
De val van het enkele instrument

Een strategie optimaliseren op één enkel symbool komt er in feite op neer dat je haar aanpast aan de koersdynamiek van een specifiek activum. Zelfs als je walk-forward hebt uitgevoerd, zelfs als bootstrap brede betrouwbaarheidsintervallen toont — al deze controles werden uitgevoerd binnen één enkele tijdreeks.
Walk-forward controleert robuustheid over tijd: werken de parameters op toekomstige data van hetzelfde instrument. Monte Carlo controleert robuustheid over de volgorde van trades: kan de strategie een andere sequentie doorstaan. Maar geen van deze methoden controleert robuustheid over instrumenten: werkt de strategie op andere activa met andere kenmerken.
Als een strategie alleen op ETHUSDT winstgevend is, heeft ze geen marktinefficiëntie gevangen, maar de specifieke structuur van de prijsreeks van ETH:
- Kenmerkende candlestick-patronen die uniek zijn voor ETH
- Specifieke volatiliteitsniveaus waarop de drempels zijn afgestemd
- De liquiditeits- en microstructuurspecifieke kenmerken van dit ene paar
- Correlatie met BTC, kenmerkend voor een bepaalde periode
Niets hiervan is een edge. Dit is curve fitting op instrumentniveau.
Symbolengroepen (tiers) in de cryptomarkt

Niet alle cryptovaluta zijn gelijk. Voor een zinvolle multi-symbol validatie moet je begrijpen dat instrumenten worden onderverdeeld in groepen met fundamenteel verschillende kenmerken.
Tier 1: Blue chips (BTC, ETH)
Hoge liquiditeit, relatief lage volatiliteit, institutionele flow. Correlatie met macro (S&P 500, DXY, Fed-rentes). Diepe orderboeken, krappe spreads, stabiele funding rates. Typische dagelijkse volatiliteit: 2-4%.
Tier 2: Large caps (SOL, BNB, ADA, XRP, AVAX)
Matige liquiditeit, verhoogde volatiliteit. Bewegingen worden vaak gedreven door sectordynamiek (L1 vs L2, DeFi vs infra). Funding rates zijn volatieler. Spreads zijn breder. Typische dagelijkse volatiliteit: 4-6%.
Tier 3: Mid caps (DOGE, SHIB, PEPE, ARB, OP)
Meme coins en narratieve tokens. Hoge volatiliteit, lage correlatie met fundamentele factoren. Bewegingen worden bepaald door social media, listings, narratieven. Dunne orderboeken op sommige exchanges. Typische dagelijkse volatiliteit: 6-10%.
Tier 4: Low caps (nieuwe listings)
Extreme volatiliteit, dunne orderboeken, manipulatierisico. Vaak onvoldoende historie voor een volledige backtest. Typische dagelijkse volatiliteit: 10-20%+.
Samenvattende tabel van kenmerken
| Kenmerk | Tier 1 | Tier 2 | Tier 3 | Tier 4 |
|---|---|---|---|---|
| Dagelijkse volatiliteit | 2-4% | 4-6% | 6-10% | 10-20%+ |
| Gemiddelde spread (perps) | 0.01-0.02% | 0.02-0.05% | 0.05-0.15% | 0.1-0.5%+ |
| Orderboekdiepte (top 5 bps) | $5-50M | $1-10M | $100K-2M | $10K-200K |
| Funding rate (gem. abs.) | 0.005-0.01% | 0.01-0.03% | 0.02-0.08% | 0.05-0.2%+ |
| Correlatie met BTC | 0.85-0.95 | 0.6-0.85 | 0.3-0.7 | 0.1-0.5 |
| Minimale historie | 5+ jaar | 2-5 jaar | 6 mnd - 3 jaar | < 6 mnd |
Elke tier is een eigen "wereld" met haar eigen microstructuur. Een strategie afgestemd op Tier 1 komt in een vreemde omgeving terecht bij verplaatsing naar Tier 3.
Methodologie voor multi-symbol validatie

Stap 1: Optimaliseren op één symbool
Kies een symbool voor optimalisatie — bijvoorbeeld ETHUSDT. Voer de volledige pipeline uit: Optuna-optimalisatie, plateau-analyse, walk-forward. Zet de parameters vast.
Stap 2: Testen op symbolen uit dezelfde tier
Voer de strategie uit met dezelfde parameters op 5-10 symbolen uit dezelfde tier. Voor Tier 1 is dit beperkt (BTC + ETH), maar voor Tier 2 en Tier 3 zijn er genoeg symbolen.
Stap 3: Testen op symbolen uit andere tiers
Voer de strategie uit op 3-5 symbolen uit elke andere tier. Dit is de zwaarste test: als de strategie werkt op ETHUSDT (Tier 1) en op DOGEUSDT (Tier 3), is de kans op curve fitting minimaal.
Stap 4: Resultaten per groep analyseren
Aggregeer de metrics per tier en beoordeel de cross-symbol robuustheid.
Metrics voor elk symbool
Registreer voor elk symbool:
- PnL — totaalrendement
- MaxDD — maximale drawdown
- N trades — aantal trades
- Win rate — aandeel winstgevende trades
- PnL/actieve dag — rendement per eenheid actieve tijd (meer details in PnL per actieve tijd)
Slagingscriteria
Een strategie slaagt voor multi-symbol validatie als:
- Winstgevend op >= 60% van de symbolen in dezelfde tier
- De gemiddelde PnL over de groep positief is
- MaxDD niet drastisch toeneemt (niet meer dan 2-3x ten opzichte van het optimalisatiesymbool)
- Als de strategie ALLEEN op het optimalisatiesymbool winstgevend is — afwijzen
Voorbeeld: drie strategieën, drie uitkomsten

Laten we een concreet voorbeeld bekijken. Drie strategieën (Strategie A, Strategie B, Strategie C), geoptimaliseerd op ETHUSDT, getest op 12 symbolen verspreid over vier tiers.
Strategie A (geoptimaliseerd op ETHUSDT)
Parameters: PnL +55%, ~500 trades, ~15% actieve tijd, MaxDD ~0,9%.
| Symbool | Tier | PnL | MaxDD | N trades | Win rate | PnL/actieve dag |
|---|---|---|---|---|---|---|
| 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% |
* — optimalisatiesymbool
Resultaten per tier:
| Tier | Symbolen | Winstgevend | Gem. PnL | Gem. 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% |
Verdict: Strategie A werkt op Tier 1-2, maar faalt volledig op Tier 3. Dit is een typische strategie afgestemd op een omgeving met lage volatiliteit. Voor een portfolio van blue chips en large caps — acceptabel. Voor universeel gebruik — nee.
Strategie B (geoptimaliseerd op ETHUSDT)
Parameters: PnL +25%, ~40 trades, ~5% actieve tijd.
| Symbool | 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% |
Resultaten per tier:
| Tier | Symbolen | Winstgevend | Gem. PnL | Gem. 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% |
Verdict: Strategie B is winstgevend op 9 van de 11 symbolen (82%). De gemiddelde PnL is positief over alle tiers. MaxDD groeit voorspelbaar met de tier. Dit is een robuuste strategie met een echte marktedge. Ondanks de bescheidener PnL op het optimalisatiesymbool (+25% versus +55%) is Strategie B aanzienlijk betrouwbaarder dan Strategie A.
Strategie C (geoptimaliseerd op ETHUSDT)
Parameters: PnL +300%, ~400 trades, ~45% actieve tijd, MaxDD ~17%.
| Symbool | 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% |
Verdict: Strategie C is klassieke overfitting. +301% op ETHUSDT, maar catastrofale verliezen op de meeste andere paren. MaxDD op Tier 3 overschrijdt 70% — dit is kapitaalvernietiging. De strategie ving unieke patronen van ETH, geen marktinefficiëntie. Afwijzen.
Waarom strategieën falen op andere symbolen

1. Volatiliteitsmismatch
De meest voorkomende reden. De strategieparameters zijn afgestemd op een specifiek volatiliteitsniveau. Als de strategie een entreedrempel van 2% gebruikt — is dit voor ETH met 3% dagelijkse volatiliteit een redelijk filter. Voor DOGE met 8% dagelijkse volatiliteit triggert deze drempel te vaak, wat een massa valse signalen genereert.
Evenzo is een stop loss van 1% adequaat voor ETH, maar voor PEPE is dit normale "ruis", en de stop wordt tientallen keren per dag geraakt.
2. Liquiditeitsverschillen
De strategie gaat uit van directe orderuitvoering tegen de huidige prijs. Bij BTCUSDT met 200K diepte — zal jouw order van $10K de prijs bewegen, en de daadwerkelijke uitvoering zal 0,05-0,2% slechter zijn. Over 500 trades betekent dit 25-100% verlies alleen al door slippage.
3. Marktmicrostructuur
Elk instrument heeft zijn eigen microstructuur:
- Funding rates: bij BTC is de funding consistent positief in een bullmarkt (+0,01% elke 8 uur). Bij meme coins kan de funding springen van -0,3% naar +0,5%. Meer details in Funding rates vreten je leverage op.
- Spread: op Tier 1 is de spread 0,01%, op Tier 4 — 0,5%. Een strategie met kleine take-profits kan niet winstgevend zijn wanneer de spread de take-omvang overschrijdt.
- Manipulatiepatronen: wicks, spoofing, wash trading — manifesteren zich anders op elke tier.
4. Regimegevoeligheid
Altcoins gedragen zich anders in verschillende marktfasen:
- In een bulltrend presteren altcoins beter dan BTC (bèta > 1)
- In een beertrend vallen altcoins harder dan BTC
- In een zijwaartse markt kunnen altcoins correleren met BTC of bewegen op basis van hun eigen narratieven
Een strategie geoptimaliseerd in één fase op één symbool kan optimaal zijn afgestemd op de lag/lead van precies dat symbool ten opzichte van BTC — en deze lag/lead zal veranderen wanneer het regime verschuift.
Adaptieve parameterschaling

Een strategie met identieke parameters op alle symbolen uitvoeren is onjuist. Maar een volledige heroptimalisatie op elk symbool druist in tegen het hele doel van multi-symbol validatie (parameters worden "inheems" aan elk symbool).
Het compromis is parameternormalisatie op basis van volatiliteit:
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:
"""
Scale strategy parameters by target symbol volatility.
Args:
base_params: parameters optimized on the original symbol
optimization_symbol_vol: daily volatility of the optimization symbol
target_symbol_vol: daily volatility of the target symbol
vol_sensitive_params: list of volatility-sensitive parameters
"""
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% — entry threshold
"stop_loss": 0.01, # 1% — stop loss
"take_profit": 0.03, # 3% — take profit
"trailing_stop": 0.008, # 0.8% — trailing stop
"atr_multiplier": 2.5, # ATR multiplier (not scaled)
"rsi_period": 14, # RSI period (not scaled)
"ma_fast": 10, # fast MA (not scaled)
"ma_slow": 50, # slow MA (not scaled)
}
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})
Uitvoer:
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'}
De stop loss steeg van 1% naar 2,53% — passend bij de dagelijkse volatiliteit van 8,1% van DOGE. Zonder schaling zou een stop van 1% tientallen keren geraakt worden door "ruis".
Belangrijk: schaal alleen prijsdrempels (entries, stops, takes). Indicatorperiodes (RSI, MA) en multipliers (ATR-multiplier) worden meestal niet geschaald — ze zijn al genormaliseerd op volatiliteit via de indicator zelf.
Twee validatiemodi
-
Strikte modus (zonder schaling): uitvoeren met identieke parameters. Een test van absolute robuustheid. Als de strategie winstgevend is — is de edge sterk.
-
Adaptieve modus (met schaling): uitvoeren met genormaliseerde parameters. Een test van de robuustheid van de strategielogica, rekening houdend met het feit dat volatiliteitsniveaus verschillen.
We raden aan beide tests uit te voeren. Strikte modus — om de "kracht" van de edge te beoordelen. Adaptieve modus — voor praktische toepassing.
Cross-symbol robuustheidsscore

Voor een kwantitatieve beoordeling van multi-symbol robuustheid introduceren we een samengestelde metric — de Cross-Symbol Robustness Score (CSRS).
Formule
waarbij:
- — aandeel winstgevende symbolen:
- — genormaliseerde, op liquiditeit gewogen gemiddelde PnL:
waarbij de liquiditeit is van symbool (gemiddeld dagelijks volume).
- — bonus voor cross-tier consistentie:
- — boete voor hoge PnL-variantie tussen symbolen:
Standaardgewichten
| Component | Gewicht | Motivatie |
|---|---|---|
| (winstgevend aandeel) | 0.35 | Het belangrijkst: strategie moet werken voor de meerderheid |
| (gem. PnL) | 0.25 | Absolute rendementen |
| (cross-tier) | 0.25 | Bonus voor universaliteit |
| (variantieboete) | 0.15 | Boete voor instabiliteit |
CSRS-interpretatie
| CSRS | Interpretatie |
|---|---|
| > 0.7 | Uitstekende robuustheid. Strategie werkt op de meeste instrumenten. |
| 0.5 — 0.7 | Goede robuustheid. Strategie werkt binnen haar tier en gedeeltelijk bij andere. |
| 0.3 — 0.5 | Grensgeval. Strategie werkt op een smalle set symbolen. |
| < 0.3 | Lage robuustheid. Curve fitting op instrumentniveau is waarschijnlijk. |
Volledige implementatie: multi-symbol validatiepipeline

import numpy as np
import pandas as pd
from dataclasses import dataclass, field
from typing import Callable, Optional
@dataclass
class SymbolResult:
"""Strategy result on a single symbol."""
symbol: str
tier: int
pnl: float
max_dd: float
n_trades: int
win_rate: float
pnl_per_active_day: float
avg_daily_volume: float # liquidity
@dataclass
class TierResult:
"""Aggregated result by tier."""
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:
"""Full multi-symbol validation result."""
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:
"""
Full multi-symbol validation pipeline.
Args:
strategy_fn: strategy function (data, params) -> (pnl, max_dd, n_trades, win_rate, returns)
base_params: parameters optimized on optimization_symbol
optimization_symbol: optimization symbol
data_loader: data loading function (symbol) -> np.ndarray
vol_sensitive_params: parameters to scale by volatility
adaptive: use volatility scaling
csrs_weights: weights (w1, w2, w3, w4) for CSRS
min_profit_ratio: minimum fraction of profitable symbols in a tier
"""
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) # rough estimate
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) # cap the penalty
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:
"""Generate text report."""
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)
Voorbeeld van pipelinegebruik
def my_strategy(data, params):
"""Your strategy. Returns (pnl, max_dd, n_trades, win_rate, returns)."""
pass
def load_ohlcv(symbol):
"""Load OHLCV data for a symbol."""
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}")
Wanneer single-symbol validatie acceptabel is

Niet elke strategie hoeft op meerdere instrumenten te werken. Er zijn legitieme gevallen waarin single-symbol een normale aanpak is:
Market making op een specifiek orderboek
Een market-making strategie (bijvoorbeeld met het Avellaneda-Stoikov-model) is per definitie gebonden aan een specifiek orderboek. Parameters hangen af van de specifieke microstructuur: diepte, spread, wachtrijpositie, fill rate. Testen op een ander symbool is zinloos — het is een ander orderboek.
Arbitrage tussen specifieke paren
Funding rate arbitrage of cross-exchange arbitrage is per definitie gebonden aan specifieke instrumentparen. Validatie vindt hier plaats op andere exchanges met dezelfde paren, niet op andere symbolen.
Strategieën die expliciet unieke eigenschappen van een activum gebruiken
Als een strategie is gebaseerd op een specifieke eigenschap van één activum (bijvoorbeeld de correlatie van BTC met de hashrate of van ETH met gasfees), is multi-symbol validatie niet van toepassing. Maar dergelijke strategieën zijn zeldzaam.
In alle andere gevallen — als de strategie gebaseerd is op "generieke" signalen (MA-crossover, RSI, momentum, mean reversion) — is multi-symbol validatie verplicht. Als een generieke strategie alleen op één symbool werkt, is dat geen edge — het is overfitting.
Relatie met andere validatiemethoden

Multi-symbol validatie is een van drie orthogonale methoden van out-of-sample testen:
| Methode | Validatie-as | Wat het onthult |
|---|---|---|
| Walk-Forward | Tijd | Overfitting op een specifieke periode |
| Multi-symbol | Instrument | Overfitting op een specifiek activum |
| Monte Carlo bootstrap | Volgorde van trades | Afhankelijkheid van een specifieke sequentie |
Elke methode controleert robuustheid langs haar eigen as. Een strategie kan slagen voor walk-forward maar falen op multi-symbol (curve fitting op het instrument). Ze kan slagen voor multi-symbol maar falen op Monte Carlo (afhankelijk van een gelukkige tradevolgorde).
Maximale bescherming tegen overfitting: gebruik alle drie de methoden.
Volledige validatiepipeline:
- Optimalisatie van parameters op één symbool
- Plateau-analyse — controle van optimum-stabiliteit
- Walk-forward — validatie langs de tijdas (WFER > 0,5)
- Multi-symbol — validatie langs de instrumentas (CSRS > 0,5)
- Monte Carlo bootstrap — betrouwbaarheidsintervallen (5e percentiel > 0)
- Rekening houden met funding rates en verlies-winst asymmetrie
Een strategie die alle zes controles doorstaat, heeft een minimale kans om een overfitting-artefact te zijn.
Uitbreidingen: symboolcorrelatie en cascade-strategieën

Multi-symbol validatie onthult nog een ander aspect: correlaties tussen symbolen. Als een strategie winstgevend is op BTC en ETH maar onrendabel op alle altcoins — is dit informatie dat de edge gebonden is aan de hoge BTC-ETH-correlatie. Gedetailleerde analyse van correlatiestructuren — in het artikel Signaalcorrelatie en pairs trading.
Voor strategieportfolio's bepalen multi-symbol resultaten op welke instrumenten een strategie moet worden gelanceerd. Strategie A uit het voorbeeld hierboven — alleen Tier 1-2. Strategie B — Tier 1-3. Dit is invoerdata voor cascade-orchestratie, waarbij verschillende strategieën op verschillende instrumenten worden gelanceerd afhankelijk van hun robuustheidsprofiel.
Conclusie
Multi-symbol validatie is niet optioneel — het is een verplichte stap voor elke strategie die een gegeneraliseerde marktedge claimt. Belangrijkste conclusies:
-
Een strategie die alleen op één symbool werkt, is hoogstwaarschijnlijk overfit op de specifieke kenmerken van dat symbool. Uitzonderingen: market making, arbitrage, strategieën gebaseerd op unieke eigenschappen van een activum.
-
Tier-groepering is verplicht. Je kunt resultaten op BTC (Tier 1) niet vergelijken met resultaten op PEPE (Tier 3) zonder de verschillen in volatiliteit, liquiditeit en microstructuur te begrijpen.
-
Adaptieve parameterschaling — drempelnormalisatie op basis van volatiliteit — verbetert het realisme van multi-symbol testen aanzienlijk.
-
CSRS > 0,5 — een redelijke minimumdrempel. De strategie zou winstgevend moeten zijn op >= 60% van de symbolen in dezelfde tier, en de gemiddelde PnL over alle symbolen zou positief moeten zijn.
-
Walk-forward + multi-symbol + Monte Carlo — drie orthogonale validatie-assen. Elke methode vangt wat de andere missen. Gebruik alle drie.
Een strategie met PnL +25% en CSRS 0,72 is betrouwbaarder dan een strategie met PnL +300% en CSRS 0,18. De eerste verdient aan marktinefficiëntie. De tweede verdient aan het uit het hoofd leren van één enkele prijsreeks.
Nuttige links
- 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
Citatie
@article{soloviov2026multisymbolvalidation,
author = {Soloviov, Eugen},
title = {Multi-Symbol Validation: Test Your Strategy on All Pairs},
year = {2026},
url = {https://marketmaker.cc/en/blog/post/multi-symbol-validation},
version = {0.1.0},
description = {Why a strategy optimized on ETHUSDT may fail on altcoins. How to properly test across pair groups (blue chips, large caps, shitcoins) and what cross-symbol robustness score to consider sufficient.}
}
Auteurs
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.