← กลับไปยังบทความ
July 4, 2026
อ่าน 5 นาที

Random Search กับ Smart Search: จุดตัดอยู่ที่ต้นทุนการประเมิน ไม่ใช่ตัวอัลกอริทึม

Random Search กับ Smart Search: จุดตัดอยู่ที่ต้นทุนการประเมิน ไม่ใช่ตัวอัลกอริทึม
#การเทรดอัลกอริทึม
#แบ็คเทสต์
#การออปติไมซ์ไฮเปอร์พารามิเตอร์
#การออปติไมซ์แบบเบย์เซียน
#walk-forward
#โอเวอร์ฟิตติ้ง
Part 7 of 10 · Collection
High-Performance Backtest Engines

ส่วนหนึ่งของซีรีส์ "Backtests Without Illusions"

มีภูมิปัญญาที่ได้รับการยอมรับอย่างกว้างขวางในวงการ hyperparameter optimization ว่า random search เป็นเพียง baseline ที่ควรก้าวข้ามไป ผลงานคลาสสิกของ Bergstra & Bengio (2012) พิสูจน์ว่า random ชนะ grid ส่วน Bayesian optimization, TPE, CMA-ES และวิธี multi-fidelity อย่าง Hyperband/ASHA ก็ควรจะเอาชนะ random ต่อไปอีกทอดหนึ่ง ดังนั้นเมื่อเรานั่งลงเพื่อเปรียบเทียบวิธีการค้นหาพารามิเตอร์ (parameter-search) สำหรับเอนจินเทรดของเราเอง เราคาดหวังลำดับขั้นแบบเดิม ๆ คือ random อยู่ล่างสุด ส่วน smart sampler อยู่บนสุด

เรากลับได้ผลตรงกันข้าม — แล้วจากนั้นก็ได้คำตอบแบบตำราเรียนด้วยเช่นกัน กลยุทธ์เดียวกัน พื้นที่พารามิเตอร์เดียวกัน objective เดียวกัน เครื่องเดียวกัน สิ่งเดียวที่เราเปลี่ยนคือ backtest หนึ่งครั้งมีต้นทุนแพงแค่ไหน และอันดับของวิธีการค้นหาก็ พลิกกลับ เมื่อการประเมินแต่ละครั้งมีต้นทุนต่ำ ลำดับ scrambled Sobol แบบโง่ ๆ ก็บดขยี้ smart sampler ทุกตัว เมื่อเราทำให้การประเมินแต่ละครั้งมีต้นทุนสูง วิธีที่ฉลาดกลับแซงขึ้นนำและหาคอนฟิกเพียงตัวเดียวที่รอดใน out-of-sample ได้

บทเรียนในที่นี้ไม่ใช่ "random ถูกประเมินค่าต่ำเกินไป" หรือ "Bayesian ถูกประเมินค่าสูงเกินไป" แต่คือ จุดตัดระหว่าง random search กับ smart search ถูกควบคุมโดยต้นทุนการประเมิน ไม่ใช่โดยความฉลาดของอัลกอริทึม เลือก optimizer ของคุณตามว่า backtest หนึ่งครั้งมีต้นทุนเท่าใด ไม่ใช่ตามชื่อเสียงของมัน บทความนี้วัดอย่างแม่นยำว่าจุดตัดนั้นอยู่ตรงไหน ทำไมมันถึงอยู่ตรงนั้น และเงื่อนไขหนึ่งเดียว — fidelity — ที่ตัดสินว่ากลเม็ดของระบอบต้นทุนสูง (early stopping, multi-fidelity pruning) จะปลอดภัยที่จะใช้หรือไม่

ทุกอย่างด้านล่างนี้มาจากสองสคริปต์ในตัว backtester ของเรา: bench_search.py (v4, commit ee092f1) สำหรับระบอบต้นทุนต่ำแบบ single-timeframe และ bench_search_multitf.py (commit 102853c) สำหรับระบอบต้นทุนสูงแบบ multi-timeframe ทั้งสองเป็น leak-free — ตัดสินใจตอนปิดแท่ง i fill ที่ open[i+1] — และทั้งสองให้คะแนนทุกวิธีบน objective แบบ multi-fold rolling walk-forward โดยมี held-out test window ที่การค้นหาไม่มีวันได้เห็น

คำถาม: throughput หรือ sample-efficiency?

งบประมาณการค้นหาในรูปเศษส่วนเดียว คือ wall-clock หารด้วยผลรวมของ ask/tell cost บวก eval cost โดยพจน์ eval cost ในตัวส่วนเป็นตัวตัดสินว่า throughput ดิบ หรือการวางตำแหน่งต่อจุดจะเป็นฝ่ายชนะ

ทุกวิธีการค้นหาใช้งบประมาณ wall-clock ของตนไปกับสองสิ่ง คือ การตัดสินใจว่าจะสุ่มตัวอย่างจุดถัดไปที่ไหน (การประมวลผลของตัว sampler เอง) และ การประเมินตัวอย่างนั้น (การรัน backtest) เรียกอย่างแรกว่า ask/tell cost และอย่างหลังว่า eval cost พลังการค้นหาที่แท้จริงของวิธีหนึ่ง ๆ ภายใต้งบประมาณ wall-clock คงที่นั้น โดยประมาณคือ:

points explored    wall-clock budgetask/tell cost+eval cost\text{points explored} \;\approx\; \frac{\text{wall-clock budget}}{\text{ask/tell cost} + \text{eval cost}}

