← 返回文章列表
March 10, 2026
5 分鐘閱讀

多品種驗證:在所有交易對上檢驗你的策略

多品種驗證:在所有交易對上檢驗你的策略
#演算法交易
#回測
#驗證
#multi-symbol
#分散化
#加密貨幣

"無幻覺回測"系列文章

你在ETHUSDT上優化了策略。25個月的資料,12+個參數。回測顯示PnL +55%,500筆交易,MaxDD -0.9%,持倉時間佔15%。權益曲線平滑上升。參數通過了plateau分析——最優解看起來範圍很寬。Walk-forward給出WFER > 0.6。蒙特卡洛自助法顯示第5百分位為正。

一切看起來完美。除了一點:你只在一個品種上測試了策略。

用相同的演算法和相同的參數在BTCUSDT上執行——PnL +8%。在SOLUSDT上——PnL -12%。在DOGEUSDT上——PnL -34%。一個通過了所有ETH檢驗的策略,在大多數其他交易對上都是虧損的。

這不是bug。這是單品種陷阱(single-symbol trap)——演算法交易中最常見且最隱蔽的過擬合形式之一。

單一品種的陷阱

單品種陷阱:一條明亮的收益曲線被其他資產上失敗的策略包圍

在單一品種上最佳化策略,本質上就是對特定資產的價格動態進行擬合。即使你進行了walk-forward,即使自助法顯示了寬置信區間——所有這些檢驗都是在同一個時間序列內部完成的。

Walk-forward檢驗的是時間維度的魯棒性:參數在同一品種的未來資料上是否有效。蒙特卡洛檢驗的是交易順序維度的魯棒性:策略能否承受不同的交易序列。但這兩種方法都無法檢驗品種維度的魯棒性:策略在具有不同特徵的其他資產上是否有效。

如果策略只在ETHUSDT上盈利——它捕獲的不是市場低效性,而是ETH價格序列的特定結構:

  • ETH獨有的K線形態
  • 針對特定波動率水平調整的閾值
  • 該交易對特有的流動性和微觀結構
  • 特定時期內與BTC的相關性

這些都不是edge,而是品種層面的曲線擬合。

加密市場的品種分組(tiers)

Symbol tier characteristics matrix

並非所有加密貨幣都是相同的。要進行有意義的多品種驗證,必須理解品種按具有根本不同特徵的組別進行劃分。

Tier 1:藍籌(BTC、ETH)

高流動性,相對較低的波動率,機構資金流。與宏觀因素相關(S&P 500、DXY、美聯儲利率)。深度訂單簿,窄價差,穩定的資金費率。典型日波動率:2-4%。

Tier 2:大市值(SOL、BNB、ADA、XRP、AVAX)

中等流動性,較高波動率。行情通常由板塊動態驅動(L1 vs L2,DeFi vs 基礎設施)。資金費率波動更大。價差更寬。典型日波動率:4-6%。

Tier 3:中等市值(DOGE、SHIB、PEPE、ARB、OP)

Meme幣和敘事型代幣。高波動率,與基本面因素的相關性低。行情由社交媒體、上線公告、敘事驅動。部分交易所訂單簿較薄。典型日波動率:6-10%。

Tier 4:小市值(新上線代幣)

極端波動率,薄訂單簿,存在操縱風險。通常沒有足夠的歷史資料進行完整回測。典型日波動率:10-20%+。

特徵彙總表

特徵 Tier 1 Tier 2 Tier 3 Tier 4
日波動率 2-4% 4-6% 6-10% 10-20%+
平均價差(永續合約) 0.01-0.02% 0.02-0.05% 0.05-0.15% 0.1-0.5%+
訂單簿深度(前5 bps) $5-50M $1-10M $100K-2M $10K-200K
資金費率(平均絕對值) 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都是一個擁有獨特微觀結構的"世界"。針對Tier 1調整的策略,在切換到Tier 3時會進入一個完全陌生的環境。

多品種驗證方法論

多品種驗證方法論:最佳化、同tier測試、跨tier測試、分析結果

步驟1:在單一品種上最佳化

選擇一個品種進行最佳化——例如ETHUSDT。執行完整的流程:Optuna最佳化plateau分析walk-forward。鎖定參數。

步驟2:在同tier品種上測試

相同的參數在同tier的5-10個品種上執行策略。對於Tier 1來說選擇有限(BTC + ETH),但Tier 2和Tier 3有足夠多的品種。

步驟3:在其他tier品種上測試

