def get_open_orders(self, sid=None, accountCode='default'): self.log.debug(__name__ + '::get_open_orders') accountCode = self.validateAccountCode(accountCode) if sid == None: ans = {} for orderId in self.PORTFOLIO.orderStatusBook: if self.PORTFOLIO.orderStatusBook[orderId].status in [ 'PreSubmitted', 'Submitted' ]: tp = self.PORTFOLIO.orderStatusBook[orderId].contract security = from_contract_to_security(tp) security = search_security_in_Qdata( self.qData, security, self.logLevel) if security not in ans: ans[security] = [ self.PORTFOLIO.orderStatusBook[orderId] ] else: ans[security].append( self.PORTFOLIO.orderStatusBook[orderId]) return ans else: ans = [] for orderId in self.PORTFOLIO.orderStatusBook: if self.PORTFOLIO.orderStatusBook[orderId].status in [ 'PreSubmitted', 'Submitted' ]: tp = self.PORTFOLIO.orderStatusBook[orderId].contract security = from_contract_to_security(tp) security = search_security_in_Qdata( self.qData, security, self.logLevel) if same_security(sid, security): ans.append(self.PORTFOLIO.orderStatusBook[orderId]) return ans
def order_status_monitor(self, orderId, target_status, waitingTimeInSeconds=30): self.log.notset(__name__ + '::order_status_monitor') if orderId == -1: self.log.error(__name__ + '::order_status_monitor: EXIT, orderId=-1') exit() elif orderId == 0: return True else: timer = dt.datetime.now() exit_flag = True while (exit_flag): time.sleep(0.1) self.processMessages() accountCode = self.orderId_to_accountcode(orderId) accountCode = self.validateAccountCode(accountCode) if (dt.datetime.now() - timer).total_seconds() <= waitingTimeInSeconds: if self.PORTFOLIO.orderStatusBook[ orderId].status == 'Filled': self.log.info( __name__ + '::order_status_monitor: Filled ' + str(self.PORTFOLIO.orderStatusBook[orderId])) return True elif self.PORTFOLIO.orderStatusBook[ orderId].status == target_status: return True elif self.PORTFOLIO.orderStatusBook[ orderId].status == 'Inactive': self.log.error( __name__ + '::order_status_monitor: EXIT, status=Inactive!!!, orderId=%i, %s' % (orderId, str( from_contract_to_security( self.PORTFOLIO.orderStatusBook[orderId]. contract)))) exit() else: self.log.error( __name__ + '::order_status_monitor: EXIT, waiting time is too long, >%i, orderId=%i, %s, %s' % (waitingTimeInSeconds, orderId, str( from_contract_to_security( self.PORTFOLIO.orderStatusBook[orderId]. contract)), self.PORTFOLIO.orderStatusBook[orderId].status)) exit()
def execDetails(self, reqId, contract, execution): self.log.debug(__name__+'::execDetails: reqId= %i' %(int(reqId),) \ + str(from_contract_to_security(contract))) self.log.debug(__name__+'::execDetails: %s %s %s %s %s %s'\ %(str(execution.side),str(execution.shares),str(execution.price),\ str(execution.orderRef), str(execution.orderId), str(execution.clientId))) if self.validateAccountCode(execution.acctNumber): cashChange = execution.shares * float(execution.price) if execution.side == 'BOT': self.PORTFOLIO.cash -= cashChange elif execution.side == 'SLD': self.PORTFOLIO.cash += cashChange else: self.log.error( __name__ + '::execDetails: EXIT, cannot handle execution.side=' + execution.side) exit() self.log.debug(__name__ + '::execDetails: cash= %f' % (float(self.PORTFOLIO.cash), )) if execution.orderRef not in self.PORTFOLIO.performanceTracking: self.PORTFOLIO.performanceTracking[execution.orderRef]=\ pd.DataFrame({'security':'NA', 'action':'NA', 'quantity':0, 'avgFillPrice':0, 'virtualStrategyBalance':0}, index=[self.get_datetime()]) security = from_contract_to_security(contract) action = str(execution.side) quantity = float(execution.shares) avgFillPrice = float(execution.price) virtualStrategyBalance = self.track_performance( execution.orderRef, security, action, quantity, avgFillPrice, execution.acctNumber) #print self.PORTFOLIO.virtualHoldings #prev=self.PORTFOLIO.performanceTracking[execution.orderRef].ix[-1, 'virtualStrategyBalance'] #print prev,virtualStrategyBalance if virtualStrategyBalance == None: virtualStrategyBalance = np.nan newRow = pd.DataFrame( { 'security': str(security), 'action': action, 'quantity': quantity, 'avgFillPrice': avgFillPrice, 'virtualStrategyBalance': virtualStrategyBalance }, index=[self.get_datetime()]) self.PORTFOLIO.performanceTracking[execution.orderRef]=\ self.PORTFOLIO.performanceTracking[execution.orderRef].append(newRow)
def placeOrderWrapper(self, contract, order, ibpyRequest): self._log.debug( __name__ + '::placeOrderWrapper: contract=%s order=%s' % (print_IBCpp_contract(contract), print_IBCpp_order(order))) if isinstance(order.orderId, int): int_orderId = order.orderId else: int_orderId = self.use_next_id() order.orderId = int_orderId # Set for ending flat. # Otherwise, the following line in broker_client_factory::CallBacks::orderStatus will not be able to find a reqId # reqId = self.activeRequests.find_reqId_by_int_orderId(int_orderId) ibpyRequest.param['int_orderId'] = int_orderId ibpyOrderId = self._idConverter.fromIBtoBroker(int_orderId) # Register ibpyOrderId in SingleTrader so that it can search accountCode by incoming int_orderId self._singleTrader.set_from_send_req_to_server(self.name, order.account, ibpyOrderId) self.orderToBeProcessed[int_orderId] = (contract, order) self.simulateOpenOrder( int_orderId, contract, order, IBCpp.OrderState(), from_contract_to_security(contract).full_print()) # IBCpp function self.simulateOrderStatus(int_orderId, 'Submitted', 0, order.totalQuantity, 0.0, 0, 0, 0, 0, '') # IBCpp function self.simulate_process_order(self.get_datetime())
def reqHistoricalDataWrapper(self, reqId, contract, endTime, goBack, barSize, whatToShow, useRTH, formatDate): self._log.debug( __name__ + '::reqHistoricalDataWrapper: reqId=%s endTime=%s goBack=%s' % (reqId, endTime, goBack)) if endTime == '': # endTime='' is acceptable for clientIB, but not for brokerClient_Local # When endTime is processed, it will be converted to string from datetime. # However, the strptime function has difficulty with some timezones, for example, 'EDT' # The safe way is to convert to UTC first. endTime = self._timeGenerator.get_current_time().astimezone( pytz.timezone('UTC')) endTime = dt.datetime.strftime( endTime, "%Y%m%d %H:%M:%S %Z") # datetime -> string security = from_contract_to_security(contract) try: hist = self._dataProvider.provide_historical_data_from_local_variable_hist( security, endTime, goBack, barSize, whatToShow, useRTH, formatDate) except NotEnoughHist: self._log.info( 'Cannot find ingested hist for security=%s endTime=%s goBack=%s barSize=%s' % (security, endTime, goBack, barSize)) self._log.info( 'IBridgePy has to request historical data from broker %s to continue backtesting but it will be slow. Recommend to add HistIngestPlan in TEST_ME.py' % (self.getDataProvider().name, )) hist = self._dataProvider.provide_hist_from_a_true_dataProvider( security, endTime, goBack, barSize, whatToShow, useRTH, formatDate) # completion signals here self._sendHistoricalData(hist, reqId, formatDate)
def placeOrderWrapper(self, contract, order, ibpyRequest): self._validate_contract(contract, 'placeOrderWrapper') self._log.info('Place Order to %s security=%s order=%s' % (self.name, print_IBCpp_contract(contract), print_IBCpp_order(order))) tdOrder = OrderConverter().fromIBtoTD(contract, order) try: ibpyOrderId = self._tdClient.place_orders(order.account, tdOrder) except RuntimeError as e: if 'buying power' in str(e): raise NotEnoughFund() else: raise RuntimeError(e) if ibpyOrderId is None: raise RuntimeError('Place order to TD failed but there is not RuntimeError.') self._log.info('Order was placed to %s successfully. ibpyOrderId=%s' % (self.name, ibpyOrderId)) # Register int_orderId in _idConverter so that brokerClient::CallBack::orderStatus knows how to handle int_orderId int_orderId = self._idConverter.fromBrokerToIB(ibpyOrderId) self._idConverter.setRelationship(int_orderId, ibpyOrderId) # Set for ending flat. # Otherwise, the following line in broker_client_factory::CallBacks::orderStatus will not be able to find a reqId # reqId = self.activeRequests.find_reqId_by_int_orderId(int_orderId) ibpyRequest.param['int_orderId'] = int_orderId # Register ibpyOrderId in SingleTrader so that it can search accountCode by incoming int_orderId self._singleTrader.set_from_send_req_to_server(self.name, order.account, ibpyOrderId) # IBCpp function order.orderId = int_orderId self.simulateOpenOrder(int_orderId, contract, order, IBCpp.OrderState(), from_contract_to_security(contract).full_print()) # IBCpp function # IBCpp function, this is the ending flag for PlaceOrder self.simulateOrderStatus(int_orderId, 'Submitted', 0, order.totalQuantity, 0.0, 0, 0, 0, 0, '')
def reqMktDataWrapper(self, reqId, contract, genericTickList, snapshot): self._validate_contract(contract, 'reqMktDataWrapper') ans = None count = 1 while count <= 3: tp = self._tdClient.quote(str(contract.symbol)) ans = None symb = contract.symbol.upper() if symb in tp: ans = tp[symb] break else: self._log.error(__name__ + '::reqMktDataWrapper: requested %s to TD and error=%s. ' 'Hint: Sometimes, TD does not response to reqMktData for unknown reasons. ' 'IBridgePy will retry 3 times. attempt=%s' % (contract.symbol, tp, count)) count += 1 if count == 4: raise RuntimeError('EXIT, TD does not response to reqMktData for %s. IBridgePy retried and gave up.' % (contract.symbol,)) str_security = from_contract_to_security(contract).full_print() self.simulateTickPrice(reqId, IBCpp.TickType.ASK, float(ans['askPrice']), True, str_security) self.simulateTickPrice(reqId, IBCpp.TickType.BID, float(ans['bidPrice']), True, str_security) self.simulateTickPrice(reqId, IBCpp.TickType.LAST, float(ans['lastPrice']), True, str_security) self.simulateTickPrice(reqId, IBCpp.TickType.OPEN, float(ans['openPrice']), True, str_security) self.simulateTickPrice(reqId, IBCpp.TickType.CLOSE, float(ans['closePrice']), True, str_security) self.simulateTickSize(reqId, IBCpp.TickType.ASK_SIZE, int(ans['askSize']), str_security) self.simulateTickSize(reqId, IBCpp.TickType.BID_SIZE, int(ans['bidSize']), str_security)
def _get_all_positions(self, accountCode): allPositions = self._singleTrader.get_all_positions(self.brokerName, accountCode) ans = {} for str_security in allPositions: contract = allPositions[str_security].contract security = from_contract_to_security(contract) # adj_security = self.add_exchange_primaryExchange_to_security(security) # ans[adj_security] = allPositions[str_security] ans[security] = allPositions[str_security] return ans
def placeOrderWrapper(self, contract, order, ibpyRequest): instrument = self._robinhoodClient.instruments(contract.symbol)[0] action = OrderActionConverter().fromIBtoRB(order.action) tif = OrderTifConverter().fromIBtoRB(order.tif) quantity = int(order.totalQuantity) ans = None if order.orderType == OrderType.MKT: ans = self._robinhoodClient.place_market_order( action, instrument, quantity, tif) elif order.orderType == OrderType.LMT: ans = self._robinhoodClient.place_limit_order( action, instrument=instrument, limit_price=order.lmtPrice, quantity=quantity, time_in_force=tif) elif order.orderType == OrderType.STP: ans = self._robinhoodClient.place_stop_order( action, instrument=instrument, stop_price=order.auxPrice, quantity=quantity, time_in_force=tif) else: self._log.error( __name__ + '::placeOrderWrapper: EXIT, cannot handle orderType=%s' % (order.orderType, )) exit() ibpyOrderId = str(ans['id']) self._log.info('Order was placed to %s successfully. ibpyOrderId=%s' % (self.name, ibpyOrderId)) # Register int_orderId in _idConverter so that brokerClient::CallBack::orderStatus knows how to handle int_orderId int_orderId = self._idConverter.fromBrokerToIB(ibpyOrderId) self._idConverter.setRelationship(int_orderId, ibpyOrderId) # Set for ending flat. # Otherwise, the following line in broker_client_factory::CallBacks::orderStatus will not be able to find a reqId # reqId = self.activeRequests.find_reqId_by_int_orderId(int_orderId) ibpyRequest.param['int_orderId'] = int_orderId # Register ibpyOrderId in SingleTrader so that it can search accountCode by incoming int_orderId self._singleTrader.set_from_send_req_to_server(self.name, order.account, ibpyOrderId) # IBCpp function order.orderId = int_orderId self.simulateOpenOrder( int_orderId, contract, order, IBCpp.OrderState(), from_contract_to_security(contract).full_print()) # IBCpp function # IBCpp function, this is the ending flag for PlaceOrder self.simulateOrderStatus(int_orderId, 'Submitted', 0, order.totalQuantity, 0.0, 0, 0, 0, 0, '')
def count_open_orders(self, security='All', accountCode='default'): self.log.debug(__name__ + '::count_open_orders') accountCode = self.validateAccountCode(accountCode) count = 0 for orderId in self.PORTFOLIO.orderStatusBook: if self.PORTFOLIO.orderStatusBook[orderId].status not in [ 'Filled', 'Cancelled', 'Inactive' ]: if security == 'All': count += self.PORTFOLIO.orderStatusBook[orderId].amount else: tp = self.PORTFOLIO.orderStatusBook[orderId].contract tp = from_contract_to_security(tp) if same_security(tp, security): count += self.PORTFOLIO.orderStatusBook[orderId].amount return count
def reqMktDataWrapper(self, reqId, contract, genericTickList, snapshot): ans = self._robinhoodClient.get_quote(str(contract.symbol)) str_security = from_contract_to_security(contract).full_print() self.simulateTickPrice(reqId, IBCpp.TickType.ASK, float(ans['ask_price']), True, str_security) self.simulateTickPrice(reqId, IBCpp.TickType.BID, float(ans['bid_price']), True, str_security) self.simulateTickPrice(reqId, IBCpp.TickType.LAST, float(ans['last_trade_price']), True, str_security) self.simulateTickPrice(reqId, IBCpp.TickType.CLOSE, float(ans['previous_close']), True, str_security) self.simulateTickSize(reqId, IBCpp.TickType.ASK_SIZE, int(ans['ask_size']), str_security) self.simulateTickSize(reqId, IBCpp.TickType.BID_SIZE, int(ans['bid_size']), str_security)
def scannerData(self, reqId, rank, contractDetails, distance, benchmark, projection, legsStr): self._log.debug( __name__ + '::scannerData: reqId=%s rank=%s contractDetails.summary%s distance=%s benchmark=%s project=%s legsStr=%s' % (reqId, rank, print_IBCpp_contract(contractDetails.summary), distance, benchmark, projection, legsStr)) aRequest = self._activeRequests.get_by_reqId_otherwise_exit(reqId) security = from_contract_to_security(contractDetails.summary) newRow = pd.DataFrame( { 'rank': rank, # 'contractDetails': contractDetails, 'security': security, # 'distance': distance, # 'benchmark': benchmark, # 'projection': projection, # 'legsStr': legsStr }, index=[len(aRequest.returnedResult)]) aRequest.returnedResult = aRequest.returnedResult.append(newRow)
def contractDetails(self, reqId, contractDetails): """ IB callback function to receive str_security info """ self._log.notset(__name__ + '::contractDetails: reqId=%s contractDetails=%s' % (reqId, print_IBCpp_contractDetails(contractDetails))) aRequest = self._activeRequests.get_by_reqId_otherwise_exit(reqId) newRow = pd.DataFrame( { 'right': contractDetails.summary.right, 'strike': float(contractDetails.summary.strike), 'expiry': contractDetails.summary.expiry, 'contractName': print_IBCpp_contract(contractDetails.summary), 'security': from_contract_to_security(contractDetails.summary), 'contract': contractDetails.summary, 'multiplier': contractDetails.summary.multiplier, 'contractDetails': contractDetails }, index=[len(aRequest.returnedResult)]) aRequest.returnedResult = aRequest.returnedResult.append(newRow)
def position(self, accountCode, contract, position, price): """ call back function of IB C++ API which updates the position of a contract of a account """ self.log.debug(__name__ + '::position: ' + accountCode + ' ' + self._print_contract(contract) + ',' + str(position) + ', ' + str(price)) self.validateAccountCode(accountCode) security = from_contract_to_security(contract) adj_security = search_security_in_Qdata(self.qData, security, self.logLevel) if (not self.PORTFOLIO.positions) or (adj_security not in self.PORTFOLIO.positions): # a_security is not in positions, add it in it self.PORTFOLIO.positions[adj_security] = PositionClass() if position: self.PORTFOLIO.positions[adj_security].amount = position self.PORTFOLIO.positions[adj_security].cost_basis = price self.PORTFOLIO.positions[adj_security].accountCode = accountCode else: del self.PORTFOLIO.positions[adj_security]
def stripe_exchange_primaryExchange_from_contract(contract): security = from_contract_to_security(contract) return stripe_exchange_primaryExchange_from_security(security)
def simulate_process_order(self, timeNow): # to simulate placing order self._log.debug(__name__ + '::simulate_process_order: timeNow=%s' % (timeNow, )) if len(self.orderToBeProcessed) == 0: self._log.debug(__name__ + '::processOrder: No order to process') return for int_orderId in list(self.orderToBeProcessed.keys())[:]: contract, order = self.orderToBeProcessed[int_orderId] security = from_contract_to_security(contract) ask_price, bid_price, high_price, low_price = \ self._dataProvider.provide_real_time_price_from_local_variable_hist(security, timeNow, [IBCpp.TickType.ASK, IBCpp.TickType.BID, IBCpp.TickType.HIGH, IBCpp.TickType.LOW]) flag = False # if a order meets the processing conditions # based on the current prices, decide which pending orders should be processed/simulated this round. ex_price = 0.0 # avoid PEP8 warning if order.orderType == 'MKT': # for MKT order, just Fill it if order.action == 'BUY': ex_price = ask_price else: ex_price = bid_price flag = True elif order.orderType == 'LMT': # always assume simulation sequence: ask_price -> low_price -> high_price -> close_price if order.action == 'BUY': if order.lmtPrice >= ask_price: flag = True ex_price = ask_price elif low_price <= order.lmtPrice < ask_price: flag = True ex_price = order.lmtPrice else: flag = False else: # SELL if order.lmtPrice <= ask_price: flag = True ex_price = ask_price elif ask_price < order.lmtPrice <= high_price: flag = True ex_price = order.lmtPrice else: flag = False elif order.orderType == 'STP': ex_price = order.auxPrice if order.action == 'BUY': if order.auxPrice <= ask_price: flag = True ex_price = ask_price elif ask_price < order.auxPrice <= high_price: flag = True ex_price = order.auxPrice else: flag = False else: if order.auxPrice >= bid_price: flag = True ex_price = bid_price elif low_price <= order.auxPrice < bid_price: flag = True ex_price = order.auxPrice else: flag = False else: self._log.error( __name__ + '::simulate_process_order: cannot handle order.orderType = %s' % (order.orderType, )) exit() # this order should be processed/simulated right now if flag and ex_price > 0.001: # IBCpp call-back function self.simulateOrderStatus(int_orderId, 'Filled', order.totalQuantity, 0, ex_price, 0, 0, 0, 0, '') del self.orderToBeProcessed[int_orderId] # after an order is executed, need to simulate execDetails (call-back function) execution = IBCpp.Execution() execution.acctNumber = order.account execution.orderId = int_orderId if order.action == 'BUY': execution.side = 'BOT' else: execution.side = 'SLD' execution.shares = int(order.totalQuantity) execution.price = ex_price execution.orderRef = order.orderRef self.simulateExecDetails( -1, contract, execution, from_contract_to_security(contract).full_print()) # IBCpp::simulatePosition needs more calculation because it needs to consider the current # positions. oldPosition = self._singleTrader.get_position( self.name, self._accountCode, security) # print(__name__ + '::simulate_process_order:: oldPosition=%s' % (position,)) oldPrice = oldPosition.price hold = oldPosition.amount amount = None price = None if order.action == 'BUY': if hold + order.totalQuantity != 0: price = (oldPrice * hold + ex_price * order.totalQuantity) / ( hold + order.totalQuantity) else: price = 0.0 amount = hold + order.totalQuantity elif order.action == 'SELL': if hold == order.totalQuantity: price = 0.0 else: price = (oldPrice * hold - ex_price * order.totalQuantity) / ( hold - order.totalQuantity) amount = hold - order.totalQuantity self.simulatePosition( order.account, contract, amount, price, from_contract_to_security(contract).full_print()) self._transactionLog.info( '%s %s %s %s %s %s' % (self.get_datetime(), execution.orderId, from_contract_to_security(contract).full_print(), execution.side, execution.shares, execution.price))