संसाधन लोड हो रहा है... लोड करना...

पायथन के साथ घटना-संचालित बैकटेस्टिंग - भाग I

लेखक:अच्छाई, बनाया गयाः 2019-03-22 11:53:50, अद्यतन किया गयाः

हमने पिछले कुछ महीनों में क्वांटस्टार्ट पर पायथन और पांडा का उपयोग करके विभिन्न ट्रेडिंग रणनीतियों का बैकटेस्टिंग किया है। पांडा की वेक्टरकृत प्रकृति यह सुनिश्चित करती है कि बड़े डेटासेट पर कुछ ऑपरेशन बेहद तेज़ हैं। हालांकि, वेक्टरकृत बैकटेस्टर के रूपों का हमने आज तक अध्ययन किया है, व्यापार निष्पादन का अनुकरण करने के तरीके में कुछ कमियां हैं। लेखों की इस श्रृंखला में हम पायथन का उपयोग करके एक घटना-संचालित बैकटेस्टिंग वातावरण का निर्माण करके ऐतिहासिक रणनीति सिमुलेशन के लिए अधिक यथार्थवादी दृष्टिकोण पर चर्चा करने जा रहे हैं।

घटना-संचालित सॉफ्टवेयर

इससे पहले कि हम इस तरह के बैकटेस्टर के विकास में डूब जाएं, हमें इवेंट-ड्राइव सिस्टम की अवधारणा को समझने की आवश्यकता है। वीडियो गेम इवेंट-ड्राइव सॉफ्टवेयर के लिए एक प्राकृतिक उपयोग मामला प्रदान करते हैं और पता लगाने के लिए एक सीधा उदाहरण प्रदान करते हैं। एक वीडियो गेम में कई घटक होते हैं जो उच्च फ्रेमरेट्स पर वास्तविक समय सेटिंग में एक दूसरे के साथ बातचीत करते हैं। यह एक अनंत लूप के भीतर गणना के पूरे सेट को चलाने से संभाला जाता है जिसे इवेंट-लूप या गेम-लूप के रूप में जाना जाता है।

गेम-लूप के प्रत्येक टिक पर एक फ़ंक्शन को नवीनतम घटना प्राप्त करने के लिए बुलाया जाता है, जिसे गेम के भीतर कुछ संबंधित पूर्व कार्रवाई द्वारा उत्पन्न किया गया होगा। घटना की प्रकृति के आधार पर, जिसमें एक कुंजी-दबाना या माउस क्लिक शामिल हो सकता है, कुछ बाद की कार्रवाई की जाती है, जो या तो लूप को समाप्त कर देगी या कुछ अतिरिक्त घटनाओं को उत्पन्न करेगी। प्रक्रिया तब जारी रहेगी। यहाँ कुछ उदाहरण छद्म कोड हैंः

while True:  # Run the loop forever
    new_event = get_new_event()   # Get the latest event

    # Based on the event type, perform an action
    if new_event.type == "LEFT_MOUSE_CLICK":
        open_menu()
    elif new_event.type == "ESCAPE_KEY_PRESS":
        quit_game()
    elif new_event.type == "UP_KEY_PRESS":
        move_player_north()
    # ... and many more events

    redraw_screen()   # Update the screen to provide animation
    tick(50)   # Wait 50 milliseconds

कोड लगातार नई घटनाओं की जांच कर रहा है और फिर इन घटनाओं के आधार पर कार्रवाई कर रहा है। विशेष रूप से यह वास्तविक समय प्रतिक्रिया हैंडलिंग के भ्रम की अनुमति देता है क्योंकि कोड लगातार लूप किया जा रहा है और घटनाओं की जांच की जा रही है। जैसा कि स्पष्ट हो जाएगा कि उच्च आवृत्ति व्यापार सिमुलेशन करने के लिए हमें ठीक यही चाहिए।

क्यों एक घटना-संचालित बैकटेस्टर?