และคุณภาพสุดท้ายของมันคือจำนวนนั้นคูณด้วยว่าแต่ละจุดถูก วางตำแหน่งได้ดี เพียงใด มีสองปุ่มปรับที่ดึงกันคนละทาง:

  • Throughput — จำนวนจุดต่อวินาที sampler แบบโง่ (random, scrambled Sobol/QMC) มี ask/tell cost ใกล้ศูนย์ คือแค่ปล่อยจุดแบบ low-discrepancy ออกมาแล้วไปต่อ มันเพิ่มจำนวนจุดให้มากที่สุด
  • Sample-efficiency — คุณภาพต่อจุด sampler แบบฉลาด (TPE, CMA-ES, ASHA) ใช้การประมวลผลจริงในการสร้างแบบจำลอง objective เพื่อวางแต่ละจุดให้ดีขึ้น มันเพิ่มคุณภาพการวางตำแหน่งให้มากที่สุด โดยแลกมาด้วย throughput

ปุ่มไหนจะชนะขึ้นอยู่กับตัวส่วนทั้งหมด เมื่อ eval cost มีค่าน้อยมาก ask/tell cost จะครอบงำตัวส่วน ดังนั้นอะไรก็ตามที่ทำให้มันพองตัว — surrogate model, kernel density estimate, การอัปเดต covariance — จะลดจำนวนจุดที่คุณสำรวจได้โดยตรง เมื่อ eval cost มีค่ามาก ask/tell cost จะกลายเป็นแค่ rounding error ทำให้ความฉลาดนั้นแทบไม่มีต้นทุนเลย และคุณควรซื้อมันมาให้มากที่สุดเท่าที่จะทำได้

นี่คือใจความทั้งหมดในประโยคเดียว: ask/tell tax นั้นคงที่ แต่ความสำคัญของมันถูกกำหนดโดย eval cost ที่คุณใช้หารมัน ทีนี้มาดูกันว่ามันเกิดขึ้นจริงอย่างไร

ระบอบต้นทุนต่ำ: Sobol แบบโง่ชนะด้วย throughput

ในระบอบต้นทุนต่ำ กระแส scrambled Sobol ท่วมพื้นที่พารามิเตอร์ด้วยการประเมินนับพันครั้งที่แทบไม่มีต้นทุน ในขณะที่ TPE และ ASHA ติดขัดอยู่หลังกลไก ask/tell ของตัวเอง ใช้งบประมาณส่วนใหญ่ไปกับการคิดแทนที่จะเป็นการมอง

กลยุทธ์ single-timeframe ของเราเป็นกฎการแยก HMA/HMA3 แบบ leak-free บนพื้นที่พารามิเตอร์ 7 ตัว ประเมินผลด้วย eval_batch แบบ in-process ที่เขียนด้วย numba ซึ่งรัน prange ไปตามชุดค่าคอนฟิกโดยไม่มี overhead ระหว่างโพรเซส บนเอนจินนี้ backtest หนึ่งครั้งแทบไม่มีต้นทุนเลย — kernel ดิบประเมินคอนฟิกได้ราว 3–4k cfg/s นี่คือระบอบต้นทุนต่ำ และเป็นจุดที่การเทรดแตกต่างอย่างชัดเจนจากบริบท deep learning ที่ตำนานเรื่อง HPO ส่วนใหญ่มาจาก "objective function" ของเราไม่ใช่การรัน training บน GPU นาน 6 ชั่วโมง แต่เป็นการผ่านอาร์เรย์ที่ใช้เวลา 0.3 มิลลิวินาที

เราให้งบประมาณเท่ากันแก่ทุกวิธี คือ 1,500 การประเมิน และบันทึก wall-clock ที่แต่ละวิธีต้องใช้เพื่อทำการประเมินเหล่านั้นให้ครบ พร้อมกับค่า held-out test objective ที่มันหาเจอ เนื่องจากงบประมาณการประเมินคงที่ คอลัมน์ wall-clock จึง เป็น การอ่านค่า overhead ของแต่ละ sampler ได้โดยตรง:

วิธี Evals Wall-clock Throughput Held-out TEST
sobol (QMC) 1,500 0.53 s ~2,830 cfg/s −259
random 1,500 0.85 s ~1,770 cfg/s −27
sobol→cmaes 1,500 1.38 s ~1,085 cfg/s −367
cmaes 1,500 1.76 s ~850 cfg/s −85
tpe 1,500 9.76 s ~154 cfg/s −161
tpe-mv+sobol 1,500 12.15 s ~123 cfg/s −151
asha (folds) 1,500 15.79 s ~95 cfg/s −165

TEST คือ walk-forward objective (PnL-per-active-time ต่อปี × ความเชื่อมั่นจากจำนวน trade) บน held-out window ที่การค้นหาไม่เคยแตะต้อง ยิ่งสูงยิ่งดี

มีข้อเท็จจริงสองอย่างที่โดดเด่นออกมา อย่างแรก ลองดู คอลัมน์ throughput scrambled Sobol วิ่งที่ ~2,830 cfg/s — ใกล้เพดานของเอนจิน TPE วิ่งที่ ~154 cfg/s และ ASHA ที่ ~95 นั่นคือการช้าลง 18–30 เท่า เพื่อทำการประเมินจำนวน เท่ากันทุกประการ smart sampler ไม่ได้ประเมินอะไรเพิ่มเติมเลย พวกมันแค่ใช้เวลานั้นไปกับกลไก ask/tell ของตัวเอง

อย่างที่สอง — และนี่คือส่วนที่ทำให้เรื่องราวนี้ยังคงซื่อสัตย์ — ไม่มีวิธีใดเลยที่หาผลลัพธ์ out-of-sample เป็นบวกได้ ค่า TEST ทุกค่าเป็นลบทั้งหมด ในระบอบ single-timeframe กลยุทธ์ของเราไม่มี OOS edge ที่ยั่งยืนเลย ดังนั้น "วิธีไหนชนะ" จึงไม่ใช่คำถามเกี่ยวกับกำไรสุดท้าย แต่เป็นคำถามเกี่ยวกับ ประสิทธิภาพการค้นหา (search efficiency) และในแง่ประสิทธิภาพการค้นหาภายใต้งบประมาณ eval คงที่ วิธีแบบโง่เป็นฝ่ายชนะขาด: Sobol และ random ได้ตัวเลข held-out เท่ากันหรือดีกว่า smart sampler ในขณะที่ใช้ wall-clock เพียง 1/20

