# 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
. The __init__
constructor requires knowledge of the event queue. In addition, the order_routing
specification is order_routing
(the default is “SMART”). If it is necessary to describe any requirements related to a specific exchange, this can also be done here. The default currency is US dollars.fill_dict
, which will later be used to generate instances of FillEvent
. We will also create the tws_conn
object, which will store information for connecting to the broker API. In addition, you need to create an initial order_id
, which will be used to track subsequent id orders in order to avoid duplication. Finally, we register message handlers (we will define them below): # ib_execution.py class IBExecutionHandler(ExecutionHandler): """ API . """ def __init__(self, events, order_routing="SMART", currency="USD"): """ IBExecutionHandler. """ 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()
FillEvent
. The method asks if the message “openOrder” was received, and checks if the orderId for this is a corresponding mark in fill_dict
. If not, it is created.create_fill
is create_fill
to create a FillEvent
. In addition, for debugging and logging purposes, this message is displayed on the screen: # ib_execution.py def _error_handler(self, msg): """ «» . """ # print "Server Error: %s" % msg def _reply_handler(self, msg): """ """ # orderId 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) # 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
method is created - it is needed to connect to the broker API using the ibConnection object. By default, it uses port 7496 and clientId equal to 10. After creating the object, the connect method is called to connect directly: # ib_execution.py def create_tws_connection(self): """ 7496 clientId 10. clientId - Id , - . """ tws_conn = ibConnection() tws_conn.connect() return tws_conn
_initial_order_id
method. In our example, this id equals 1, but in a more elaborate system it would be possible to request the last available ID via the brokerage system API and use it. # ib_execution.py def create_initial_order_id(self): """ order ID, . """ # #, 1. return 1
register_handlers
method simply registers errors and methods for processing server responses: # ib_execution.py def register_handlers(self): """ . "" self.tws_conn.register(self._error_handler, 'Error') self.tws_conn.registerAll(self._reply_handler)
# ib_execution.py def create_contract(self, symbol, sec_type, exch, prim_exch, curr): """ Contract, , , . symbol - sec_type - ('STK' ) exch - , prim_exch - , curr - """ 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
method create_order
responsible for creating the second element of the pair — the Order instance. He needs the type of order (mart or limit), the number of shares for the transaction and the action (purchase or sale). It returns an instance of Order: # ib_execution.py def create_order(self, order_type, quantity, action): """ Order ( Market/Limit) long/short. order_type - 'MKT', 'LMT' Market Limit quantity – , action - 'BUY' 'SELL' """ order = Order() order.m_orderType = order_type order.m_totalQuantity = quantity order.m_action = action return order
FillEvent
for specific order IDs, we use the fill_dict
dictionary, which stores the keys for specific order identifiers. When an order execution message is generated, the key value filled for a specific ID is set to True. If the subsequent ServerResponse message from the brokerage system indicates that the order has been executed (and this duplicate message), then a new fill event is not created. # ib_execution.py def create_fill_dict_entry(self, msg): """ Fill Dictionary, orderID. - . """ self.fill_dict[msg.orderId] = { "symbol": msg.contract.m_symbol, "exchange": msg.contract.m_exchange, "direction": msg.order.m_action, "filled": False }
create_fill
method creates create_fill
events and places them in a queue: # ib_execution.py def create_fill(self, msg): """ FillEvent, """ fd = self.fill_dict[msg.orderId] # symbol = fd["symbol"] exchange = fd["exchange"] filled = msg.filled direction = fd["direction"] fill_cost = msg.avgFillPrice # FillEvent fill = FillEvent( datetime.datetime.utcnow(), symbol, exchange, filled, direction, fill_cost ) # , - self.fill_dict[msg.orderId]["filled"] = True # fill self.events.put(fill_event)
execute_order
method from the abstract base class ExecutionHandler
. In particular, this method is responsible for placing orders using the brokerage system API.OrderEvent
, and then prepare Contract and Order objects for it with the appropriate parameters. After they are created, the placeOrder
method from IbPy is called for the corresponding order_id
.time.sleep (1)
method to make sure that the order has actually passed to the brokerage system. Removing this parameter may result in inconsistent interaction with the API. # ib_execution.py def execute_order(self, event): """ API. fill, . : event – Event . """ if event.type == 'ORDER': # asset = event.symbol asset_type = "STK" order_type = event.order_type quantity = event.quantity direction = event.direction # Order ib_contract = self.create_contract( asset, asset_type, self.order_routing, self.order_routing, self.currency ) # Order ib_order = self.create_order( order_type, quantity, direction ) # self.tws_conn.placeOrder( self.order_id, ib_contract, ib_order ) # : # , ! time.sleep(1) # ID self.order_id += 1
Source: https://habr.com/ru/post/270215/
All Articles