Multi-Symbol Validation: ทดสอบกลยุทธ์ของคุณกับทุกคู่เทรด
บทความจากซีรีส์ "Backtests Without Illusions"
คุณปรับแต่งกลยุทธ์บน ETHUSDT ข้อมูล 25 เดือน พารามิเตอร์ 12+ ตัว ผล backtest แสดง 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 ที่พบบ่อยและอันตรายที่สุดใน algotrading
กับดักเครื่องมือเดียว

การปรับแต่งกลยุทธ์บนสัญลักษณ์เดียวโดยพื้นฐานแล้วคือการ fit กับพลวัตราคาของสินทรัพย์นั้นโดยเฉพาะ แม้คุณจะรัน walk-forward แม้ bootstrap จะแสดง confidence interval กว้าง — การตรวจสอบเหล่านี้ทั้งหมดดำเนินการ ภายใน time series เดียว
Walk-forward ตรวจสอบความทนทานข้าม เวลา: พารามิเตอร์ทำงานกับข้อมูลอนาคตของเครื่องมือเดิมได้ไหม Monte Carlo ตรวจสอบความทนทานข้าม ลำดับไม้: กลยุทธ์ทนต่อลำดับที่ต่างออกไปได้ไหม แต่ไม่มีวิธีใดตรวจสอบความทนทานข้าม เครื่องมือ: กลยุทธ์ทำงานกับสินทรัพย์อื่นที่มีคุณสมบัติต่างกันได้ไหม
ถ้ากลยุทธ์ทำกำไรได้เฉพาะบน ETHUSDT — มันจับได้ไม่ใช่ความไม่มีประสิทธิภาพของตลาด แต่เป็นโครงสร้างเฉพาะของ price series ของ ETH:
- รูปแบบแท่งเทียนที่เป็นลักษณะเฉพาะของ ETH
- ระดับความผันผวนเฉพาะที่ threshold ถูก tune ให้
- ความเจาะจงด้านสภาพคล่องและ microstructure ของคู่เทรดนี้
- ความสัมพันธ์กับ BTC ที่เป็นลักษณะเฉพาะของช่วงเวลาหนึ่ง
สิ่งเหล่านี้ไม่ใช่ edge นี่คือ curve fitting ในระดับเครื่องมือ
กลุ่มสัญลักษณ์ (Tiers) ในตลาด Crypto