ทีนี้ลองพลิกการเปรียบเทียบให้เป็นแบบที่ผู้ปฏิบัติงานจริงเจอ — fix ค่า wall-clock ไม่ใช่ fix จำนวน eval ถ้าคุณให้เวลาทุกวิธีเท่ากับ 15.8 วินาทีที่ ASHA ต้องใช้สำหรับ 1,500 evals ของมัน Sobol จะไม่หยุดที่ 1,500 มันจะเดินหน้าต่อไปจนถึงราว 45,000 คอนฟิก ในระบอบต้นทุนต่ำ คำถามไม่เคยเป็น "sampler ไหนวางจุด 1,500 จุดได้ดีที่สุด" แต่เป็น "คุณอยากได้ 1,500 จุดที่วางอย่างฉลาด หรือ 45,000 จุดแบบ scrambled เมื่อแต่ละจุดแทบไม่มีต้นทุน" เมื่อ eval แทบไม่มีต้นทุน ความกว้าง (breadth) เป็นฝ่ายชนะ การครอบคลุมพื้นที่ 7 มิติมากกว่าถึงสามสิบเท่าเอาชนะแบบจำลองที่ดีกว่าของมันได้

ask/tell tax

20 เท่านั้นหายไปไหน? ไม่ได้หายไปที่ backtest — เพราะส่วนนั้นเหมือนกันทุกวิธี มันหายไปกับการทำบัญชี (bookkeeping) ต่อจุดของ sampler ที่รันด้วย Python อยู่ใน loop:

  • TPE สร้าง kernel-density estimate สองชุด (trial ที่ดี vs ไม่ดี) ในทุก ask และต้นทุนนี้เพิ่มขึ้นตามประวัติ trial ที่สะสมมา TPE แบบ multivariate จะสร้างแบบจำลองร่วมกันข้ามมิติ — โมเดลมากขึ้น โค้ด Python มากขึ้น
  • CMA-ES อัปเดตและสุ่มตัวอย่างจาก covariance matrix ในทุก generation ถูกกว่า TPE ในกรณีนี้ (มันวิ่งที่ ~850 cfg/s) แต่ก็ยังมี overhead มากกว่าการปล่อยจุด Sobol อยู่หนึ่งอันดับ (order of magnitude)
  • ASHA ต้องจ่ายค่าบัญชี promotion/rung ของ pruner และ ในดีไซน์ folds-as-fidelity ของเรา ยังต้องจ่ายค่า precompute ของ indicator แบบคงที่ก่อนที่จะตัด (prune) อะไรได้เลยด้วยซ้ำ — ดังนั้นการประเมินที่มัน "ประหยัด" ได้จริงจึงน้อยกว่าที่การคำนวณบนกระดาษบอกไว้

นี่ไม่ใช่การตำหนิอัลกอริทึมเหล่านี้แต่อย่างใด แต่คือประเด็นสำคัญ: ask/tell cost เป็นตัวเลขมิลลิวินาทีต่อจุดที่ค่อนข้างคงที่ และเมื่อ eval ที่มันห่อหุ้มอยู่ก็ใช้เวลาไม่กี่มิลลิวินาทีเช่นกัน ต้นทุนคงที่นั้นก็จะกลายเป็น 90% ของงบประมาณของคุณในทันที smart sampler ใช้ wall-clock เก้าในสิบส่วนไปกับการคิดว่าจะมองที่ไหน และหนึ่งในสิบส่วนไปกับการมองจริง ๆ ส่วน scrambled Sobol ใช้เวลาทั้งหมดไปกับการมอง เมื่อการมองมีต้นทุนต่ำ การมองเป็นฝ่ายชนะ

เราจงใจ ไม่ เปรียบเทียบ Gaussian-process Bayesian optimizer แบบเต็มรูปแบบในที่นี้ ด้วยเหตุผลเดียวกัน: surrogate แบบ GP มีความซับซ้อน O(n3)O(n^3) ตามจำนวน trial เมื่อเทียบกับ eval ที่มีต้นทุนระดับมิลลิวินาที การ fit surrogate จะกินงบประมาณการค้นหาทั้งหมดไปก่อนที่มันจะประเมินพื้นที่ได้เพียงสัดส่วนเล็กน้อยที่มีความหมาย ในระบอบต้นทุนต่ำ GP-BO ถูกตัดสิทธิ์ไปด้วยเลขคณิตล้วน ๆ

ระบอบต้นทุนสูง: จุดตัดพลิกกลับ

จุดตัด (crossover point): เมื่อการประเมินหนึ่งครั้งมีต้นทุนสูงขึ้น เส้นกราฟของสองวิธีก็ตัดกัน — Sobol แบบมองไม่เห็นต้นทุนร่วงลง ในขณะที่ smart sampler ที่รับรู้ต้นทุน (cost-aware) ไต่ขึ้นแซงมันไป กลายเป็นวิธีเดียวที่ข้ามเข้าสู่แดนบวกของผล out-of-sample

