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.

Articles

ईमानदार नकारात्मक परिणाम: हजारों बैकटेस्ट, पांच मेजर, कोई मजबूत एज नहीं

ईमानदार नकारात्मक परिणाम: हजारों बैकटेस्ट, पांच मेजर, कोई मजबूत एज नहीं

सर्च-एंड-ओवरफिट कथानक का चरम बिंदु, और यह एक नकारात्मक परिणाम पर खत्म होता है — जो सही है। ETHUSDT पर एक सिंगल-सिंबल ड्यूल-टाइमफ्रेम सर्च ने एक ऐसा कॉन्फ़िग खोजा जो out-of-sample पर +16.35% और एक अछूते holdout पर +2.62% देता था; Deflated Sharpe Ratio ने, ~37,000 ट्रायल को ध्यान में रखते हुए, इसे घटाकर 0.00 कर दिया। पांच मेजर (ETH/BTC/SOL/BNB/XRP, प्रत्येक ~1.18M 1m बार) पर एक क्रॉस-इंस्ट्रूमेंट पास, median out-of-sample के आधार पर चयन करते हुए, इसे हमेशा के लिए खत्म कर देता है: dual DSR 0.24 / PBO 0.264, triple DSR 0.14 / PBO 0.327 — दोनों गेट फेल हो जाते हैं। चैंपियन 5 में से 1 सिंबल पर लाभदायक है और बाकी पर नकारात्मक। एंटी-ओवरफिट तंत्र इसी के लिए है: आपको शोर के सबसे अच्छे हिस्से को अल्फा के रूप में शिप करने से रोकने के लिए।

मल्टी-Timeframe Backtests में No Look-Ahead साबित करना: भविष्य को Perturb करें, साबित करें कि अतीत उसे देख नहीं सकता

मल्टी-Timeframe Backtests में No Look-Ahead साबित करना: भविष्य को Perturb करें, साबित करें कि अतीत उसे देख नहीं सकता

मल्टी-timeframe backtests एक बनते हुए higher-timeframe bar के जरिए भविष्य लीक करते हैं, जिसका final close अभी अस्तित्व में ही नहीं है। सिर्फ code review करके भरोसा नहीं जीता जा सकता — इसे टेस्ट करना ही पड़ता है। हम live bot के closed-bar rule को बिल्कुल वैसा ही reproduce करते हैं, फिर shifted-future probe से साबित करते हैं कि कोई leakage नहीं है: भविष्य के हर bar को perturb करें और assert करें कि अतीत का हर signal और trade bitwise अपरिवर्तित रहता है। 25/25 parity checks, और probe में असली पकड़ (teeth) है।

GPU कब अपनी कीमत वसूलता है: पैरामीटर-स्वीप की roofline, जहाँ सुर्खियों वाला 167x असल में 27x एल्गोरिदम गुणा 6.2x हार्डवेयर है

GPU कब अपनी कीमत वसूलता है: पैरामीटर-स्वीप की roofline, जहाँ सुर्खियों वाला 167x असल में 27x एल्गोरिदम गुणा 6.2x हार्डवेयर है

CPU पर GPU की बढ़त batch size के साथ बढ़ती है — हमारे मल्टी-टाइमफ्रेम इंडिकेटर precompute पर प्रति कॉल एक combo पर 54.5x से लेकर 61 पर 359.6x तक — क्योंकि छोटा स्वीप kernel-launch और transfer overhead की भरपाई नहीं कर पाता। हम सुर्खियों वाले 167x को 27x की एल्गोरिदमिक जीत (जो CPU को भी उतना ही तेज़ करती है) गुणा 6.2x की हार्डवेयर जीत में तोड़ते हैं, दिखाते हैं कि GPU बनाम सर्वश्रेष्ठ-CPU की असली बढ़त सिंगल-टाइमफ्रेम पर सिर्फ़ 3.2x और मल्टी पर 6.2x है, और एक निर्णय-गाइड देते हैं कि GPU खरीदने लायक बनने से पहले स्वीप कितना चौड़ा होना चाहिए।

GPU प्रिसिजन ट्रैप: Apple Metal पर fp32 बैकटेस्ट चुपचाप गार्बेज नतीजे कैसे देता है

GPU प्रिसिजन ट्रैप: Apple Metal पर fp32 बैकटेस्ट चुपचाप गार्बेज नतीजे कैसे देता है

