एक सवाल है जिससे हर बैकटेस्ट कतराता है: यही कोड, अगर वही बाज़ार लाइव मिलता, तो क्या वही करता? इसका जवाब और बैकटेस्टिंग से नहीं मिलेगा। जवाब सिर्फ़ इस तरह मिलता है कि स्ट्रैटेजी को लाइव डेटा पर असली एक्ज़ीक्यूशन सिमेंटिक्स के साथ चलाया जाए, और फिर ट्रेड दर ट्रेड जाँचा जाए कि दोनों दुनियाएँ आपस में मेल खाती हैं या नहीं। यह जाँच हम हर दिन, अपने-आप करते हैं — और यही अब तक प्लेटफ़ॉर्म का सबसे उपजाऊ बग-फ़ाइंडर साबित हुई है।
पहला दिन: शीशा तैयार करो
हर प्रमोट हुई स्ट्रैटेजी अपने अलग, आइसोलेटेड लाइव नोड में चलती है और असली एक्सचेंज स्ट्रीम्स पर टिकी होती है: फ़िल्स के लिए लाइव कोट्स, असली स्प्रेड, असली सेशन आवर्स। स्ट्रैटेजियों के बीच कोई साझा स्टेट नहीं (यह सबक हमने ठोकर खाकर सीखा — साझा नोड में एक स्ट्रैटेजी की पोज़ीशन क्वेरीज़ दूसरी में रिस जाती थीं)। हर फ़िल के साथ वह सिग्नल वैल्यू भी रिकॉर्ड होती है जिसने उसे जन्म दिया।
हर सुबह: रिप्ले और डिफ़
एक डेली जॉब हर स्ट्रैटेजी की पेपर विंडो लेता है, उसी अवधि पर कैटलॉग डेटा के साथ बिल्कुल वही कोड बैकटेस्ट इंजन से चलाता है, और फ़िल्स को एक-से-एक मिलाता है: वही साइड, वही टाइमस्टैम्प टॉलरेंस, वही साइज़। नतीजा कोई कोरिलेशन या अंदाज़ा नहीं होता। वह एक टेबल होती है: matched, paper-only, replay-only. सेहतमंद स्ट्रैटेजी 55 में से 54 matched पर बैठती है। बीमार स्ट्रैटेजी ठीक-ठीक बता देती है कि कौन-सा ट्रेड और कब बहका।
क्या-क्या टूटा, जिस क्रम में टूटा
- वॉर्मअप फ़िल्स। लाइव नोड इंडिकेटर गर्म करने के लिए हिस्ट्री फीड करता था — और कस्टम बार हैंडलर वाली स्ट्रैटेजियाँ उसी पर मज़े से ट्रेड कर डालती थीं। बैकटेस्ट को ये फ़ैंटम एंट्रीज़ कभी दिखीं ही नहीं। फ़िक्स सबमिशन-लेयर पर गार्ड लगाकर हुआ, स्ट्रैटेजी में नहीं — क्योंकि वरना यह बग हर स्ट्रैटेजी को विरासत में मिलता है।
- सीक्वेंशियल मल्टी-लेग वॉर्मअप। एक क्रॉस-सेक्शनल स्ट्रैटेजी एक बार में एक ही इंस्ट्रूमेंट गर्म करती थी; हर लेग को उसके सिबलिंग्स खाली दिखते और ऐंकर कभी इनिशियलाइज़ ही नहीं होता। लाइव में उसने एक भी ट्रेड नहीं किया; रिप्ले में ठीक-ठाक ट्रेड किए। शून्य matched ट्रेड — पर यह बात खुलकर सिर्फ़ डिफ़ ने कही।
- टिक-प्रिसिज़न क्रैश लूप। लाइव aggTrade टिक्स उस प्रिसिज़न से अलग प्रिसिज़न पर आते हैं जिसकी सैंडबॉक्स इंस्ट्रूमेंट को उम्मीद थी। नोड एक ऐसे assertion पर क्रैश-लूप करने लगा जिसे बैकटेस्ट कभी ट्रिगर ही नहीं कर सकता था, क्योंकि कैटलॉग बार पहले से नॉर्मलाइज़्ड होते हैं।
- रीस्टार्ट की भूलने की बीमारी। प्रोसेस रीस्टार्ट पहले से मौजूद पोज़ीशनों पर एंट्री लॉजिक दोबारा चला देते थे — रीबैलेंसिंग स्ट्रैटेजी के लिए एक रीस्टार्ट चुपके से एक रीबैलेंस बन जाता था। लाइव ट्रेडिंग में यह पैरिटी का फ़ुटनोट नहीं है; यह पैसे से जुड़ा लाल झंडा है।
पैटर्न पर ग़ौर कीजिए: इनमें से एक भी सिग्नल बग नहीं है। ये सब एक्ज़ीक्यूशन-बाउंड्री के बग हैं — वॉर्मअप, स्टेट, प्रिसिज़न, रीस्टार्ट। और ठीक इसी किस्म की नाकामी के प्रति बैकटेस्ट संरचनात्मक रूप से अंधे होते हैं, क्योंकि बैकटेस्ट में एक्ज़ीक्यूशन बाउंड्री ख़ुद बैकटेस्ट इंजन ही है।
वे असमानताएँ जो हम जानबूझकर रखते हैं
दोनों दुनियाएँ सोच-समझकर एक जैसी नहीं रखी गई हैं। बैकटेस्ट PnL के भीतर एक मॉडल किया हुआ हाफ़-स्प्रेड और स्क्वायर-रूट इम्पैक्ट वसूलता है; पेपर फ़िल प्राइस में असली स्प्रेड चुकाता है और उसमें कोई इम्पैक्ट मॉडल नहीं होता। पेपर में मॉडल वाला स्प्रेड जोड़ना (या बैकटेस्ट में असली वाला) दोहरी गिनती होगी। पैरिटी का मतलब है वही फ़ैसले, टॉलरेंस के भीतर वही फ़िल्स — बिट-दर-बिट एक जैसा PnL नहीं। कौन-सा फ़र्क़ सैद्धांतिक है और कौन-सा बग, यह पहचानना ही इस अनुशासन का बड़ा हिस्सा है।
बैकटेस्ट एक परिकल्पना है। पेपर ट्रेडिंग वह प्रयोग है। रिप्ले पैरिटी वह लैब नोटबुक है जो आपको ख़ुद को बहलाते हुए रंगे हाथ पकड़ती है।
अगर आप स्ट्रैटेजियाँ चलाते हैं और लाइव व्यवहार को रिप्ले किए गए व्यवहार से एक तय शेड्यूल पर मिलाकर नहीं देखते, तो बग की एक पूरी श्रेणी ऐसी है जो आपने कभी देखी ही नहीं। हमें ऐसा एक बग हर दो हफ़्ते में मिल जाता है, और हर बार वह बैकटेस्ट के भीतर से पूरी तरह अदृश्य था।
← सभी पोस्ट