ตอนนี้เราทำให้ backtest หนึ่งครั้งมีต้นทุนสูงขึ้น กลยุทธ์ multi-timeframe ซ้อนไทม์เฟรมสูง กลาง และต่ำเข้าด้วยกัน (triple-TF) แต่ละไทม์เฟรมมีส่วนร่วมด้วยการผ่าน indicator และ threshold ของตัวเอง ทั้งหมดให้คะแนนผ่าน multi-fold walk-forward เดียวกัน การประเมินหนึ่งครั้งตอนนี้มีต้นทุนอยู่ในระดับ 0.1–0.5 วินาที แทนที่จะเป็น 0.3 มิลลิวินาที — กระโดดขึ้นสามอันดับ (three orders of magnitude) eval cost ได้ย้ายจากพจน์ rounding-error ในตัวส่วนของเรา ไปเป็นพจน์ที่ครอบงำแทน ตามทฤษฎีที่วางไว้ ask/tell tax ควรจะหยุดมีความสำคัญ และความฉลาดควรจะเริ่มให้ผลตอบแทน และมันก็เป็นเช่นนั้นจริง ๆ

เรารันทุกวิธีภายใต้งบประมาณ wall-clock คงที่ประมาณ 150 วินาที บนโจทย์ triple-TF (พื้นที่พารามิเตอร์ 18 ตัว) ปล่อยให้แต่ละวิธีใช้งบประมาณนั้นตามที่ sampler ของมันกำหนด แล้วประเมินคอนฟิกที่ดีที่สุดเพียงตัวเดียวที่มันคืนค่ามาบน held-out test window:

วิธี (triple-TF, 150 วิ) Evals Held-out TEST ผลตัดสิน
sobol (QMC) 349 −673 แพ้
cascade (sobol²×64) 20,864 −585 แพ้
asha (folds) 292 eff. −239 แพ้
tpe-mv+sobol 455 −43 แพ้
sobol→cmaes 15,239 +226 OOS เป็นบวกเพียงหนึ่งเดียว

TEST คือ walk-forward objective เดียวกับก่อนหน้านี้ มีเพียงวิธีเดียวเท่านั้นที่ข้ามศูนย์ไปได้

baseline Sobol แบบโง่ที่เคยครองระบอบต้นทุนต่ำ ตอนนี้กลับ รั้งท้ายสุด ที่ −673 การสุ่มตัวอย่างแบบ low-discrepancy ที่มองไม่เห็นอะไรเลยบนพื้นที่ 18 มิติ โดยมีเพียง 349 การประเมินให้ใช้เพราะแต่ละครั้งมีต้นทุนสูง ไม่สามารถระบุตำแหน่ง (localize) อะไรได้เลย ส่วนวิธีที่ฉลาดอย่าง sobol→cmaes — ใช้งบประมาณ 30% กับ Sobol เพื่อหว่านเมล็ด (seed) แอ่ง (basin) จากนั้นปรับละเอียดด้วย CMA-ES จากเมล็ดที่ดีที่สุด — เป็น วิธีเดียวเท่านั้นที่ให้ผลลัพธ์ out-of-sample เป็นบวกได้เลย บน holdout สุดท้ายที่ไม่เคยถูกแตะต้อง แชมป์ตัวนี้ให้ผลตอบแทน +2.62% (19 trade, การ expose เงินทุนราว ~6.6%) ต่อยอดจาก test window ที่ให้ผลตอบแทน +16.35% (46 trade, exposure ราว ~15.7%) แชมป์ของคู่แข่งทุกตัวขาดทุนใน out-of-sample

นั่นคือจุดตัด (crossover) ที่วัดบนตระกูลกลยุทธ์เดียวกัน objective เดียวกัน เครื่องเดียวกัน: ไม่เปลี่ยนอะไรเลยนอกจากต้นทุนของการประเมินหนึ่งครั้ง แล้วอันดับของวิธีการค้นหาก็พลิกกลับ ในระบอบต้นทุนต่ำ Sobol ชนะ และ smart sampler คือความสูญเปล่า 20 เท่า ส่วนในระบอบต้นทุนสูง smart sampler เป็นสิ่งเดียวที่ใช้งานได้ และ Sobol คือความสูญเปล่า

เหตุใด "smart" จึงชนะที่นี่ — และไม่ใช่แค่เพราะ sample-efficiency

การใช้ประโยชน์แบบรับรู้ต้นทุน (cost-aware) บนพื้นที่พารามิเตอร์สองแกน: แกน indicator ที่มีต้นทุนสูงถูกตรึงไว้กับที่ ในขณะที่ smart sampler ท่วมแกน threshold ที่มีต้นทุนต่ำบนสัญญาณที่แคช (cached) ไว้ แปลง wall-clock เดียวกันให้กลายเป็นทั้งการประเมินที่มากขึ้นและวางตำแหน่งได้ดีขึ้น

เวอร์ชันที่เรียบร้อยของเรื่องนี้คือ "eval ที่แพงให้รางวัลกับ sample-efficiency ดังนั้นวิธีที่วางจุดน้อยกว่าแต่ดีกว่าจะชนะ" นั่นถูกต้องเพียงครึ่งเดียว และข้อมูลบังคับให้เราต้องพูดถึงอีกครึ่งหนึ่งที่ซื่อสัตย์และน่าสนใจกว่า

ลองดูจำนวน eval อีกครั้ง sobol→cmaes ไม่ได้ชนะเพราะประเมินจุด น้อยกว่า Sobol แบบมองไม่เห็นต้นทุน — มันประเมินไปถึง 15,239 จุด เทียบกับ 349 จุดของ Sobol มากกว่าถึงสี่สิบเท่า ในเวลา 150 วินาทีเท่ากัน ทำไมถึงเป็นเช่นนั้น? เพราะ eval cost ของ multi-TF ของเรามี โครงสร้าง ไม่ได้สม่ำเสมอ มีสองแกน: แกน indicator ที่ แพง (คาบเวลาของไทม์เฟรมและความยาว HMA ใช้เวลาคำนวณ 30–500 ms ต่อครั้ง เพราะมันบังคับให้ต้อง recompute indicator ใหม่) และแกน threshold ที่ ถูก (ระดับการแยก entry/exit ใช้เวลาราว ~1–2 ms ต่อครั้งบนสัญญาณที่แคชไว้แล้ว) ช่องว่างระหว่างสองแกนนี้อยู่ที่ 30–100 เท่า