Apple के Metal GPU में float64 होता ही नहीं। किसी vectorized बैकटेस्ट को उस पर भोलेपन से पोर्ट कर दीजिए, और वह लुभावना prefix-sum WMA fp32 में overflow कर जाता है — अधिकतम relative error 211× — फिर भी वह चलता रहता है और plausible दिखने वाले नंबर लौटाता है। इसका फिक्स ज्यादा precision नहीं है; यह एक अलग formulation है: एक direct windowed convolution, जो fp32 में 8×10⁻⁷ तक सुरक्षित है और single-thread numba से 55.9× तेज है। यह लेख इसी ट्रैप, उसके पीछे के arithmetic, और यह साबित करने के तरीके पर है कि आप खुद उसमें फंसे तो नहीं।

फिडेलिटी गेट: कोर्स-टू-फाइन बैकटेस्टिंग आपको और तेज़ी से बेवकूफ बनाती है, जब तक कि सस्ता प्रॉक्सी वैसे ही रैंक न करे जैसे महंगा वाला करता है

फिडेलिटी गेट: कोर्स-टू-फाइन बैकटेस्टिंग आपको और तेज़ी से बेवकूफ बनाती है, जब तक कि सस्ता प्रॉक्सी वैसे ही रैंक न करे जैसे महंगा वाला करता है

ड्रिल-डाउन / मल्टी-फिडेलिटी सर्च (ASHA, successive halving, Hyperband) हज़ारों कॉन्फ़िग्स को सस्ते में स्क्रीन करती है और केवल बचे हुए (survivors) को महंगे फुल इवैल्यूएशन के लिए आगे बढ़ाती है। यह एक असली स्पीडअप है — लेकिन अगर लो-फिडेलिटी रैंकिंग हाई-फिडेलिटी रैंकिंग से असहमत हो, तो यह चुपचाप ध्वस्त हो जाती है। हमने फोल्ड-रैंक कोरिलेशन को मापा: एक फोल्ड पर Spearman ρ 0.03 तक हो सकता है (लगभग रैंडम रैंकिंग), और जैसे-जैसे फोल्ड्स बढ़ते हैं यह 0.43, 0.67, 0.78, 0.91 तक चढ़ता जाता है। इसका समाधान एक अनिवार्य गेट है — पहले ρ(cheap, full) मापें, और न्यूनतम फिडेलिटी को ऑटोमैटिक रूप से उस पहले रंग (rung) तक बढ़ा दें जहाँ ρ ≥ 0.5 हो।

रैंडम बनाम स्मार्ट सर्च: क्रॉसओवर इवैल कॉस्ट से तय होता है, एल्गोरिदम से नहीं

रैंडम बनाम स्मार्ट सर्च: क्रॉसओवर इवैल कॉस्ट से तय होता है, एल्गोरिदम से नहीं

जब एक बैकटेस्ट सस्ता होता है, तो डम्ब स्क्रैम्बल्ड Sobol रॉ थ्रूपुट पर जीत जाता है — स्मार्ट सैंपलर (TPE, CMA-ES, ASHA) एक Python ask/tell टैक्स चुकाते हैं जो उन्हें 20x धीमा कर देता है, इसलिए बराबर वॉल-क्लॉक में वे बहुत कम पॉइंट्स इवैल्यूएट करते हैं और हार जाते हैं। हर eval को महंगा बनाइए (multi-TF + walk-forward folds) और क्रॉसओवर पलट जाता है। हमने दोनों रीजीम मापे, और क्यों fold-rank fidelity (ρ@1 का 0.03→0.43 तक बढ़ना) pruning के फायदेमंद होने की पूर्वशर्त है।

दो-अक्षीय पैरामीटर स्पेस: आपके स्वीप का ज्यादातर हिस्सा लगभग मुफ्त क्यों होना चाहिए

दो-अक्षीय पैरामीटर स्पेस: आपके स्वीप का ज्यादातर हिस्सा लगभग मुफ्त क्यों होना चाहिए

सभी पैरामीटर खोजने में एक जैसे महंगे नहीं होते। स्ट्रैटेजी के पैरामीटर दो अक्षों में बंट जाते हैं: महंगा अक्ष (इंडिकेटर — पूरी सीरीज पर दोबारा गणना) और सस्ता अक्ष (डिसीजन थ्रेशोल्ड — पहले से गणना किए गए सिग्नलों पर एक O(n) पास)। चूंकि इंडिकेटर थ्रेशोल्ड से अपरिवर्तित रहते हैं, आप उन्हें एक बार गणना करके हजारों थ्रेशोल्ड कॉन्फिग ~5,600 cfg/s की रफ्तार से स्वीप कर सकते हैं — हर कॉन्फिग पर दोबारा गणना करने से करीब 1,600 गुना सस्ता। यह डाइमेंशनैलिटी के अभिशाप की कीमत का पुनर्मूल्यांकन है।

