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