在每個其他tier的3-5個品種上執行策略。這是最嚴格的測試:如果策略在ETHUSDT(Tier 1)和DOGEUSDT(Tier 3)上都有效,曲線擬合的可能性極低。

步驟4:按組分析結果

按tier彙總指標並評估cross-symbol魯棒性。

每個品種的指標

對每個品種記錄:

  • PnL — 最終收益率
  • MaxDD — 最大回撤
  • N trades — 交易次數
  • Win rate — 盈利交易比例
  • PnL/active day — 每單位活躍時間的收益率(詳見按活躍時間計算PnL

通過標準

策略通過多品種驗證的條件:

  1. 在同tier >= 60%的品種上盈利
  2. 該組的平均PnL為正
  3. MaxDD不會急劇增加(相對於最佳化品種不超過2-3倍)
  4. 如果策略僅在最佳化品種上盈利——拒絕

示例:三個策略,三種結果

三種策略對比:A(綠色,部分成功)、B(青色,穩健)、C(紅色,過擬合)

來看一個具體示例。三個策略(Strategy A、Strategy B、Strategy C),在ETHUSDT上最佳化,在四個tier的12個品種上測試。

Strategy A(在ETHUSDT上最佳化)

參數:PnL +55%,約500筆交易,約15%活躍時間,MaxDD約0.9%。

品種 Tier PnL MaxDD 交易數 勝率 PnL/活躍日
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結果:

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上完全失敗。這是典型的針對低波動率環境調整的策略。用於藍籌和大市值組合——可以接受。用於通用目的——不行。

Strategy B(在ETHUSDT上最佳化)

參數:PnL +25%,約40筆交易,約5%活躍時間。

品種 Tier PnL MaxDD 交易數 勝率
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結果:

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在11個品種中有9個盈利(82%)。所有tier的平均PnL均為正。MaxDD隨tier級別可預測地增長。這是一個具有真實市場edge的魯棒策略。儘管在最佳化品種上的PnL較為溫和(+25% vs +55%),Strategy B遠比Strategy A可靠。

Strategy C(在ETHUSDT上最佳化)

參數:PnL +300%,約400筆交易,約45%活躍時間,MaxDD約17%。

品種 Tier PnL MaxDD 交易數 勝率
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是典型的過擬合。在ETHUSDT上+301%,但在大多數其他交易對上出現災難性虧損。Tier 3的MaxDD超過70%——這意味著資金毀滅。策略捕獲了ETH獨有的模式,而非市場低效性。拒絕。

策略在其他品種上失效的原因

導致策略失效的四個因素:波動率、流動性、微觀結構和市場狀態轉換

1. 波動率不匹配

最常見的原因。策略參數針對特定的波動率水平進行了調整。如果策略使用2%的入場閾值——對於日波動率3%的ETH來說,這是合理的過濾器。但對於日波動率8%的DOGE來說——這個閾值觸發過於頻繁,產生大量虛假訊號。

同樣,1%的止損對ETH來說是合理的,但對PEPE來說這只是正常的"噪音",止損會在一天內被觸發數十次。

2. 流動性差異

策略假設訂單按當前價格即時成交。在訂單簿深度為50M5bps范围内)的BTCUSDT上——这是现实的。在深度仅50M(5 bps范围内)的BTCUSDT上——这是现实的。在深度仅200K的ARBUSDT上——你$10K的訂單會推動價格,實際成交價會差0.05-0.2%。500筆交易下來,僅滑點就會造成25-100%的損失。

3. 市場微觀結構

每個品種都有自己的微觀結構:

  • 資金費率: 在牛市中,BTC的資金費率穩定為正(每8小時+0.01%)。Meme幣的資金費率可能在-0.3%到+0.5%之間劇烈波動。詳見資金費率如何吞噬你的槓桿
  • 價差: Tier 1的價差為0.01%,Tier 4為0.5%。止盈較小的策略在價差超過止盈幅度時無法盈利。
  • 操縱模式: 插針、欺騙掛單、刷量交易——在每個tier中表現不同。

4. 市場狀態敏感性

山寨幣在不同市場階段表現各異:

  • 在牛市中,山寨幣跑贏BTC(beta > 1)
  • 在熊市中,山寨幣跌幅超過BTC
  • 在橫盤中,山寨幣可能與BTC相關,也可能按自身敘事波動

在某一階段對某一品種最佳化的策略,可能恰好針對該品種相對於BTC的領先/滯後關係進行了最優調整——而這種領先/滯後關係在市場狀態切換時會改變。

自適應參數縮放