फ्रेमवर्क टैक्स: जब आपकी बैकटेस्ट लाइब्रेरी एक भोले pandas लूप से भी धीमी होती है

फ्रेमवर्क टैक्स: जब आपकी बैकटेस्ट लाइब्रेरी एक भोले pandas लूप से भी धीमी होती है

हमने आठ बैकटेस्ट इंजनों को एक ही समान पैरामीटर स्वीप पर बेंचमार्क किया — 150k बार, 80 HMA-क्रॉस संयोजन, ट्रेड-गिनती की पैरिटी 2707 पर लॉक। दो सबसे लोकप्रिय इवेंट-ड्रिवन फ्रेमवर्क हाथ से लिखे pandas लूप से भी धीमे निकले, जबकि एक वेक्टराइज़्ड/कंपाइल्ड इंजन ने वही काम लगभग 13,000× तेज़ी से चलाया। उस प्रति-बार ओवरहेड का अध्ययन जिसे लोकप्रिय लाइब्रेरियाँ कभी अमॉर्टाइज़ करने के लिए बनी ही नहीं थीं।

The Probability of Backtest Overfitting: Did Your Search Beat a Coin Flip?

The Probability of Backtest Overfitting: Did Your Search Beat a Coin Flip?

The Deflated Sharpe Ratio prices the winning strategy; PBO prices the search that picked it. Combinatorially Symmetric Cross-Validation runs C(16,8) = 12,870 train/test splits over a 1000x200 performance matrix and asks: does the in-sample winner land in the bottom half out of sample? The catch almost everyone misses — PBO's null is 0.5, not 1. On 200 zero-edge strategies the best in-sample annualized Sharpe of 1.98 collapses to 0.06 out of sample and PBO = 0.476: a coin flip, fully overfit. Plant a real edge (annualized Sharpe 2.38) and PBO drops to 0.001, the in-sample 3.73 surviving to an out-of-sample 2.34. A moving-average grid on a pure random walk has no out-of-sample skill either — PBO 0.463 averaged over 60 matrices, statistically indistinguishable from the null — and on one representative matrix the mirage is vivid: a best in-sample Sharpe of 2.33 collapses to a median out-of-sample -0.22, PBO 0.573, a 63% chance of a loss.

The IPC Tax: Put the Backtest Engine Behind a Socket and Lose 13% — Almost None of It to the Socket

The IPC Tax: Put the Backtest Engine Behind a Socket and Lose 13% — Almost None of It to the Socket

We ported a numba backtest kernel line-for-line to Rust and called it across a process boundary four ways, with an equivalence gate confirming identical PnL to the last trade. Shipping the entire 1.2 MB price series through a Unix socket costs ~2 ms — about 0.1% of the job. JSON-encoding the same payload costs 1348x more than raw bytes, chatty per-combo calls re-ship the data 80 times, and a per-bar call pattern would pay 2.1 s of pure IPC on a 2.0 s job. The boundary is cheap; the tax is in how you cross it.

The Deflated Sharpe Ratio: How Many of Your Backtest 'Winners' Survive Multiple Testing?

The Deflated Sharpe Ratio: How Many of Your Backtest 'Winners' Survive Multiple Testing?

A parameter search is a machine for manufacturing luck. On pure noise — 1,000 strategies with zero true edge — the best annual Sharpe averages 1.63 and the naive significance test flags a discovery 100% of the time. We build controlled ground truth and show that the Deflated Sharpe Ratio, the Harvey-Liu haircut, and White's Reality Check restore honesty: false discoveries drop from 1.000 to 0.001-0.057, genuine edges above the noise ceiling are kept with power ~1 — and one real trap (correlated grids) where the raw DSR over-deflates and the verdict must be read across a whole band of effective-trial estimates, not one.

Objective-Function Design: The Metric You Optimize Secretly Picks Your Strategy

Objective-Function Design: The Metric You Optimize Secretly Picks Your Strategy

To search for the 'best' strategy you must first define 'best' — and that scalar silently chooses the winner. On synthetic data with a known edge (600 seeds, T=2000, 80 thresholds), a naive per-trade Sharpe crowns a lottery: it picks a sub-5%-exposure winner in 56% of seeds and degenerates in 57% — on the starkest seed, 8 trades posting an in-sample Sharpe of 21.09 that collapses to 0.13 out of sample. The honest repair is almost dull: measure on the full timeline, which never degenerates (out-of-sample 1.71). A trade-count (conf_k) shrinkage and an exposure floor can retrofit a per-trade metric, but even fully repaired they only match full-timeline Sharpe (1.70 vs 1.71) — never beat it. Goodhart's law, in a backtest, with controlled ground truth.