यह कुछ समय हो गया है जब से हमने इवेंट-ड्राइव बैकटेस्टर पर विचार किया है, जिसके बारे में हमने इस लेख में चर्चा करना शुरू किया था। भाग VI में मैंने एक स्टैंड-इन निष्पादन हैंडलर मॉडल को कोड करने का वर्णन किया जो ऐतिहासिक बैकटेस्टिंग स्थिति के लिए काम करता था। इस लेख में हम एक लाइव ट्रेडिंग सिस्टम की ओर बढ़ने के लिए संबंधित इंटरएक्टिव ब्रोकर एपीआई हैंडलर को कोड करने जा रहे हैं।
मैंने पहले चर्चा की है कि कैसे ट्रेडर वर्कस्टेशन डाउनलोड करें और एक इंटरएक्टिव ब्रोकर डेमो खाता बनाएं और साथ ही IbPy का उपयोग करके IB API के लिए एक बुनियादी इंटरफ़ेस कैसे बनाएं। यह लेख बुनियादी IbPy इंटरफ़ेस को घटना-संचालित प्रणाली में लपेटेगा, ताकि जब यह लाइव बाजार फीड के साथ जोड़ा जाए, तो यह एक स्वचालित निष्पादन प्रणाली का आधार बनेगा।
IBExecutionHandler वर्ग का मूल विचार (नीचे देखें) घटनाओं की कतार से OrderEvent उदाहरण प्राप्त करना और फिर IbPy पुस्तकालय का उपयोग करके इंटरएक्टिव ब्रोकर ऑर्डर एपीआई के खिलाफ सीधे उन्हें निष्पादित करना है। कक्षा एपीआई के माध्यम से वापस भेजे गए
कक्षा स्वयं व्यवहार्य रूप से निष्पादन अनुकूलन तर्क के साथ-साथ परिष्कृत त्रुटि हैंडलिंग के साथ काफी जटिल हो सकती है। हालांकि, मैंने इसे अपेक्षाकृत सरल रखने का विकल्प चुना है ताकि आप मुख्य विचारों को देख सकें और इसे उस दिशा में विस्तारित कर सकें जो आपकी विशेष व्यापार शैली के अनुरूप है।
हमेशा की तरह, पहला कार्य पायथन फ़ाइल बनाना और आवश्यक पुस्तकालयों को आयात करना है। फ़ाइल को ib_execution.py कहा जाता है और अन्य घटना-संचालित फ़ाइलों के समान निर्देशिका में रहता है।
हम आवश्यक दिनांक/समय हैंडलिंग पुस्तकालयों, IbPy वस्तुओं और विशिष्ट घटना वस्तुओं है कि IBExecutionHandler द्वारा संभाला जाता है आयातः
# ib_execution.py
import datetime
import time
from ib.ext.Contract import Contract
from ib.ext.Order import Order
from ib.opt import ibConnection, message
from event import FillEvent, OrderEvent
from execution import ExecutionHandler
अब हम IBExecutionHandler वर्ग को परिभाषित करते हैं.आरंभ करनाconstructor सबसे पहले घटनाओं की कतार के ज्ञान की आवश्यकता है. यह भी order_routing के विनिर्देश की आवश्यकता है, जो मैं
विधि के भीतर हम एक fill_dict शब्दकोश बनाते हैं, जिसे बाद में FillEvent उदाहरणों को उत्पन्न करने में उपयोग के लिए आवश्यक है। हमें इंटरएक्टिव ब्रोकर एपीआई के लिए अपनी कनेक्शन जानकारी संग्रहीत करने के लिए एक tws_conn कनेक्शन ऑब्जेक्ट भी बनाना है। हमें एक प्रारंभिक डिफ़ॉल्ट आदेश_आईडी भी बनाना है, जो डुप्लिकेट से बचने के लिए सभी बाद के आदेशों का ट्रैक रखता है। अंत में हम संदेश हैंडलर पंजीकृत करते हैं (जिसे हम नीचे अधिक विस्तार से परिभाषित करेंगे):
# ib_execution.py
class IBExecutionHandler(ExecutionHandler):
"""
Handles order execution via the Interactive Brokers
API, for use against accounts when trading live
directly.
"""
def __init__(self, events,
order_routing="SMART",
currency="USD"):
"""
Initialises the IBExecutionHandler instance.
"""
self.events = events
self.order_routing = order_routing
self.currency = currency
self.fill_dict = {}
self.tws_conn = self.create_tws_connection()
self.order_id = self.create_initial_order_id()
self.register_handlers()
आईबी एपीआई एक संदेश-आधारित घटना प्रणाली का उपयोग करता है जो हमारी कक्षा को कुछ संदेशों के लिए विशिष्ट तरीकों से प्रतिक्रिया करने की अनुमति देता है, जो कि घटना-संचालित बैकटेस्टर के समान है। मैंने _error_handler विधि के माध्यम से टर्मिनल को आउटपुट के अलावा किसी भी वास्तविक त्रुटि हैंडलिंग (संक्षिप्तता के उद्देश्यों के लिए) को शामिल नहीं किया है।
दूसरी ओर, _reply_handler विधि का उपयोग यह निर्धारित करने के लिए किया जाता है कि FillEvent उदाहरण बनाने की आवश्यकता है या नहीं। विधि पूछती है कि क्या एक
यदि यह एक
# ib_execution.py
def _error_handler(self, msg):
"""
Handles the capturing of error messages
"""
# Currently no error handling.
print "Server Error: %s" % msg
def _reply_handler(self, msg):
"""
Handles of server replies
"""
# Handle open order orderId processing
if msg.typeName == "openOrder" and \
msg.orderId == self.order_id and \
not self.fill_dict.has_key(msg.orderId):
self.create_fill_dict_entry(msg)
# Handle Fills
if msg.typeName == "orderStatus" and \
msg.status == "Filled" and \
self.fill_dict[msg.orderId]["filled"] == False:
self.create_fill(msg)
print "Server Response: %s, %s\n" % (msg.typeName, msg)
निम्नलिखित विधि, create_tws_connection, IbPy ibConnection ऑब्जेक्ट का उपयोग करके IB API से कनेक्शन बनाता है। यह 7496 के डिफ़ॉल्ट पोर्ट और 10 के डिफ़ॉल्ट क्लाइंटआईडी का उपयोग करता है। एक बार ऑब्जेक्ट बनाए जाने के बाद, कनेक्ट विधि को कनेक्शन करने के लिए कहा जाता है:
# ib_execution.py
def create_tws_connection(self):
"""
Connect to the Trader Workstation (TWS) running on the
usual port of 7496, with a clientId of 10.
The clientId is chosen by us and we will need
separate IDs for both the execution connection and
market data connection, if the latter is used elsewhere.
"""
tws_conn = ibConnection()
tws_conn.connect()
return tws_conn
अलग आदेशों का ट्रैक रखने के लिए (ट्रैक भरने के प्रयोजनों के लिए) निम्न विधि create_initial_order_id का उपयोग किया जाता है। मैंने इसे डिफ़ॉल्ट रूप से
# ib_execution.py
def create_initial_order_id(self):
"""
Creates the initial order ID used for Interactive
Brokers to keep track of submitted orders.
"""
# There is scope for more logic here, but we
# will use "1" as the default for now.
return 1
निम्नलिखित विधि, register_handlers, केवल TWS कनेक्शन के साथ ऊपर परिभाषित त्रुटि और उत्तर हैंडलर विधियों को पंजीकृत करती है:
# ib_execution.py
def register_handlers(self):
"""
Register the error and server reply
message handling functions.
"""
# Assign the error handling function defined above
# to the TWS connection
self.tws_conn.register(self._error_handler, 'Error')
# Assign all of the server reply messages to the
# reply_handler function defined above
self.tws_conn.registerAll(self._reply_handler)
IbPy का उपयोग करने के बारे में पिछले ट्यूटोरियल की तरह हमें एक अनुबंध उदाहरण बनाने की आवश्यकता है और फिर इसे एक ऑर्डर उदाहरण के साथ जोड़ना है, जिसे IB एपीआई में भेजा जाएगा। निम्नलिखित विधि, create_contract, इस जोड़ी का पहला घटक उत्पन्न करती है। यह एक टिकर प्रतीक, एक सुरक्षा प्रकार (जैसे स्टॉक या भविष्य), एक विनिमय / प्राथमिक विनिमय और मुद्रा की उम्मीद करता है। यह अनुबंध उदाहरण लौटाता हैः
# ib_execution.py
def create_contract(self, symbol, sec_type, exch, prim_exch, curr):
"""
Create a Contract object defining what will
be purchased, at which exchange and in which currency.
symbol - The ticker symbol for the contract
sec_type - The security type for the contract ('STK' is 'stock')
exch - The exchange to carry out the contract on
prim_exch - The primary exchange to carry out the contract on
curr - The currency in which to purchase the contract
"""
contract = Contract()
contract.m_symbol = symbol
contract.m_secType = sec_type
contract.m_exchange = exch
contract.m_primaryExch = prim_exch
contract.m_currency = curr
return contract
निम्नलिखित विधि, create_order, जोड़ी का दूसरा घटक उत्पन्न करती है, अर्थात् ऑर्डर उदाहरण। यह एक ऑर्डर प्रकार (जैसे बाजार या सीमा), व्यापार करने के लिए परिसंपत्ति की मात्रा और एक
# ib_execution.py
def create_order(self, order_type, quantity, action):
"""
Create an Order object (Market/Limit) to go long/short.
order_type - 'MKT', 'LMT' for Market or Limit orders
quantity - Integral number of assets to order
action - 'BUY' or 'SELL'
"""
order = Order()
order.m_orderType = order_type
order.m_totalQuantity = quantity
order.m_action = action
return order
किसी विशेष ऑर्डर आईडी के लिए FillEvent उदाहरणों की दोहराव से बचने के लिए, हम एक शब्दकोश का उपयोग करते हैं जिसे fill_dict कहा जाता है, जो विशेष ऑर्डर आईडी से मेल खाने वाली कुंजियों को संग्रहीत करता है। जब एक भरने को उत्पन्न किया गया है, तो किसी विशेष ऑर्डर आईडी के लिए प्रविष्टि की
# ib_execution.py
def create_fill_dict_entry(self, msg):
"""
Creates an entry in the Fill Dictionary that lists
orderIds and provides security information. This is
needed for the event-driven behaviour of the IB
server message behaviour.
"""
self.fill_dict[msg.orderId] = {
"symbol": msg.contract.m_symbol,
"exchange": msg.contract.m_exchange,
"direction": msg.order.m_action,
"filled": False
}
निम्नलिखित विधि, create_fill, वास्तव में FillEvent उदाहरण बनाता है और इसे घटनाओं की कतार में रखता हैः
# ib_execution.py
def create_fill(self, msg):
"""
Handles the creation of the FillEvent that will be
placed onto the events queue subsequent to an order
being filled.
"""
fd = self.fill_dict[msg.orderId]
# Prepare the fill data
symbol = fd["symbol"]
exchange = fd["exchange"]
filled = msg.filled
direction = fd["direction"]
fill_cost = msg.avgFillPrice
# Create a fill event object
fill = FillEvent(
datetime.datetime.utcnow(), symbol,
exchange, filled, direction, fill_cost
)
# Make sure that multiple messages don't create
# additional fills.
self.fill_dict[msg.orderId]["filled"] = True
# Place the fill event onto the event queue
self.events.put(fill_event)
अब जब सभी पूर्ववर्ती विधियों को लागू किया गया है, तो यह ExecutionHandler अमूर्त आधार वर्ग से execute_order विधि को ओवरराइट करना बाकी है। यह विधि वास्तव में IB एपीआई के साथ ऑर्डर प्लेसमेंट करती है।
हम पहले जांचते हैं कि इस पद्धति को प्राप्त होने वाली घटना वास्तव में एक OrderEvent है और फिर अनुबंध और ऑर्डर ऑब्जेक्ट को उनके संबंधित मापदंडों के साथ तैयार करते हैं। एक बार दोनों बनाए जाने के बाद IbPy विधि placeOrder कनेक्शन ऑब्जेक्ट को संबंधित order_id के साथ कहा जाता है।
यह सुनिश्चित करने के लिए आदेश वास्तव में आईबी के माध्यम से चला जाता है समय.sleep))) विधि कॉल करने के लिए अत्यंत महत्वपूर्ण है। इस पंक्ति को हटाने एपीआई के असंगत व्यवहार के लिए नेतृत्व करता है, कम से कम मेरे सिस्टम पर!
अंत में, हम यह सुनिश्चित करने के लिए आदेश आईडी में वृद्धि करते हैं कि हम आदेश दोहराएं नहींः
# ib_execution.py
def execute_order(self, event):
"""
Creates the necessary InteractiveBrokers order object
and submits it to IB via their API.
The results are then queried in order to generate a
corresponding Fill object, which is placed back on
the event queue.
Parameters:
event - Contains an Event object with order information.
"""
if event.type == 'ORDER':
# Prepare the parameters for the asset order
asset = event.symbol
asset_type = "STK"
order_type = event.order_type
quantity = event.quantity
direction = event.direction
# Create the Interactive Brokers contract via the
# passed Order event
ib_contract = self.create_contract(
asset, asset_type, self.order_routing,
self.order_routing, self.currency
)
# Create the Interactive Brokers order via the
# passed Order event
ib_order = self.create_order(
order_type, quantity, direction
)
# Use the connection to the send the order to IB
self.tws_conn.placeOrder(
self.order_id, ib_contract, ib_order
)
# NOTE: This following line is crucial.
# It ensures the order goes through!
time.sleep(1)
# Increment the order ID for this session
self.order_id += 1
यह वर्ग एक इंटरएक्टिव ब्रोकर निष्पादन हैंडलर का आधार बनाता है और सिमुलेटेड निष्पादन हैंडलर के स्थान पर इस्तेमाल किया जा सकता है, जो केवल बैकटेस्टिंग के लिए उपयुक्त है। हालांकि, आईबी हैंडलर का उपयोग करने से पहले, बैकटेस्टर सिस्टम के ऐतिहासिक डेटा फीड हैंडलर को बदलने के लिए लाइव मार्केट फीड हैंडलर बनाना आवश्यक है। यह एक भविष्य के लेख का विषय होगा।
इस प्रकार हम बैकटेस्ट और लाइव सिस्टम से जितना संभव हो उतना पुनः उपयोग कर रहे हैं ताकि यह सुनिश्चित हो सके कि कोड