Sobol แบบมองไม่เห็นต้นทุนไม่สนใจโครงสร้างนี้เลย ทุกจุดที่มันสุ่มออกมาจะขยับแกน indicator ที่แพง บังคับให้ต้อง recompute ใหม่ทุกครั้ง — ดังนั้นมันจึงจ่ายราคาเต็มในทั้ง 349 การประเมิน ส่วน sobol→cmaes เมื่อ CMA-ES ระบุตำแหน่งบริเวณที่มีแนวโน้มดีได้แล้ว มักจะตรึงโครงสร้าง indicator แบบหยาบให้คงที่โดยประมาณ แล้วรบกวน (perturb) เฉพาะ threshold แบบต่อเนื่อง ซึ่งตกลงบนสัญญาณที่แคชไว้และแทบไม่มีต้นทุนเลย วิธีที่ฉลาดจะแปลง wall-clock เดียวกันให้เป็น ทั้ง จุดที่วางตำแหน่งดีขึ้น และ จำนวนจุดที่มากขึ้นกว่าเดิมมาก เพราะการปรับตัว (adaptive) ในที่นี้หมายถึงการ รับรู้ต้นทุน (cost-aware) คือการอยู่บนแกนที่ถูกต่อไปหลังจากแกนที่แพงถูกตรึงไว้แล้ว การใช้ประโยชน์แบบ cascade(sobol²×64) ที่เราออกแบบไว้อย่างชัดเจนทำสิ่งนี้อย่างดุดันที่สุด — 20,864 evals ด้วยการรวมกลุ่ม (batch) threshold ที่ถูกบนสัญญาณที่แคชไว้ — และแม้ว่ามันจะแพ้ใน test ของ triple-TF แต่ในรูปแบบสองไทม์เฟรม (two-timeframe) มันกลับชนะ test window ไปอย่างขาดลอยที่ +20.2% (ก่อนที่จะแพ้ holdout ของตัวเอง — จะพูดถึงรายละเอียดด้านล่าง)

ดังนั้นข้อความที่คมชัดกว่าของจุดตัดนี้คือ: ในระบอบต้นทุนสูง ask/tell tax จะกลายเป็นสิ่งที่ไม่มีนัยสำคัญ ซึ่ง ปลดปล่อย ให้คุณฉลาดได้ — และคำว่า "ฉลาด" หมายถึงการปรับตัวให้เข้ากับโครงสร้างต้นทุนของ objective ไม่ใช่แค่รูปร่างของมัน การสุ่มตัวอย่างแบบมองไม่เห็นต้นทุนทำไม่ได้ทั้งสองอย่าง นี่คือโครงสร้างสองแกนอย่างแม่นยำที่เอนจิน adaptive-resolution drill-down ของเราถูกสร้างขึ้นมาเพื่อใช้ประโยชน์ และนี่คือเหตุผลที่วิธี multi-fidelity เหมาะกับระบอบต้นทุนสูง — โดยมีเงื่อนไขหนึ่งที่ต้องเป็นจริงก่อน

Fidelity: เงื่อนไขที่ซ่อนอยู่ก่อนจะทำ pruning ได้

วิธีการแบบ multi-fidelity — Hyperband, ASHA, pruner แบบ early-stopping ใด ๆ — ตั้งอยู่บนสมมติฐานเดียว: ว่าการประเมินแบบ ถูกและไม่สมบูรณ์ (cheap, partial) จะ จัดอันดับ (rank) คอนฟิกในทางเดียวกันกับการประเมินแบบ แพงและสมบูรณ์ (expensive, full) ถ้าคอนฟิกที่ดูดีใน walk-forward fold หนึ่งมีแนวโน้มจะดูดีในทุก fold ด้วย คุณก็สามารถฆ่าตัวที่แพ้ตั้งแต่เนิ่น ๆ แล้วใช้งบประมาณของผู้รอดชีวิตไปกับผู้ชนะได้ แต่ถ้า fidelity ราคาถูกจัดอันดับแบบ สุ่ม การทำ early stopping ก็แค่ทิ้งคอนฟิกที่ดีไปด้วยการโยนเหรียญเท่านั้น

ดังนั้นก่อนจะเชื่อ pruner ใด ๆ เราวัดสมมติฐานนี้โดยตรง fidelity ของเราคือ จำนวน walk-forward fold (ประเมินบน r fold แบบถูก หรือทั้ง K fold ด้วยต้นทุนเต็ม) และ fidelity gate จะคำนวณ Spearman rank correlation ρ ระหว่าง objective แบบ r-fold ที่ถูก กับ objective แบบเต็มบนตัวอย่างคอนฟิกแบบสุ่ม ρ@1 คือค่าสหสัมพันธ์เมื่อคุณตัดสินด้วย fold เดียว — fidelity ที่ดุดันที่สุดและถูกที่สุด นี่คือสิ่งที่ gate นั้นรายงานในทั้งสองระบอบ:

Fidelity (จำนวน fold ที่ใช้) Single-TF ρ Multi-TF ρ
ρ@1 (1 fold) ~0.03 0.43
ρ@2 0.67
ρ@3 0.78
ρ@4 0.82
ρ@5 0.91