ไม่ใช่ว่าสกุลเงินดิจิทัลทุกตัวเท่าเทียมกัน สำหรับ multi-symbol validation ที่มีความหมาย คุณต้องเข้าใจว่าเครื่องมือแบ่งออกเป็นกลุ่มที่มีคุณสมบัติแตกต่างกันโดยพื้นฐาน
Tier 1: Blue Chips (BTC, ETH)
สภาพคล่องสูง ความผันผวนค่อนข้างต่ำ กระแส institutional ความสัมพันธ์กับ macro (S&P 500, DXY, อัตราดอกเบี้ย Fed) Order book ลึก spread แคบ funding rate เสถียร ความผันผวนรายวันทั่วไป: 2-4%
Tier 2: Large Caps (SOL, BNB, ADA, XRP, AVAX)
สภาพคล่องปานกลาง ความผันผวนสูงขึ้น การเคลื่อนไหวมักขับเคลื่อนโดย sector dynamics (L1 vs L2, DeFi vs infra) Funding rate ผันผวนมากขึ้น Spread กว้างขึ้น ความผันผวนรายวันทั่วไป: 4-6%
Tier 3: Mid Caps (DOGE, SHIB, PEPE, ARB, OP)
Meme coin และ narrative token ความผันผวนสูง ความสัมพันธ์กับปัจจัยพื้นฐานต่ำ การเคลื่อนไหวถูกกำหนดโดย social media, listing, narrative Order book บางบน exchange บางแห่ง ความผันผวนรายวันทั่วไป: 6-10%
Tier 4: Low Caps (New Listings)
ความผันผวนสุดขั้ว order book บาง ความเสี่ยงจากการ manipulate ประวัติมักไม่เพียงพอสำหรับ backtest เต็มรูปแบบ ความผันผวนรายวันทั่วไป: 10-20%+
ตารางสรุปคุณสมบัติ
| คุณสมบัติ | Tier 1 | Tier 2 | Tier 3 | Tier 4 |
|---|---|---|---|---|
| ความผันผวนรายวัน | 2-4% | 4-6% | 6-10% | 10-20%+ |
| Spread เฉลี่ย (perps) | 0.01-0.02% | 0.02-0.05% | 0.05-0.15% | 0.1-0.5%+ |
| ความลึก order book (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 คือ "โลก" ที่แยกจากกันด้วย microstructure ของตัวเอง กลยุทธ์ที่ tune สำหรับ Tier 1 เข้าสู่สภาพแวดล้อมแปลกใหม่เมื่อย้ายไป Tier 3
วิธีการ Multi-Symbol Validation

ขั้นตอนที่ 1: ปรับแต่งบนสัญลักษณ์เดียว
เลือกสัญลักษณ์สำหรับการปรับแต่ง เช่น ETHUSDT รัน pipeline เต็มรูปแบบ: Optuna optimization, plateau analysis, walk-forward กำหนดพารามิเตอร์ให้คงที่
ขั้นตอนที่ 2: ทดสอบบนสัญลักษณ์จาก Tier เดิม
รันกลยุทธ์ด้วย พารามิเตอร์เดิม บน 5-10 สัญลักษณ์จาก tier เดิม สำหรับ Tier 1 มีจำกัด (BTC + ETH) แต่สำหรับ Tier 2 และ Tier 3 มีสัญลักษณ์เพียงพอ
ขั้นตอนที่ 3: ทดสอบบนสัญลักษณ์จาก Tier อื่น
รันกลยุทธ์บน 3-5 สัญลักษณ์จากแต่ละ tier อื่น นี่คือการทดสอบที่โหดที่สุด: ถ้ากลยุทธ์ทำงานบน ETHUSDT (Tier 1) และบน DOGEUSDT (Tier 3) ความน่าจะเป็นของ curve fitting นั้นน้อยมาก
ขั้นตอนที่ 4: วิเคราะห์ผลลัพธ์ตามกลุ่ม
รวมเมตริกตาม tier และประเมินความทนทานข้ามสัญลักษณ์
เมตริกสำหรับแต่ละสัญลักษณ์
สำหรับแต่ละสัญลักษณ์ บันทึก:
- PnL — ผลตอบแทนรวม
- MaxDD — drawdown สูงสุด
- N trades — จำนวนไม้
- Win rate — สัดส่วนไม้ที่ทำกำไร
- PnL/active day — ผลตอบแทนต่อหน่วยเวลาที่ active (รายละเอียดใน PnL by active time)
เกณฑ์การผ่าน
กลยุทธ์ผ่าน multi-symbol validation หาก:
- ทำกำไรบน >= 60% ของสัญลักษณ์ใน tier เดิม
- PnL เฉลี่ยในกลุ่มเป็นบวก
- MaxDD ไม่เพิ่มขึ้นอย่างมาก (ไม่เกิน 2-3 เท่าเทียบกับสัญลักษณ์ที่ใช้ปรับแต่ง)
- ถ้ากลยุทธ์ทำกำไรเฉพาะบนสัญลักษณ์ที่ปรับแต่ง — ปฏิเสธ
ตัวอย่าง: สามกลยุทธ์ สามผลลัพธ์

ลองดูตัวอย่างที่เป็นรูปธรรม สามกลยุทธ์ (Strategy A, Strategy B, Strategy C) ปรับแต่งบน ETHUSDT ทดสอบบน 12 สัญลักษณ์ใน tier สี่ระดับ
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:
| 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 นี่คือกลยุทธ์ทั่วไปที่ tune สำหรับสภาพแวดล้อมความผันผวนต่ำ สำหรับพอร์ตโฟลิโอของ 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:
| 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 เฉลี่ยเป็นบวกในทุก tier MaxDD เพิ่มขึ้นตามที่คาดไว้ตาม tier นี่คือ กลยุทธ์ที่ทนทาน ด้วย edge ตลาดที่แท้จริง แม้ PnL บนสัญลักษณ์ที่ปรับแต่งจะถ่อมตัวกว่า (+25% เทียบกับ +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. ความไม่ตรงกันของความผันผวน
เหตุผลที่พบบ่อยที่สุด พารามิเตอร์กลยุทธ์ถูก tune ให้กับระดับความผันผวนเฉพาะ ถ้ากลยุทธ์ใช้ threshold เข้า 2% — สำหรับ ETH ที่มีความผันผวนรายวัน 3% นี่คือ filter ที่สมเหตุสมผล สำหรับ DOGE ที่มีความผันผวนรายวัน 8% — threshold นี้ trigger บ่อยเกินไป สร้างสัญญาณเท็จจำนวนมาก
ในทำนองเดียวกัน stop loss 1% เหมาะสำหรับ ETH แต่สำหรับ PEPE มันคือ "noise" ปกติ และ stop จะถูก hit หลายสิบครั้งต่อวัน
2. ความแตกต่างด้านสภาพคล่อง
กลยุทธ์สมมติว่าคำสั่งถูก execute ทันทีที่ราคาปัจจุบัน บน BTCUSDT ด้วยความลึก order book 200K — คำสั่ง $10K ของคุณจะเคลื่อนราคา และการ execute จริงจะแย่กว่า 0.05-0.2% ใน 500 ไม้ นั่นคือ 25-100% ที่หายไปเพียงจาก slippage เท่านั้น
3. Market Microstructure
แต่ละเครื่องมือมี microstructure ของตัวเอง:
- Funding rates: บน BTC funding เป็นบวกสม่ำเสมอในตลาดขาขึ้น (+0.01% ทุก 8 ชั่วโมง) บน meme coin funding อาจกระโดดจาก -0.3% ถึง +0.5% รายละเอียดเพิ่มเติม — ใน Funding rates kill your leverage
- Spread: บน Tier 1 spread คือ 0.01% บน Tier 4 — 0.5% กลยุทธ์ที่มี take-profit เล็กไม่สามารถทำกำไรได้เมื่อ spread เกินขนาด take
- Manipulation patterns: wicks, spoofing, wash trading — แสดงออกต่างกันในแต่ละ tier
4. Regime Sensitivity
Altcoin ประพฤติตัวต่างกันในเฟสตลาดที่ต่างกัน:
- ในเทรนด์ขาขึ้น altcoin outperform BTC (beta > 1)
- ในเทรนด์ขาลง altcoin ร่วงหนักกว่า BTC
- ในตลาด sideways altcoin อาจ correlate กับ BTC หรือเคลื่อนไหวตาม narrative ของตัวเอง
กลยุทธ์ที่ปรับแต่งในเฟสหนึ่งบนสัญลักษณ์หนึ่งอาจถูก tune ให้เหมาะสมกับ lag/lead ของสัญลักษณ์นั้นเทียบกับ BTC โดยเฉพาะ — และ lag/lead นี้จะเปลี่ยนเมื่อ regime เปลี่ยน
การปรับพารามิเตอร์แบบ Adaptive

การรันกลยุทธ์ด้วยพารามิเตอร์เดิมบนสัญลักษณ์ทั้งหมดนั้นไม่ถูกต้อง แต่การ re-optimize เต็มรูปแบบบนแต่ละสัญลักษณ์ก็ทำลายวัตถุประสงค์ของ multi-symbol validation (พารามิเตอร์กลายเป็น "native" ของแต่ละสัญลักษณ์)
ทางประนีประนอมคือ การ normalize พารามิเตอร์ตามความผันผวน:
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})
ผลลัพธ์:
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'}
Stop loss เพิ่มจาก 1% เป็น 2.53% — เหมาะสมกับความผันผวนรายวัน 8.1% ของ DOGE โดยไม่มีการ scale stop 1% จะถูก hit โดย "noise" หลายสิบครั้ง
สำคัญ: scale เฉพาะ price thresholds (entries, stops, takes) เท่านั้น Period ของ indicator (RSI, MA) และตัวคูณ (ATR multiplier) มักไม่ถูก scale — พวกมัน normalize ตามความผันผวนผ่าน indicator อยู่แล้ว
สองโหมดการตรวจสอบ
-
Strict mode (ไม่มี scaling): รันด้วยพารามิเตอร์เดิม ทดสอบความทนทานสัมบูรณ์ ถ้ากลยุทธ์ทำกำไร — edge นั้นแข็งแกร่ง
-
Adaptive mode (มี scaling): รันด้วยพารามิเตอร์ที่ normalize แล้ว ทดสอบความทนทานของ logic กลยุทธ์ โดยยอมรับว่าระดับความผันผวนต่างกัน
เราแนะนำให้รันทั้งสองการทดสอบ Strict mode — เพื่อประเมิน "ความแข็งแกร่ง" ของ edge Adaptive mode — สำหรับการประยุกต์ใช้จริง
Cross-Symbol Robustness Score

