class IBProvider(BaseProvider): def __init__(self): basicConfig() # These two variables are initialized in Connect method self._connection = None self._wrapper = None self._request_id = 0 def connect(self): self._wrapper = ReferenceWrapper() self._connection = EClientSocket(self._wrapper) self._connection.eConnect(IB_HOST, IB_PORT, IB_PROVIDER_CLIENT_ID) def disconnect(self): if self._connection.isConnected(): self._connection.eDisconnect() def _make_contract(self, symbol): contract = Contract() contract.m_symbol = symbol contract.m_secType = 'STK' contract.m_exchange = 'SMART' contract.m_primaryExch = 'SMART' contract.m_currency = 'USD' contract.m_localSymbol = symbol return contract def _get_next_request_id(self): self._request_id += 1 return self._request_id def get_market_depth_L1(self, symbol): contract = self._make_contract(symbol) request_id = self._get_next_request_id() self._connection.reqMktData(request_id, contract, '', True) while not self._wrapper.isExecutionRequestFinished(request_id): err = self._wrapper.getError(request_id) if err is not None: raise Exception(err) very_short_sleep() return self._wrapper.getMarketDepthL1(request_id)
class IBBroker(BaseBroker): def __init__(self): basicConfig() # These two variables are initialized in Connect method self._connection = None self._wrapper = None self._request_id = 0 def _get_next_request_id(self): self._request_id += 1 return self._request_id def get_security(self, symbol): contract = IBSecurity() contract.Symbol = symbol contract.symbol_id = 0 contract.Currency = 'USD' return contract def _get_next_valid_order_id(self): """ You must assign a unique order ID to each order you place. IB's servers keep track of the next available order ID you can use; this function requests that value from IB's servers, waits until IB sends a response, then returns the ID. """ last_time = self._wrapper._time_received_next_valid_order_id self._connection.reqIds(1) # Wait until IB sends the next valid ID while last_time == self._wrapper._time_received_next_valid_order_id: very_short_sleep() return self._wrapper._next_valid_order_id def _request_current_time(self): self._connection.reqCurrentTime() def connect(self): self._wrapper = ReferenceWrapper() self._connection = EClientSocket(self._wrapper) self._connection.eConnect(IB_HOST, IB_PORT, IB_CLIENT_ID) def disconnect(self): if self._connection.isConnected(): self._connection.eDisconnect() def send_pre_trade(self, trade_info): # trade info is fa profile self._connection.requestFA(self._connection.PROFILES) self._connection.replaceFA(self._connection.PROFILES, trade_info) def send_order(self, order): order.__class__ = IBOrder # casting to IBOrder order.prepare_IB_order() order_id = self._get_next_valid_order_id() contract = self.get_security(order.Symbol) #order.m_transmit = True # forces IB to transmit order straight away self._connection.placeOrder(order_id, contract, order) # places order order.Status = Order.StatusChoice.Sent.value # order status is set to SENT order.Order_Id = order_id # sets broker specific ID while not self._wrapper.isOpeningOfOrdersFinished(order_id): err = self._wrapper.getError(order_id) if err is not None: raise Exception(err) very_short_sleep() #if(self._wrapper.isError(id)): # raise Exception(self.wrapper.isError(id)) def update_orders(self, orders): requestId = self._get_next_request_id() exf = ExecutionFilter() distribution = {} self._connection.reqExecutions(requestId, exf) # while not self._wrapper.isExecutionRequestFinished(requestId): err = self._wrapper.getError(requestId) if err is not None: raise Exception(err) very_short_sleep() executions = self._wrapper.getExecutions(requestId) for order in orders: price = 0 shares = 0 if executions is not None: for execution in executions: if execution.m_shares > 0 and execution.m_orderId == order.Order_Id and not execution.m_acctNumber.startswith('DF'): price = execution.m_price if order.Symbol not in distribution: distribution[order.Symbol] = {} if execution.m_acctNumber not in distribution[order.Symbol]: distribution[order.Symbol][execution.m_acctNumber] = 0 distribution[order.Symbol][execution.m_acctNumber] += execution.m_shares shares += execution.m_shares if price != 0: order.setFills(price, shares) return distribution def get_account_info(self, broker_account): requestId = self._get_next_request_id() self._connection.reqAccountSummary(requestId, 'All', 'AccountType,TotalCashValue') while not self._wrapper.isExecutionRequestFinished(requestId): err = self._wrapper.getError(requestId) max_resp = self._wrapper.getMaxRequestFailureError() if err is not None: raise Exception(err) if max_resp: raise Exception("Maximum number of account summary requests exceeded") very_short_sleep() return self._wrapper.getAccountInfo(broker_account.ib_account)
# Connection and Server ############################################################## # EClientSocket # eConnect # eDisconnect ---> connectionClosed # isConnected # setServerLogLevel # reqCurrentTime ---> currentTime self.current_Time # serverVersion # TwsConnectionTime # ---> error ###################################################################################''' print "Testing Connection and Server Group \n" print tws.isConnected() tws.setServerLogLevel(5) tws.reqCurrentTime() print "Server Version " + str(tws.serverVersion()) print "TWS Connection Time %s " % tws.TwsConnectionTime() # Executions ######################################################################### # reqExecutions ---> execDetails self.exec_Details_reqId # self.exec_Details_contract # self.exec_Details_execution # ---> execDetailsEnd self.exec_DetailsEnd_flag # ---> commissionReport self.commission_Report ###################################################################################''' print "Testing Executions Group \n" order_id = [] tws.reqIds(1)
# Connection and Server ############################################################## # EClientSocket # eConnect # eDisconnect ---> connectionClosed # isConnected # setServerLogLevel # reqCurrentTime ---> currentTime self.current_Time # serverVersion # TwsConnectionTime # ---> error ###################################################################################''' print("Testing Connection and Server Group \n") print(tws.isConnected()) tws.setServerLogLevel(5) tws.reqCurrentTime() print("Server Version " + str(tws.serverVersion())) print("TWS Connection Time %s " % tws.TwsConnectionTime()) # Executions ######################################################################### # reqExecutions ---> execDetails self.exec_Details_reqId # self.exec_Details_contract # self.exec_Details_execution # ---> execDetailsEnd self.exec_DetailsEnd_flag # ---> commissionReport self.commission_Report ###################################################################################''' print("Testing Executions Group \n") order_id = [] tws.reqIds(1)
print( "\n###################### No orders to show #######################\n" ) return df_order_status # Establish connection ---------------------------------------------------------------------- #accountName = "Your Account Name Here" callback = IBWrapper() # Instantiate IBWrapper. callback tws = EClientSocket( callback) # Instantiate EClientSocket and return data to callback host = "" port = 4002 clientId = 8 tws.eConnect(host, port, clientId) # Connect to TWS create = contract() # Instantiate contract class callback.initiate_variables() tws.reqAccountUpdates(1, accountName) # Portfolio Query ------------------------------------------------------------ ib = IB() df_portfolio = ib.portfolio() count = len(df_portfolio) # Disconnect ------------------------------------------------------------------ time.sleep(2) tws.isConnected() tws.eDisconnect()
print('low than ratio') tws.cancelOrder(order_id) # preventing double transaction tws.reqIds(1) # Need to request next valid order Id time.sleep(1) # change this if next Id is empty order_id = data.next_ValidId contract = cont.create_contract('TVIX', 'STK', 'SMART', 'SMART', 'USD') order = cont.create_order(accountId, 'STP', position, 'SELL' ) tws.placeOrder(order_id, contract, order) tws.reqIds(1) # Need to request next valid order Id time.sleep(1) # change this if next Id is empty order_id = data.next_ValidId contract = cont.create_contract('UVXY', 'STK', 'SMART', 'SMART', 'USD') order = cont.create_order(accountId, 'STP', position, 'SELL' ) tws.placeOrder(order_id, contract, order) ''' time.sleep(2) if(tws.isConnected()): tws.eDisconnect() ''' Message: while loop?? tws.isConnected() outside while loop, so it disconnect when certain cond satisfied? scheduler to reconnect and disconnect (set up crontab on unix) '''
# Connection and Server ############################################################## # EClientSocket # eConnect # eDisconnect ---> connectionClosed # isConnected # setServerLogLevel # reqCurrentTime ---> currentTime self.current_Time # serverVersion # TwsConnectionTime # ---> error ###################################################################################''' print "Testing Connection and Server Group \n" print tws.isConnected() tws.setServerLogLevel(5) tws.reqCurrentTime() print "Server Version " + str(tws.serverVersion()) print "TWS Connection Time %s " % tws.TwsConnectionTime() # Executions ######################################################################### # reqExecutions ---> execDetails self.exec_Details_reqId # self.exec_Details_contract # self.exec_Details_execution # ---> execDetailsEnd self.exec_DetailsEnd_flag # ---> commissionReport self.commission_Report
class TWS_gateway(threading.Thread): # config config = None # redis connection rs = None # channel clients' requests to IB/TWS cli_request_handler = None # manage conID / contracts mapping contract_subscription_mgr = None connection = None # handler to process incoming IB/TWS messages and echo back to clients tws_event_handler = None # monitor IB connection / heart beat ibh = None tlock = None ib_conn_status = None ib_order_transmit = False def __init__(self, host, port, clientId, kafka_host, kafka_port, config): super(TWS_gateway, self).__init__() self.config = config self.host = host self.port = port self.clientId = clientId self.ib_order_transmit = config.get("tws_gateway", "tws_gateway.order_transmit").strip('"').strip("'") if \ config.get("tws_gateway", "tws_gateway.order_transmit").strip('"').strip("'") <> None\ else False logging.info('starting up TWS_gateway...') logging.info('Order straight through (no-touch) flag = %s' % ('True' if self.ib_order_transmit == True else 'False')) logging.info('connecting to Redis server...') self.initialize_redis(config) logging.info('starting up TWS_event_handler...') self.tws_event_handler = TWS_event_handler(kafka_host, kafka_port) logging.info('starting up IB EClientSocket...') self.connection = EClientSocket(self.tws_event_handler) logging.info('starting up client request handler - kafkaConsumer...') self.cli_request_handler = KafkaConsumer( *[(v,0) for v in list(TWS_Protocol.topicMethods) + list(TWS_Protocol.gatewayMethods) ], \ metadata_broker_list=['%s:%s' % (kafka_host, kafka_port)],\ group_id = 'epc.tws_gateway',\ auto_commit_enable=True,\ auto_commit_interval_ms=30 * 1000,\ auto_offset_reset='largest') # discard old ones self.reset_message_offset() if not self.eConnect(): logging.error( 'TWS_gateway: unable to establish connection to IB %s:%d' % (self.host, self.port)) sys.exit(-1) else: # start heart beat monitor logging.info('starting up IB heart beat monitor...') self.tlock = Lock() self.ibh = IbHeartBeat(config) self.ibh.register_listener([self.on_ib_conn_broken]) self.ibh.run() logging.info('starting up subscription manager...') self.initialize_subscription_mgr() def initialize_subscription_mgr(self): self.contract_subscription_mgr = SubscriptionManager(self) self.contract_subscription_mgr.register_persistence_callback( self.persist_subscriptions) key = self.config.get( "tws_gateway", "subscription_manager.subscriptions.redis_key").strip('"').strip( "'") if self.rs.get(key): #contracts = map(lambda x: ContractHelper.kvstring2contract(x), json.loads(self.rs.get(key))) def is_outstanding(c): today = time.strftime('%Y%m%d') if c.m_expiry < today: logging.info( 'initialize_subscription_mgr: ignoring expired contract %s%s%s' % (c.m_expiry, c.m_strike, c.m_right)) return False return True contracts = filter( lambda x: is_outstanding(x), map(lambda x: ContractHelper.kvstring2object(x, Contract), json.loads(self.rs.get(key)))) self.contract_subscription_mgr.load_subscription(contracts) def persist_subscriptions(self, contracts): key = self.config.get( "tws_gateway", "subscription_manager.subscriptions.redis_key").strip('"').strip( "'") #cs = json.dumps(map(lambda x: ContractHelper.contract2kvstring(x) if x <> None else None, contracts)) cs = json.dumps( map( lambda x: ContractHelper.object2kvstring(x) if x <> None else None, contracts)) logging.debug( 'Tws_gateway: updating subscription table to redis store %s' % cs) self.rs.set(key, cs) def initialize_redis(self, config): r_host = config.get("redis", "redis.server").strip('"').strip("'") r_port = config.get("redis", "redis.port") r_db = config.get("redis", "redis.db") self.rs = redis.Redis(r_host, r_port, r_db) try: self.rs.client_list() except redis.ConnectionError: logging.error( 'TWS_gateway: unable to connect to redis server using these settings: %s port:%d db:%d' % (r_host, r_port, r_db)) logging.error('aborting...') sys.exit(-1) def reset_message_offset(self): topic_offsets = map( lambda topic: (topic, self.cli_request_handler.get_partition_offsets( topic, 0, -1, 999)), TWS_Protocol.topicMethods + TWS_Protocol.gatewayMethods) topic_offsets = filter( lambda x: x <> None, map(lambda x: (x[0], x[1][1], x[1][0]) if len(x[1]) > 1 else None, topic_offsets)) logging.info('TWS_gateway set topic offset to the latest point\n%s' % (''.join('%s,%s,%s\n' % (x[0], x[1], x[2]) for x in topic_offsets))) # the set_topic_partitions method clears out all previous settings when executed # therefore it's not possible to call the function multiple times: # self.consumer.set_topic_partitions(('gw_subscriptions', 0, 114,) # self.consumer.set_topic_partitions(('tickPrice', 0, 27270,)) # as the second call will wipe out whatever was done previously self.cli_request_handler.set_topic_partitions(*topic_offsets) def run(self): for message in self.cli_request_handler: logging.info("%s:%d:%d: key=%s value=%s" % (message.topic, message.partition, message.offset, message.key, message.value)) # print ("TWS_gateway: received client request %s:%d:%d: key=%s value=%s" % (message.topic, message.partition, # message.offset, message.key, # message.value)) getattr(self, message.topic, None)(message.value) #self.cli_request_handler.task_done(message) def on_ib_conn_broken(self, msg): logging.error('TWS_gateway: detected broken IB connection!') self.ib_conn_status = 'ERROR' self.tlock.acquire() # this function may get called multiple times try: # block until another party finishes executing if self.ib_conn_status == 'OK': # check status return # if already fixed up while waiting, return self.eDisconnect() self.eConnect() while not self.connection.isConnected(): logging.error('TWS_gateway: attempt to reconnect...') self.eConnect() sleep(2) # we arrived here because the connection has been restored # resubscribe tickers again! logging.info( 'TWS_gateway: IB connection restored...resubscribe contracts') self.contract_subscription_mgr.force_resubscription() finally: self.tlock.release() def eConnect(self): logging.info('TWS_gateway - eConnect. Connecting to %s:%s App Id: %s' % (self.host, self.port, self.clientId)) self.connection.eConnect(self.host, self.port, self.clientId) return self.connection.isConnected() def reqAccountUpdates(self, value=None): logging.info('TWS_gateway - reqAccountUpdates value=%s' % value) self.connection.reqAccountUpdates(1, '') def reqAccountSummary(self, value): logging.info('TWS_gateway - reqAccountSummary value=%s' % value) vals = map( lambda x: x.encode('ascii') if isinstance(x, unicode) else x, json.loads(value)) self.connection.reqAccountSummary(vals[0], vals[1], vals[2]) def reqOpenOrders(self, value=None): self.connection.reqOpenOrders() def reqPositions(self, value=None): self.connection.reqPositions() def reqExecutions(self, value): try: filt = ExecutionFilter( ) if value == '' else ExecutionFilterHelper.kvstring2object( value, ExecutionFilter) self.connection.reqExecutions(0, filt) except: logging.error(traceback.format_exc()) def reqIds(self, value=None): self.connection.reqIds(1) def reqNewsBulletins(self): self.connection.reqNewsBulletins(1) def cancelNewsBulletins(self): self.connection.cancelNewsBulletins() def setServerLogLevel(self): self.connection.setServerLogLevel(3) def reqAutoOpenOrders(self): self.connection.reqAutoOpenOrders(1) def reqAllOpenOrders(self): self.connection.reqAllOpenOrders() def reqManagedAccts(self): self.connection.reqManagedAccts() def requestFA(self): self.connection.requestFA(1) def reqMktData(self, sm_contract): logging.info('TWS Gateway received reqMktData request: %s' % sm_contract) try: #self.contract_subscription_mgr.reqMktData(ContractHelper.kvstring2contract(sm_contract)) self.contract_subscription_mgr.reqMktData( ContractHelper.kvstring2object(sm_contract, Contract)) except: pass def reqHistoricalData(self): contract = Contract() contract.m_symbol = 'QQQQ' contract.m_secType = 'STK' contract.m_exchange = 'SMART' endtime = strftime('%Y%m%d %H:%M:%S') self.connection.reqHistoricalData(tickerId=1, contract=contract, endDateTime=endtime, durationStr='1 D', barSizeSetting='1 min', whatToShow='TRADES', useRTH=0, formatDate=1) def placeOrder(self, value=None): logging.info('TWS_gateway - placeOrder value=%s' % value) try: vals = json.loads(value) except ValueError: logging.error('TWS_gateway - placeOrder Exception %s' % traceback.format_exc()) return # c = ContractHelper.kvstring2contract(vals[1]) o = OrderHelper.kvstring2object(vals[2], Order) o.__dict__['transmit'] = self.ib_order_transmit # print c.__dict__ # print o.__dict__ # print '---------------------' #self.connection.placeOrder(vals[0], ContractHelper.kvstring2contract(vals[1]), OrderHelper.kvstring2object(vals[2], Order)) self.connection.placeOrder( vals[0], ContractHelper.kvstring2object(vals[1], Contract), OrderHelper.kvstring2object(vals[2], Order)) # self.connection.placeOrder(orderId, contract, newOptOrder) def eDisconnect(self, value=None): sleep(2) self.connection.eDisconnect() ####################################################################3 # Gateway commands def gw_req_subscriptions(self, value=None): #subm = map(lambda i: ContractHelper.contract2kvstring(self.contract_subscription_mgr.handle[i]), range(len(self.contract_subscription_mgr.handle))) #subm = map(lambda i: ContractHelper.object2kvstring(self.contract_subscription_mgr.handle[i]), range(len(self.contract_subscription_mgr.handle))) subm = map( lambda i: (i, ContractHelper.object2kvstring( self.contract_subscription_mgr.handle[i])), range(len(self.contract_subscription_mgr.handle))) print subm if subm: self.tws_event_handler.broadcast_event('gw_subscriptions', {'subscriptions': subm}, source='GW')