自適應參數縮放:波動率比率儀表盤,參數滑塊從窄閾值變換為寬閾值

用完全相同的參數在所有品種上執行策略是不正確的。但對每個品種進行完全重新最佳化會使多品種驗證本身失去意義(參數會變成每個品種"自己的")。

折中方案是按波動率歸一化參數

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%——對於日波動率8.1%的DOGE來說是合理的。不進行縮放的話,1%的止損會因為"噪音"被觸發數十次。

重要: 只縮放價格閾值(入場、止損、止盈)。指標週期(RSI、MA)和乘數(ATR multiplier)通常不需要縮放——它們通過指標本身已經按波動率歸一化了。

兩種驗證模式

  1. 嚴格模式(不縮放): 使用完全相同的參數執行。測試絕對魯棒性。如果策略仍然盈利——edge很強。

  2. 自適應模式(帶縮放): 使用歸一化後的參數執行。測試策略邏輯的魯棒性,允許波動率水平存在差異。

建議兩種測試都進行。嚴格模式——評估edge的"強度"。自適應模式——用於實際應用。

Cross-symbol魯棒性評分

Multi-symbol cross-robustness radar

為了量化評估多品種魯棒性,我們引入一個複合指標——Cross-Symbol Robustness Score (CSRS)

公式

CSRS=w1Rprofit+w2Rpnl+w3Pconsistencyw4Pvariance\text{CSRS} = w_1 \cdot R_{profit} + w_2 \cdot R_{pnl} + w_3 \cdot P_{consistency} - w_4 \cdot P_{variance}

其中:

  • RprofitR_{profit} — 盈利品種佔比:

Rprofit=NprofitableNtotalR_{profit} = \frac{N_{profitable}}{N_{total}}

  • RpnlR_{pnl} — 歸一化加權平均PnL(按流動性加權):

Rpnl=i=1NliPnLii=1NliR_{pnl} = \frac{\sum_{i=1}^{N} l_i \cdot \text{PnL}_i}{\sum_{i=1}^{N} l_i}

其中 lil_i 為品種 ii 的流動性(平均日成交量)。

  • PconsistencyP_{consistency} — 跨tier一致性獎勵:

Pconsistency=Nprofitable_tiersNtotal_tiersP_{consistency} = \frac{N_{profitable\_tiers}}{N_{total\_tiers}}

  • PvarianceP_{variance} — 品種間PnL高方差懲罰:

Pvariance=σ(PnL1,,PnLN)max(PnLˉ,0.01)P_{variance} = \frac{\sigma(\text{PnL}_1, \ldots, \text{PnL}_N)}{\max(|\bar{\text{PnL}}|, 0.01)}

預設權重

組成部分 權重 依據
w1w_1(盈利佔比) 0.35 最重要:策略必須在大多數品種上有效
w2w_2(平均PnL) 0.25 絕對收益率
w3w_3(跨tier一致性) 0.25 通用性獎勵
w4w_4(方差懲罰) 0.15 不穩定性懲罰

CSRS解讀

CSRS 解讀
> 0.7 優秀的魯棒性。策略在大多數品種上有效。
0.5 — 0.7 良好的魯棒性。策略在自身tier和部分其他tier上有效。
0.3 — 0.5 臨界水平。策略僅在少數品種上有效。
< 0.3 低魯棒性。可能存在品種層面的曲線擬合。

完整實現:多品種驗證流水線

等距3D資料處理流水線用於多品種策略驗證

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汇总的结果。"""
    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:
    """多品种验证的完整结果。"""
    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:
    """
    完整的多品种验证流水线。

    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: CSRS的权重 (w1, w2, w3, w4)
        min_profit_ratio: 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)  # 粗略估计
            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))  # 限制在[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)

流水線使用示例

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}")

何時可以接受單品種驗證

例外情況:做市商訂單簿、跨交易所套利和資產特定相關性模式

並非每個策略都必須在多個品種上有效。在以下合理情況下,單品種驗證是正常的做法:

特定訂單簿上的做市

做市策略(例如基於Avellaneda-Stoikov模型)天然繫結到特定訂單簿。參數依賴於具體的微觀結構:深度、價差、佇列位置、成交率。在其他品種上測試沒有意義——那是另一個訂單簿。

特定交易對之間的套利

資金費率套利跨交易所套利天然繫結到特定的品種對。這裡的驗證應該在相同交易對的不同交易所上進行,而非在不同品種上。

明確利用資產獨有屬性的策略

如果策略基於某個資產的特定屬性(例如BTC與算力的相關性,或ETH與gas費的相關性),多品種驗證不適用。但這類策略非常少見。