สำหรับการประเมินเชิงปริมาณของความทนทานข้ามสัญลักษณ์ เราแนะนำ metric ผสม — Cross-Symbol Robustness Score (CSRS)
สูตร
โดยที่:
- — สัดส่วนสัญลักษณ์ที่ทำกำไร:
- — PnL เฉลี่ยถ่วงน้ำหนักสภาพคล่องแบบ normalize:
โดยที่ คือสภาพคล่องของสัญลักษณ์ (ปริมาณซื้อขายรายวันเฉลี่ย)
- — โบนัสสำหรับความสอดคล้องข้าม tier:
- — บทลงโทษสำหรับความแปรปรวนสูงของ PnL ระหว่างสัญลักษณ์:
น้ำหนักเริ่มต้น
| ส่วนประกอบ | น้ำหนัก | เหตุผล |
|---|---|---|
| (สัดส่วนที่ทำกำไร) | 0.35 | สำคัญที่สุด: กลยุทธ์ต้องทำงานบนส่วนใหญ่ |
| (PnL เฉลี่ย) | 0.25 | ผลตอบแทนสัมบูรณ์ |
| (ข้าม tier) | 0.25 | โบนัสสำหรับความเป็นสากล |
| (บทลงโทษความแปรปรวน) | 0.15 | บทลงโทษสำหรับความไม่เสถียร |
การตีความ CSRS
| CSRS | การตีความ |
|---|---|
| > 0.7 | ความทนทานยอดเยี่ยม กลยุทธ์ทำงานบนเครื่องมือส่วนใหญ่ |
| 0.5 — 0.7 | ความทนทานดี กลยุทธ์ทำงานใน tier ของตัวเองและบางส่วนใน tier อื่น |
| 0.3 — 0.5 | เส้นแบ่ง กลยุทธ์ทำงานบนชุดสัญลักษณ์แคบ |
| < 0.3 | ความทนทานต่ำ curve fitting ในระดับเครื่องมือมีแนวโน้มสูง |
การ Implement เต็มรูปแบบ: 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:
"""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)
ตัวอย่างการใช้งาน Pipeline
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}")
เมื่อการตรวจสอบสัญลักษณ์เดียวเป็นที่ยอมรับได้

ไม่ใช่ทุกกลยุทธ์ที่ต้องทำงานข้ามหลายเครื่องมือ มีกรณีที่ชอบด้วยกฎหมายที่ single-symbol เป็นแนวทางปกติ:
Market Making บน Order Book เฉพาะ
กลยุทธ์ market-making (เช่น ใช้โมเดล Avellaneda-Stoikov) โดยนิยามแล้วผูกกับ order book เฉพาะ พารามิเตอร์ขึ้นอยู่กับ microstructure เฉพาะ: ความลึก, spread, ตำแหน่งในคิว, fill rate การทดสอบบนสัญลักษณ์อื่นไม่มีความหมาย — มันเป็น order book ที่ต่างกัน
Arbitrage ระหว่างคู่เทรดเฉพาะ
Funding rate arbitrage หรือ cross-exchange arbitrage โดยนิยามแล้วผูกกับคู่เครื่องมือเฉพาะ การตรวจสอบที่นี่คือบน exchange อื่นด้วยคู่เดิม ไม่ใช่บนสัญลักษณ์ที่ต่างกัน
กลยุทธ์ที่ใช้คุณสมบัติเฉพาะของสินทรัพย์อย่างชัดเจน
ถ้ากลยุทธ์อิงอยู่กับคุณสมบัติเฉพาะของสินทรัพย์หนึ่ง (เช่น ความสัมพันธ์ของ BTC กับ hashrate หรือความสัมพันธ์ของ ETH กับ gas fees) multi-symbol validation ไม่สามารถใช้ได้ แต่กลยุทธ์เหล่านี้หายาก
ในกรณีอื่นทั้งหมด — ถ้ากลยุทธ์อิงอยู่กับสัญญาณ "ทั่วไป" (MA crossover, RSI, momentum, mean reversion) — multi-symbol validation เป็นสิ่งจำเป็น ถ้ากลยุทธ์ทั่วไปทำงานเฉพาะบนสัญลักษณ์เดียว มันไม่ใช่ edge — มันคือ overfitting
ความสัมพันธ์กับวิธีการตรวจสอบอื่น

Multi-symbol validation คือ หนึ่งในสามวิธีตั้งฉากกัน ของการทดสอบ out-of-sample:
| วิธีการ | แกนการตรวจสอบ | สิ่งที่เผยให้เห็น |
|---|---|---|
| Walk-Forward | เวลา | Overfitting กับช่วงเวลาเฉพาะ |
| Multi-symbol | เครื่องมือ | Overfitting กับสินทรัพย์เฉพาะ |
| Monte Carlo Bootstrap | ลำดับไม้ | การพึ่งพาลำดับเฉพาะ |
แต่ละวิธีตรวจสอบความทนทานตามแกนของตัวเอง กลยุทธ์สามารถผ่าน walk-forward แต่ล้มเหลวใน multi-symbol (curve fitted กับเครื่องมือ) สามารถผ่าน multi-symbol แต่ล้มเหลวใน Monte Carlo (ขึ้นอยู่กับลำดับไม้ที่โชคดี)
การป้องกัน overfitting สูงสุด: ใช้ทั้งสามวิธี
Full validation pipeline:
- Optimization ของพารามิเตอร์บนสัญลักษณ์เดียว
- Plateau analysis — ตรวจสอบเสถียรภาพของจุดเหมาะสม
- Walk-forward — การตรวจสอบแกนเวลา (WFER > 0.5)
- Multi-symbol — การตรวจสอบแกนเครื่องมือ (CSRS > 0.5)
- Monte Carlo bootstrap — confidence intervals (เปอร์เซ็นต์ไทล์ที่ 5 > 0)
- คำนึงถึง funding rates และ ความไม่สมมาตรของการขาดทุน
กลยุทธ์ที่ผ่านการตรวจสอบทั้งหกมีความน่าจะเป็นน้อยที่สุดที่จะเป็น overfitting artifact
ส่วนขยาย: Correlation ระหว่างสัญลักษณ์และ Cascade Strategies

Multi-symbol validation เผยให้เห็นอีกด้านหนึ่ง: correlations ระหว่างสัญลักษณ์ ถ้ากลยุทธ์ทำกำไรบน BTC และ ETH แต่ไม่ทำกำไรบน altcoin ทั้งหมด — นี่คือข้อมูลที่ว่า edge ผูกกับ correlation สูงระหว่าง BTC-ETH การวิเคราะห์โครงสร้าง correlation โดยละเอียด — ในบทความ Signal correlation and pairs trading
สำหรับพอร์ตโฟลิโอกลยุทธ์ ผลลัพธ์ multi-symbol กำหนดว่าจะ launch กลยุทธ์บนเครื่องมือใด Strategy A จากตัวอย่างข้างต้น — เฉพาะ Tier 1-2 Strategy B — Tier 1-3 นี่คือข้อมูลสำหรับ cascade orchestration ซึ่ง launch กลยุทธ์ต่างกันบนเครื่องมือต่างกันขึ้นอยู่กับ robustness profile ของพวกมัน
บทสรุป
Multi-symbol validation ไม่ใช่ตัวเลือก — มันเป็นขั้นตอนบังคับสำหรับกลยุทธ์ใดๆ ที่อ้างว่ามี market edge ที่เป็นสากล ประเด็นสำคัญ:
-
กลยุทธ์ที่ทำงานบนสัญลักษณ์เดียวมักจะ overfit กับลักษณะเฉพาะของสัญลักษณ์นั้น ข้อยกเว้น: market making, arbitrage, กลยุทธ์ที่อิงคุณสมบัติเฉพาะของสินทรัพย์
-
การจัดกลุ่ม Tier เป็นสิ่งจำเป็น คุณไม่สามารถเปรียบเทียบผลลัพธ์บน BTC (Tier 1) กับผลลัพธ์บน PEPE (Tier 3) โดยไม่เข้าใจความแตกต่างด้านความผันผวน สภาพคล่อง และ microstructure
-
การปรับพารามิเตอร์แบบ Adaptive — การ normalize threshold ตามความผันผวน — ปรับปรุงความสมจริงของการทดสอบ multi-symbol อย่างมีนัยสำคัญ
-
CSRS > 0.5 — threshold ขั้นต่ำที่สมเหตุสมผล กลยุทธ์ควรทำกำไรบน >= 60% ของสัญลักษณ์ใน tier เดิม และ PnL เฉลี่ยในสัญลักษณ์ทั้งหมดควรเป็นบวก
-
Walk-forward + Multi-symbol + Monte Carlo — สามแกนการตรวจสอบตั้งฉากกัน แต่ละวิธีจับสิ่งที่วิธีอื่นพลาด ใช้ทั้งสาม
กลยุทธ์ที่มี PnL +25% และ CSRS 0.72 น่าเชื่อถือกว่ากลยุทธ์ที่มี PnL +300% และ CSRS 0.18 กลยุทธ์แรกหาเงินจากความไม่มีประสิทธิภาพของตลาด กลยุทธ์หลังหาเงินจากการจำ price series เดียว
ลิงก์ที่เป็นประโยชน์
- 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 Validation: Test Your Strategy on All Pairs},
year = {2026},
url = {https://marketmaker.cc/th/blog/post/multi-symbol-validation},
version = {0.1.0},
description = {ทำไมกลยุทธ์ที่ปรับแต่งบน ETHUSDT ถึงอาจล้มเหลวกับ altcoin อื่น วิธีทดสอบอย่างถูกต้องข้ามกลุ่มคู่เทรด (blue chips, large caps, shitcoins) และระดับคะแนนความทนทานข้ามสัญลักษณ์ที่ถือว่าเพียงพอ}
}
ผู้เขียน
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.