ในระบอบ single-timeframe fold เดียวจัดอันดับคอนฟิกด้วยค่าสหสัมพันธ์เพียง ~0.03 เทียบกับความจริง — ซึ่งแยกไม่ออกทางสถิติจากการสุ่ม นี่ไม่ใช่เรื่องบังเอิญ แต่เป็นข้อเท็จจริงเดียวกับที่ว่า "ไม่มีวิธีใดหา OOS edge เจอ" เมื่อกลยุทธ์ไม่มีสัญญาณที่ยั่งยืน ผลงานต่อ fold ของมันส่วนใหญ่เป็นเรื่องของโชค ดังนั้น fold เดี่ยวใด ๆ ก็เป็นการสุ่มที่แทบไม่ต่างจากการสุ่มจริง และการ pruning ด้วย low-fidelity ก็จะฆ่าคอนฟิกที่ดีทิ้งไปพร้อมกับเลื่อนขั้นคอนฟิกที่แค่โชคดี multi-fidelity ไม่ปลอดภัยในระบอบต้นทุนต่ำที่นี่ — ไม่ใช่เพราะวิธีนี้แย่ แต่เพราะสัญญาณราคาถูกคือ noise (gate ของเราตรวจจับสิ่งนี้และปฏิเสธที่จะ prune อย่างดุดัน)

ในระบอบ multi-timeframe มี edge จริงอยู่ และภาพของ fidelity ก็เปลี่ยนไปโดยสิ้นเชิง: ρ@1 เพิ่มขึ้นเป็น 0.43 และเมื่อถึงห้า fold ρ ไต่ขึ้นไปถึง 0.91 ตอนนี้ fold เดียวก็มีข้อมูลการจัดอันดับที่แท้จริงอยู่แล้ว และห้า fold ก็มีข้อมูลเกือบทั้งหมด early stopping จึง ปลอดภัย — คอนฟิกที่แพ้ในสอง-สาม fold แรกมีแนวโน้มสูงจริง ๆ ว่าจะเป็นตัวแพ้ นี่คือเหตุผลที่สองที่วิธี multi-fidelity เหมาะกับระบอบต้นทุนสูง: ไม่ใช่แค่ว่า eval ที่แพงทำให้การ pruning คุ้มค่า แต่ยังเป็นเพราะระบอบต้นทุนสูงคือที่ที่ fidelity ราคาถูกในที่สุดก็ จัดอันดับเหมือนกับ แบบเต็ม

กฎที่ได้จากสิ่งนี้ตรงไปตรงมาและรันได้ถูกมาก: วัดค่า ρ ก่อนที่จะ prune ค่าสหสัมพันธ์ของ fidelity เป็นการคำนวณเพียงสองบรรทัดบนคอนฟิกสุ่มไม่กี่ร้อยตัว และมันคือความแตกต่างระหว่างการค้นหาแบบ multi-fidelity ที่เร่งความเร็วให้คุณ กับการค้นหาแบบ multi-fidelity ที่ค่อย ๆ บ่อนทำลายคุณอย่างเงียบ ๆ

การชนะการค้นหา ไม่ใช่การรอดจากมัน

ขอเพิ่มหมายเหตุเรื่องความซื่อสัตย์อีกข้อหนึ่ง เพราะซีรีส์นี้พูดถึง backtest ที่โกหก แชมป์ triple-TF ของเรา sobol→cmaes เป็นวิธีเดียวที่ทำ holdout เป็นบวกได้ — +2.62% ต่อยอดจาก +16.35% ใน test window นี่คือข่าวดี แต่นี่คือข้อควรระวัง: มันไม่รอดจาก statistical deflation

แชมป์ตัวนี้คือตัวที่ดีที่สุดจากคอนฟิกนับหมื่นที่ลองมาทั้งหมดในทุกวิธี ภายใต้การทดสอบซ้ำจำนวนมากขนาดนั้น holdout +2.62% ไม่ได้เป็นของจริงโดยอัตโนมัติ เรารัน overfitting gate ที่ทั้งซีรีส์นี้พึ่งพาอยู่ — Deflated Sharpe Ratio ที่แก้ไขด้วย effective-N สำหรับความสัมพันธ์ระหว่าง trial และ PBO ผ่าน combinatorially-symmetric cross-validation แชมป์ตัวนี้ ผ่าน PBO (0.12 ต่ำกว่าเกณฑ์ 0.2 อย่างสบาย ๆ — อันดับของมันเสถียรตลอดการแบ่ง CSCV) แต่ deflated Sharpe ของมันร่วงลงเหลือศูนย์ (gate กำหนดว่าต้อง ≥ 0.95) ผลตัดสิน: ไม่รอด

อ่านให้ละเอียด เพราะนี่คือประเด็นของแบบฝึกหัดทั้งหมดนี้ ผลลัพธ์ของจุดตัดนั้นเป็นเรื่องจริง: smart search ชนะการค้นหา ในระบอบต้นทุนสูงอย่างเด็ดขาด และ Sobol แพ้ไป แต่ การชนะการค้นหาเป็นข้อความเกี่ยวกับตัว optimizer ไม่ใช่เกี่ยวกับตัวกลยุทธ์ คอนฟิกที่ดีที่สุดที่ optimizer ดี ๆ หาเจอจากพื้นที่ที่ไม่มี edge เลย ก็ยังคงไม่มี edge อยู่ดี — deflation คือสิ่งที่บอกคุณว่าคุณกำลังถืออันไหนอยู่ การเลือกวิธีการค้นหาที่ถูกต้องทำให้คุณได้คำตอบที่ดีที่สุดที่มีอยู่อย่างมีประสิทธิภาพ แต่มันไม่ได้สร้าง edge ที่ไม่เคยมีอยู่จริงขึ้นมา optimizer และ overfitting gate เป็นเครื่องมือคนละชนิดที่วัดสิ่งคนละอย่าง และคุณต้องใช้ทั้งสองอย่าง

กฎการตัดสินใจที่คุณนำไปใช้ได้จริง