在所有其他情況下——如果策略基於"通用"訊號(MA交叉、RSI、動量、均值迴歸)——多品種驗證是必須的。如果通用策略只在一個品種上有效,這不是edge——這是過擬合。

與其他驗證方法的關係

三個正交驗證軸:時間(walk-forward)、品種(multi-symbol)、交易順序(蒙特卡洛)

多品種驗證是三種正交的樣本外測試方法之一:

方法 檢驗維度 發現的問題
Walk-Forward 時間 對特定時期的過擬合
多品種驗證 品種 對特定資產的過擬合
蒙特卡洛自助法 交易順序 對特定交易序列的依賴

每種方法沿各自的維度檢驗魯棒性。策略可能通過walk-forward,但在多品種驗證上失敗(對品種的曲線擬合)。可能通過多品種驗證,但在蒙特卡洛上失敗(依賴於特定的交易順序)。

最大程度防止過擬合:三種方法全部使用。

完整驗證流水線:

  1. 在單一品種上最佳化參數
  2. Plateau分析——檢驗最優解的穩定性
  3. Walk-forward——時間維度檢驗(WFER > 0.5)
  4. 多品種驗證——品種維度檢驗(CSRS > 0.5)
  5. 蒙特卡洛自助法——置信區間(第5百分位 > 0)
  6. 考慮資金費率虧損不對稱性

通過全部六項檢驗的策略,成為過擬合產物的機率最小。

擴充:品種相關性與級聯策略

加密貨幣相關性網路圖與級聯策略分配流

多品種驗證還揭示了另一個維度:品種間的相關性。如果策略在BTC和ETH上盈利,但在所有山寨幣上虧損——這說明edge繫結在BTC-ETH的高相關性上。關於相關性結構的詳細分析,請參閱訊號相關性與配對交易

對於策略組合,多品種結果決定了應該在哪些品種上執行策略。上述示例中的Strategy A——僅限Tier 1-2。Strategy B——Tier 1-3。這些是級聯編排的輸入資料,其中不同策略根據其魯棒性特徵在不同品種上執行。

結論

多品種驗證不是可選項,而是任何聲稱具有泛化市場edge的策略的必要步驟。核心要點:

  1. 只在一個品種上有效的策略,很可能對該品種的特性過擬合了。 例外情況:做市、套利、基於資產獨有屬性的策略。

  2. 按tier分組是必須的。 不能在不理解波動率、流動性和微觀結構差異的情況下,將BTC(Tier 1)的結果與PEPE(Tier 3)的結果進行比較。

  3. 自適應參數縮放——按波動率縮放閾值——顯著提高了多品種測試的現實性。

  4. CSRS > 0.5——合理的最低門檻。策略應在同tier >= 60%的品種上盈利,且所有品種的平均PnL為正。

  5. Walk-forward + 多品種驗證 + 蒙特卡洛——三個正交的驗證維度。每種方法能捕獲其他方法遺漏的問題。三者都要使用。

PnL +25%且CSRS 0.72的策略,比PnL +300%且CSRS 0.18的策略更可靠。前者從市場低效性中獲利。後者只是記住了一條價格序列。


參考連結

  1. Lopez de Prado, M. — Advances in Financial Machine Learning (Wiley)
  2. Pardo, R. — The Evaluation and Optimization of Trading Strategies (Wiley)
  3. Bailey, D.H. et al. — The Probability of Backtest Overfitting
  4. Aronson, D.R. — Evidence-Based Technical Analysis
  5. Kevin Davey — Building Winning Algorithmic Trading Systems (Wiley)
  6. Harvey, C.R. & Liu, Y. — Backtesting (2015)
  7. Chan, E. — Algorithmic Trading: Winning Strategies and Their Rationale (Wiley)
  8. Binance Research — Cryptocurrency Correlation Analysis
  9. NumPy — numpy.random.choice
  10. 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上优化的策略可能在山寨币上失败。如何正确按交易对分组(蓝筹、大市值、垃圾币)进行测试,以及什么水平的cross-symbol robustness score才算足够。}
}
免責宣告:本文提供的資訊僅用於教育和參考目的,不構成財務、投資或交易建議。加密貨幣交易涉及重大損失風險。

Authors

Eugen Soloviov
Eugen Soloviov

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.

Newsletter

緊跟市場步伐

訂閱我們的時事通訊,獲取獨家 AI 交易見解、市場分析和平台更新。

我們尊重您的隱私。您可以隨時退訂。