घटना-संचालित प्रणालियां वेक्टर पद्धति के मुकाबले कई फायदे प्रदान करती हैंः

  • कोड पुनः उपयोग - एक घटना-संचालित बैकटेस्टर, डिजाइन के अनुसार, घटकों के न्यूनतम स्विच-आउट के साथ ऐतिहासिक बैकटेस्टिंग और लाइव ट्रेडिंग दोनों के लिए इस्तेमाल किया जा सकता है। यह वेक्टरिज्ड बैकटेस्टर के लिए सच नहीं है जहां सांख्यिकीय विश्लेषण करने के लिए सभी डेटा एक बार में उपलब्ध होना चाहिए।
  • लुकहेड पूर्वाग्रह - इवेंट-ड्राइव बैकटेस्टर के साथ कोई लुकहेड पूर्वाग्रह नहीं है क्योंकि बाजार डेटा प्राप्ति को एक इवेंट के रूप में माना जाता है जिस पर कार्य किया जाना चाहिए। इस प्रकार यह संभव है कि इवेंट-ड्राइव बैकटेस्टर को बाजार डेटा के साथ फीड करें, यह दोहराएं कि ऑर्डर प्रबंधन और पोर्टफोलियो सिस्टम कैसे व्यवहार करेगा।
  • यथार्थवाद - इवेंट-ड्राइव बैकटेस्टर्स ऑर्डर निष्पादित करने और लेनदेन लागतों को कैसे उत्पन्न करते हैं, इस पर महत्वपूर्ण अनुकूलन की अनुमति देते हैं। यह बुनियादी बाजार और सीमा आदेशों के साथ-साथ बाजार-ऑन-ओपन (एमओओ) और बाजार-ऑन-क्लोज (एमओसी) को संभालना सरल है, क्योंकि एक कस्टम एक्सचेंज हैंडलर बनाया जा सकता है।

यद्यपि घटना-संचालित प्रणालियों में कई लाभ हैं, लेकिन वे सरल वेक्टर सिस्टम की तुलना में दो प्रमुख नुकसानों से पीड़ित हैं। सबसे पहले, वे लागू करने और परीक्षण करने के लिए काफी अधिक जटिल हैं। अधिक चलती भागों हैं जो बगों को पेश करने की अधिक संभावना पैदा करते हैं। इस उचित सॉफ्टवेयर परीक्षण पद्धति को कम करने के लिए परीक्षण-संचालित विकास जैसे नियोजित किए जा सकते हैं।

दूसरा वेक्टर प्रणाली की तुलना में निष्पादित करने के लिए धीमी हैं। गणितीय गणनाओं को करने के दौरान इष्टतम वेक्टर ऑपरेशन का उपयोग नहीं किया जा सकता है। हम बाद के लेखों में इन सीमाओं को दूर करने के तरीकों पर चर्चा करेंगे।

घटना-संचालित बैकटेस्टर अवलोकन

एक बैकटेस्टिंग प्रणाली के लिए एक घटना-संचालित दृष्टिकोण लागू करने के लिए हमारे घटकों (या वस्तुओं) को परिभाषित करना आवश्यक है जो विशिष्ट कार्यों को संभालेंगेः

  • घटना - घटना घटना-संचालित प्रणाली की मौलिक वर्ग इकाई है। इसमें एक प्रकार (जैसे मार्केट, सिग्नल, ऑर्डर या फिल) होता है जो यह निर्धारित करता है कि इसे घटना-लूप के भीतर कैसे संभाला जाएगा।
  • घटना कतार - घटना कतार एक इन-मेमोरी पायथन कतार वस्तु है जो बाकी सॉफ्टवेयर द्वारा उत्पन्न सभी घटना उप-वर्ग वस्तुओं को संग्रहीत करती है।
  • डेटा हैंडलर - डेटा हैंडलर एक अमूर्त आधार वर्ग (एबीसी) है जो ऐतिहासिक या लाइव बाजार डेटा दोनों को संभालने के लिए एक इंटरफ़ेस प्रस्तुत करता है। यह महत्वपूर्ण लचीलापन प्रदान करता है क्योंकि रणनीति और पोर्टफोलियो मॉड्यूल को इस प्रकार दोनों दृष्टिकोणों के बीच पुनः उपयोग किया जा सकता है। डेटा हैंडलर सिस्टम के हर दिल की धड़कन पर एक नया मार्केट इवेंट उत्पन्न करता है (नीचे देखें) ।
  • रणनीति - रणनीति एक एबीसी भी है जो बाजार डेटा लेने और संबंधित सिग्नल इवेंट उत्पन्न करने के लिए एक इंटरफ़ेस प्रस्तुत करती है, जिसका उपयोग पोर्टफोलियो ऑब्जेक्ट द्वारा किया जाता है। एक सिग्नल इवेंट में एक टिकर प्रतीक, एक दिशा (लंबी या छोटी) और एक टाइमस्टैम्प होता है।
  • पोर्टफोलियो - यह एक एबीसी है जो एक रणनीति के लिए वर्तमान और बाद की स्थिति से जुड़े ऑर्डर प्रबंधन को संभालता है। यह पोर्टफोलियो में जोखिम प्रबंधन भी करता है, जिसमें सेक्टर एक्सपोजर और स्थिति आकार शामिल हैं। एक अधिक परिष्कृत कार्यान्वयन में इसे जोखिम प्रबंधन वर्ग में सौंपा जा सकता है। पोर्टफोलियो कतार से सिग्नल इवेंट लेता है और ऑर्डर इवेंट उत्पन्न करता है जो कतार में जोड़े जाते हैं।
  • ExecutionHandler - ExecutionHandler एक ब्रोकर के साथ कनेक्शन का अनुकरण करता है। हैंडलर का काम ऑर्डर इवेंट्स को कतार से लेना और उन्हें निष्पादित करना है, या तो एक अनुकरणीय दृष्टिकोण या एक वास्तविक कनेक्शन के माध्यम से। एक बार ऑर्डर निष्पादित हो जाने के बाद हैंडलर FillEvents बनाता है, जो वास्तव में लेनदेन का वर्णन करता है, जिसमें शुल्क, कमीशन और फिसलन (यदि मॉडल किया गया है) शामिल हैं।
  • लूप - इन सभी घटकों को एक इवेंट-लूप में लपेटा जाता है जो सभी इवेंट प्रकारों को सही ढंग से संभालता है, उन्हें उपयुक्त घटक में रूट करता है।