คุณไม่จำเป็นต้องรัน benchmark ของเราซ้ำเพื่อเลือก optimizer คุณต้องการตัวเลขเดียวเท่านั้น: backtest หนึ่งครั้งใช้เวลานานแค่ไหน? จับเวลาการประเมิน objective ของคุณหนึ่งครั้ง — การผ่าน walk-forward เต็มรูปแบบหนึ่งรอบ ทุก fold — แล้วอ่านผลออกมาเป็นระบอบ

  • Eval ราคาถูก (≲ ~10 ms/backtest): ซื้อ throughput ใช้ scrambled Sobol/QMC หรือ random ask/tell tax บน TPE/CMA-ES/ASHA จะทำให้คุณเสียจำนวนจุด 10–30 เท่า เพื่อแลกกับการวางตำแหน่งที่ eval แทบไม่มีต้นทุนไม่ได้ให้รางวัลตอบแทนเลย อย่าไปยุ่งกับ multi-fidelity pruning เลย — และถ้าคุณอยากลอง ให้เช็ค ρ@1 ก่อน ในระบอบต้นทุนต่ำที่ edge ต่ำ มันมักจะใกล้ศูนย์ ซึ่งหมายความว่า pruning ก็แค่โยนเหรียญ ใช้เวลาทางวิศวกรรมที่ประหยัดได้ไปกับการขยายการค้นหาให้กว้างขึ้น ไม่ใช่ทำให้แคบลง
  • Eval ราคาแพง (≳ ~100 ms–หลายวินาที/backtest): ซื้อ sample-efficiency ใช้ CMA-ES, TPE หรือ hybrid แบบ Sobol-seeded CMA-ES เพราะ overhead ของ sampler ตอนนี้กลายเป็นแค่ rounding error เมื่อเทียบกับ eval ถ้า eval cost ของคุณมี โครงสร้าง (แกน indicator ที่ช้าและแกน threshold ที่เร็ว เหมือนใน multi-TF) ให้เลือกวิธีที่ใช้ประโยชน์จากโครงสร้างนั้น — cascade, drill-down หรืออะไรก็ตามที่ cost-aware — มากกว่าวิธีที่มองทุกมิติว่ามีต้นทุนเท่ากันหมด
  • อยู่ระหว่างกลาง หรือไม่แน่ใจ: hybrid แบบ Sobol-seeded (sobol→cmaes) เป็นค่าเริ่มต้นที่แข็งแกร่งที่สุด มันมีพฤติกรรมเหมือน Sobol แบบ breadth-first ในช่วงต้น (ถูก ไม่ต้อง fit โมเดล) และเหมือนตัวปรับละเอียดที่ฉลาดในช่วงหลัง ดังนั้นมันจึงเสื่อมประสิทธิภาพลงอย่างค่อยเป็นค่อยไป (degrades gracefully) ไม่ว่าคุณจะอยู่ในระบอบไหนก็ตาม — ซึ่งเป็นเหตุผลที่มันเป็นแชมป์ในระบอบต้นทุนสูงของเราพอดี
  • ก่อนใช้ pruner ใด ๆ ให้วัด fidelity ก่อน คำนวณ Spearman ρ ระหว่าง fidelity ราคาถูกกับ objective แบบเต็มบนคอนฟิกสุ่มไม่กี่ร้อยตัว ถ้า ρ@1 ต่ำ อย่า prune ด้วย fold เดียว ให้เพิ่ม resource ขั้นต่ำขึ้นไปจนกว่า ρ จะผ่าน ~0.5 สิ่งนี้ใช้โค้ดเพียงสองบรรทัดและป้องกันไม่ให้ accelerator ของคุณทิ้งคอนฟิกที่ดีที่สุดของคุณไปอย่างเงียบ ๆ
  • ไม่ว่าตัวไหนจะชนะการค้นหา ให้รัน deflation gate เสมอ ผู้ชนะของ optimizer คือวัตถุที่เสี่ยงต่อ overfitting มากที่สุดที่คุณจะสร้างขึ้นได้ในสัปดาห์นั้น DSR และ PBO ต่างหาก ไม่ใช่คะแนนของ optimizer ที่ตัดสินว่ามันเทรดได้จริงหรือไม่

จุดเชื่อมโยงกับที่อื่น

ผลลัพธ์นี้อยู่ตรงกลางของประเด็นหลายเส้นที่ซีรีส์นี้ได้ดึงเอาไว้:

  • มันตั้งอยู่บนสมมติฐานว่าเอนจินที่อยู่เบื้องล่างซื่อสัตย์ ข้อได้เปรียบทั้งหมดในระบอบต้นทุนต่ำมีอยู่ เพราะ เอนจิน numba แบบ in-process ของเราทำได้หลายพันคอนฟิกต่อวินาทีโดยไม่มี IPC — speed ladder คือสิ่งที่พาคุณเข้าสู่ระบอบที่ throughput ชนะตั้งแต่แรก เอนจินที่ช้าและถูกเก็บภาษีโดย framework จะทำให้ทุกปัญหาตกอยู่ในระบอบต้นทุนสูงโดยปริยาย และคุณจะไม่มีวันได้เห็นจุดตัดนี้เลย
  • การใช้ประโยชน์ในระบอบต้นทุนสูงคือโครงสร้างต้นทุนสองแกนที่เอนจิน adaptive-resolution drill-down ของเราถูกออกแบบมาโดยรอบ: ระบุตำแหน่งบนแกนหยาบที่แพงก่อน แล้วจึงใช้ประโยชน์จากแกนละเอียดที่ถูก
  • ทุกวิธีในที่นี้น่าเชื่อถือได้ก็เพราะเอนจินเป็น leak-free เท่านั้น การค้นหาผ่าน trial นับหมื่นครั้งเป็นเครื่องจักรที่มีประสิทธิภาพที่สุดเท่าที่จะเป็นไปได้ในการหาและใช้ประโยชน์จากบั๊ก look-ahead — "ผู้ชนะ" ก็จะเป็นคอนฟิกที่พึ่งพา leak นั้นหนักที่สุดนั่นเอง แก้นาฬิกาให้ถูกต้องก่อน แล้วค่อยค้นหา
  • และชะตากรรมของแชมป์ — ชนะการค้นหา แต่แพ้ deflation — คือข้อโต้แย้งทั้งหมดสำหรับการปฏิบัติต่อ การค้นหาพารามิเตอร์และการควบคุม overfitting ให้เป็นขั้นตอนที่แยกจากกัน โดยใช้เครื่องมือคนละชุด

พื้นหลังทางวิชาการก็คือเรื่องเดียวกับที่วงการนี้วนกลับมาซ้ำ ๆ: Bergstra & Bengio (2012) ว่าด้วยเหตุผลที่ random ชนะ grid; Hyperband ของ Li et al. (2018) และงานต่อยอด ASHA (2020) ว่าด้วย multi-fidelity; และ Bailey & López de Prado (2014) ว่าด้วยเหตุผลที่ผู้ชนะของการค้นหาขนาดใหญ่ใด ๆ ต้องถูก deflate ก่อนที่จะเชื่อได้ ไม่มีงานชิ้นไหนกำหนดว่ามี optimizer ที่ดีที่สุดเพียงตัวเดียว เพราะมันไม่มีอยู่จริง — มีแต่ระบอบ และต้นทุนที่เป็นตัวเลือกระบอบนั้น

สรุปประเด็นสำคัญ

  1. จุดตัดระหว่าง random search กับ smart search ถูกกำหนดโดยต้นทุนการประเมิน ไม่ใช่โดยตัวอัลกอริทึม เราพลิกอันดับของทุกวิธีได้โดยไม่เปลี่ยนอะไรเลยนอกจากต้นทุนของ backtest หนึ่งครั้ง
  2. Eval ราคาถูก → Sobol แบบโง่ชนะด้วย throughput บนเอนจิน single-TF ของเรา (~3–4k cfg/s) TPE และ ASHA วิ่งช้ากว่า 18–30 เท่าสำหรับจำนวน eval เท่ากัน — ~95–154 cfg/s เทียบกับ ~2,830 ของ Sobol เมื่อ wall-clock เท่ากัน ความกว้าง (breadth) เอาชนะแบบจำลองที่ดีกว่าของพื้นที่ เมื่อแต่ละจุดแทบไม่มีต้นทุน
  3. Eval ราคาแพง → วิธีแบบฉลาดชนะด้วยประสิทธิภาพ บนโจทย์ triple-TF sobol→cmaes เป็นวิธี เดียว ที่หาผลลัพธ์ out-of-sample เป็นบวกได้ (+16.35% ใน test, +2.62% ใน holdout) ส่วน Sobol แบบมองไม่เห็นต้นทุนจบด้วยอันดับรั้งท้าย
  4. ในระบอบต้นทุนสูง "smart" หมายถึง cost-aware ผู้ชนะใช้ประโยชน์จากช่องว่าง 30–100 เท่าระหว่างแกน indicator ที่แพงกับแกน threshold ที่ถูก — มันทำ eval ได้มากกว่า และ วางตำแหน่งได้ดีกว่า ด้วยการอยู่บนแกนที่ถูกหลังจากแกนที่แพงถูกตรึงไว้แล้ว
  5. Fidelity คือเงื่อนไขก่อนที่จะทำ pruning ได้ ค่าสหสัมพันธ์ของการจัดอันดับด้วย fold เดียวเพิ่มขึ้นจาก ρ@1 ≈ 0.03 (single-TF ซึ่งแทบเป็นการสุ่ม) ไปเป็น 0.43 (multi-TF) และไปถึง 0.91 เมื่อใช้ห้า fold multi-fidelity/ASHA จะให้ผลตอบแทนก็ต่อเมื่อ fidelity ราคาถูกจัดอันดับได้เหมือนกับแบบแพงเท่านั้น — ดังนั้นให้วัด ρ ก่อนที่จะ prune
  6. การชนะการค้นหาไม่ใช่การรอดจากมัน แชมป์ผ่าน PBO แต่แพ้ Deflated Sharpe gate เลือก optimizer ตามต้นทุนของ eval ตัดสินว่าเทรดได้จริงหรือไม่ด้วย deflation gate ทั้งสองเป็นเครื่องมือคนละชนิด และคุณต้องใช้ทั้งคู่

เลือก optimizer ของคุณตามต้นทุนของ backtest หนึ่งครั้ง แล้วจำไว้ว่าคำตอบที่ดีที่สุดที่ optimizer หาเจอได้ในพื้นที่ที่ไม่มี edge เลยนั้น ก็ยังคงไม่มี edge อยู่ดี — และให้ gate ไม่ใช่การค้นหา เป็นตัวบอกคุณว่าคุณกำลังถืออันไหนอยู่

ข้อจำกัดความรับผิดชอบ: ข้อมูลที่ให้ไว้ในบทความนี้มีไว้เพื่อการศึกษาและให้ข้อมูลเท่านั้น และไม่ถือเป็นคำแนะนำทางการเงิน การลงทุน หรือการเทรด การเทรดสกุลเงินดิจิทัลมีความเสี่ยงสูงที่จะขาดทุน

ผู้เขียน

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 เฉพาะ การวิเคราะห์ตลาด และการอัปเดตแพลตฟอร์ม

เราเคารพความเป็นส่วนตัวของคุณ ยกเลิกการสมัครได้ทุกเมื่อ