यह एक ट्रेडिंग इंजन का काफी बुनियादी मॉडल है। विस्तार के लिए महत्वपूर्ण गुंजाइश है, विशेष रूप से पोर्टफोलियो का उपयोग कैसे किया जाता है के संबंध में। इसके अलावा विभिन्न लेनदेन लागत मॉडल को भी अपने स्वयं के वर्ग पदानुक्रम में सारित किया जा सकता है। इस चरण में यह इस श्रृंखला के लेखों के भीतर अनावश्यक जटिलता पेश करता है इसलिए हम वर्तमान में इस पर आगे चर्चा नहीं करेंगे। बाद के ट्यूटोरियल में हम संभवतः अतिरिक्त यथार्थवाद को शामिल करने के लिए प्रणाली का विस्तार करेंगे।

यहाँ पायथन कोड का एक स्निपेट है जो दर्शाता है कि बैकटेस्टर व्यवहार में कैसे काम करता है। कोड में दो लूप होते हैं। बाहरी लूप का उपयोग बैकटेस्टर को दिल की धड़कन देने के लिए किया जाता है। लाइव ट्रेडिंग के लिए यह वह आवृत्ति है जिस पर नए बाजार डेटा को पोल किया जाता है। बैकटेस्टिंग रणनीतियों के लिए यह सख्ती से आवश्यक नहीं है क्योंकि बैकटेस्टर ड्रिप-फीड रूप में प्रदान किए गए बाजार डेटा का उपयोग करता है (बार देखें।update_bars))) लाइन) ।

आंतरिक लूप वास्तव में घटनाओं की कतार ऑब्जेक्ट से घटनाओं को संभालता है। विशिष्ट घटनाओं को संबंधित घटक को सौंपा जाता है और बाद में नई घटनाओं को कतार में जोड़ा जाता है। जब घटनाओं की कतार खाली होती है, तो दिल की धड़कन लूप जारी रहती हैः

# Declare the components with respective parameters
bars = DataHandler(..)
strategy = Strategy(..)
port = Portfolio(..)
broker = ExecutionHandler(..)

while True:
    # Update the bars (specific backtest code, as opposed to live trading)
    if bars.continue_backtest == True:
        bars.update_bars()
    else:
        break
    
    # Handle the events
    while True:
        try:
            event = events.get(False)
        except Queue.Empty:
            break
        else:
            if event is not None:
                if event.type == 'MARKET':
                    strategy.calculate_signals(event)
                    port.update_timeindex(event)

                elif event.type == 'SIGNAL':
                    port.update_signal(event)

                elif event.type == 'ORDER':
                    broker.execute_order(event)

                elif event.type == 'FILL':
                    port.update_fill(event)

    # 10-Minute heartbeat
    time.sleep(10*60)

यह घटना-संचालित बैकटेस्टर के डिजाइन की मूल रूपरेखा है। अगले लेख में हम घटना वर्ग पदानुक्रम पर चर्चा करेंगे।


अधिक