class Client(CallbackBase, EWrapper): cached_cds = dict() id_to_cd = dict() stk_base = {'m_secType': 'STK', 'm_exchange': 'SMART', 'm_currency': 'USD'} opt_base = {'m_secType': 'OPT', 'm_exchange': 'SMART', 'm_currency': 'USD'} ind_base = {'m_secType': 'IND', 'm_currency': 'USD'} fx_base = {'m_secType': 'CASH'} def __init__(self, client_id=9): self.client_id = client_id self.init_logger() self.req_id = 0 self.m_client = EClientSocket(self) self.tt = TickType() def init_logger(self): cid = '%2i' % self.client_id logger_fmt = ' '.join(['%(levelno)s, [%(asctime)s #%(process)5i]', 'client', cid, '%(levelname)8s: %(message)s']) self.logger = logging.getLogger(__name__) hdlr = TimedRotatingFileHandler('ib_client.log', when='midnight') fmt = logging.Formatter(fmt=logger_fmt) hdlr.setFormatter(fmt) self.logger.addHandler(hdlr) self.logger.setLevel(LOGLEVEL) def connect(self, host='', port=7496): self.m_client.eConnect(host, port, self.client_id) def disconnect(self): self.m_client.eDisconnect() self.logger.info('Client disconnected') id_to_localSymbol = dict() for cid in self.id_to_cd: id_to_localSymbol[cid] = self.id_to_cd[cid].m_summary.m_localSymbol fnm = 'id_to_localSymbol_%s.pkl' % datetime.now().isoformat() pickle.dump(id_to_localSymbol, open(fnm, 'w')) def request_contract_details(self, key): if key not in self.cached_cds: args = key._asdict() if type(key) == ContractId: if key[0] in self.id_to_cd: return [self.id_to_cd[key[0]]] elif type(key) in (Currency, CurrencyLocal): args.update(self.fx_base) elif type(key) == Index: args.update(self.ind_base) elif type(key) in (Option, OptionLocal): args.update(self.opt_base) elif type(key) == Stock: args.update(self.stk_base) else: errmsg = 'Valid arg types are %s; not %s' raise TypeError(errmsg % (', '.join(CONKEYTYPES), str(type(key)))) args = dict([(k, v) for (k, v) in args.items() if v]) contract = Contract(**args) self.req_id += 1 self.m_client.reqContractDetails(self.req_id, contract) while self.req_id not in (self.failed_contracts.keys() + self.fulfilled_contracts.keys()): sleep(.5) if self.req_id in self.failed_contracts: return None self.cached_cds[key] = self.req_cds[self.req_id] for cd in self.req_cds[self.req_id]: self.id_to_cd[cd.m_summary.m_conId] = cd return self.cached_cds[key] # Request data methods def request_mkt_data(self, contract, gtick_list='', snapshot=True, fname=None): self.req_id += 1 self.data_requests[self.req_id] = datetime.now() if not fname: fname = 'MKT_%i_%s.txt' % (contract.m_conId, gtick_list) self.data_req_fnames[self.req_id] = fname self.mkt_data[self.req_id] = (contract.m_conId, gtick_list) self.m_client.reqMktData(self.req_id, contract, gtick_list, snapshot) return self.req_id def start_realtime_bars(self, contract, show='TRADES', fname=None): if self.too_many_requests(): self.logger.error('Too many requests.') return None self.req_id += 1 self.data_requests[self.req_id] = datetime.now() self.realtime_bars[self.req_id] = (contract.m_conId, show) if not fname: fname = 'RTBARS_%i_%s.txt' % (contract.m_conId, show) self.data_req_fnames[self.req_id] = fname self.m_client.reqRealTimeBars(self.req_id, contract, 5, show, 0) self.logger.info('Realtime bars started for req_id %i', self.req_id) return self.req_id def request_historical_data(self, contract, end_time=None, duration='1 D', bar_size='1 min', show='TRADES', fname=None): if self.too_many_requests(): return None if not end_time: end_time = datetime.now().strftime('%Y%m%d %H:%M:%S') self.req_id += 1 self.data_requests[self.req_id] = datetime.now() self.historical_data[self.req_id] = (contract.m_conId, show) if not fname: fname = 'HSTBARS_%i_%s.txt' % (contract.m_conId, show) self.data_req_fnames[self.req_id] = fname self.m_client.reqHistoricalData(self.req_id, contract, end_time, duration, bar_size, show, 1, 1) return self.req_id def request_fundamentals(self, contract, report_type, fname=None): if self.too_many_requests(): return None self.req_id += 1 self.data_requests[self.req_id] = datetime.now() self.fundamentals[self.req_id] = (contract.m_conId, report_type) if not fname: fname = 'FND_%i_%s.txt' % (contract.m_conId, report_type) self.data_req_fnames[req_id] = fname self.m_client.reqFundamentalData(self.req_id, contract, report_type) return self.req_id # Cancel data methods def cancel_mkt_data(self, req_id): self.m_client.cancelMktData(req_id) del self.mkt_data[req_id] self.logger.info('Market data canceled for req_id %i', req_id) return True def cancel_realtime_bars(self, req_id): self.m_client.cancelRealTimeBars(req_id) del self.realtime_bars[req_id] self.logger.info('Realtime bars canceled for req_id %i', req_id) return True def cancel_historical_data(self, req_id): self.m_client.cancelHistoricalData(req_id) del self.historical_data[req_id] self.logger.info('Historical data canceled for req_id %i', req_id) return True def cancel_fundamentals(self, req_id): self.m_client.cancelFundamentalData(req_id) del self.fundamentals[req_id] self.logger.info('Fundamentals canceled for req_id %i', req_id) return True # Cancel all data methods def cancel_all_mkt_data(self): bar_ids = self.mkt_data.keys() [self.cancel_mkt_data(x) for x in bar_ids] def cancel_all_realtime_bars(self): bar_ids = self.realtime_bars.keys() [self.cancel_realtime_bars(x) for x in bar_ids] def cancel_all_historical_data(self): historical_ids = self.historical_data.keys() [self.cancel_historical_data(x) for x in historical_ids] def cancel_all_fundamentals(self): fundamental_ids = self.fundamentals.keys() [self.cancel_fundamentals(x) for x in fundamental_ids] # Orders and Executions methods def place_order(self, contract, order): order_id = self.nextId self.m_client.placeOrder(self.nextId, contract, order) self.m_client.reqIds(1) while order_id == self.nextId: self.logger.debug('Waiting for next order id') sleep(.1) return order_id def request_open_orders(self): self.m_client.reqOpenOrders() def request_all_orders(self): self.m_client.reqAllOpenOrders() def cancel_order(self, order_id): self.m_client.cancelOrder(order_id) del self.orders[self.client_id][order_id] def cancel_open_orders(self): self.request_open_orders() if self.client_id not in self.orders: self.logger.error('Client has no open orders') else: order_ids = self.orders[self.client_id].keys() [self.cancel_order(x) for x in order_ids if self.orders[self.client_id][x]['status'].lower() != 'cancelled'] def request_executions(self, client_id=None, time=None, symbol=None, sec_type=None, side=None, exchange=None): args = {'m_clientId': client_id, 'm_time': time, 'm_symbol': symbol, 'm_secType': sec_type, 'm_side': side, 'm_exchange': exchange} args = dict([(k, v) for (k, v) in args.items() if v]) self.req_id += 1 self.m_client.reqExecutions(self.req_id, ExecutionFilter(**args)) # Helper methods def too_many_requests(self): since = datetime.now() - timedelta(seconds=600) count =len([x for x in self.data_requests.values() if x > since]) if count >= 60: return True else: return False
class ClientManager: def __init__(self, host="localhost", port=7496, id=1): self.host = host self.port = port self.id = id self.subscriptions = {} self.subscriptionCounter = 1 wrapper = Wrapper() self.client = EClientSocket(wrapper) self.client.eConnect(host, port, id) time.sleep(5) def subscribeStock(self, symbol): contract = Contract() contract.m_symbol = symbol contract.m_exchange = "SMART" contract.m_currency = "USD" contract.m_secType = "STK" self.subscriptions[symbol] = self.subscriptionCounter self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter += 1 def subscribeFX(self, base, priceCur): """ base = base of the currency pair priceCur = currency for pricing ex. USD, JPY means buy/sell USD with price of JPY """ contract = Contract() contract.m_symbol = base contract.m_exchange = "IDEALPRO" contract.m_currency = priceCur contract.m_secType = "CASH" symbol = ".".join([base, priceCur]) self.subscriptions[symbol] = self.subscriptionCounter self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter += 1 def unsubscribeStock(self, symbol): if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.subscriptions.pop(symbol) def unsubscribeFX(self, base, priceCur): symbol = ".".join([base, priceCur]) if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.subscriptions.pop(symbol) def reqCurrentTime(self): print self.client.reqCurrentTime() def connected(self): return self.client.connected
class ClientManager: """ object that connects to the TWS gateway --> use an external program to drive this component """ def __init__(self, host="localhost", port=7496, id=1): self.host = host self.port = port self.id = id self.subscriptions = {} self.tickerMap = {} self.funcMap = self._defineFuncMap() self.subscriptionCounter = 1 self.wrapper = Wrapper() self.client = EClientSocket(self.wrapper) self.client.eConnect(host, port, id) time.sleep(5) def _defineFuncMap(self): funcMap = { "reqMktData": self.reqMktData, "cancelHistoricalData": self.cancelHistoricalData, "cancelRealTimeBars": self.cancelRealTimeBars, "reqHistoricalData": self.reqHistoricalData, "reqRealTimeBars": self.reqRealTimeBars, "reqContractDetails": self.reqContractDetails, "reqMktDepth": self.reqMktDepth, "cancelMktData": self.cancelMktData, "cancelMktDepth": self.cancelMktDepth, "exerciseOptions": self.exerciseOptions, "placeOrder": self.placeOrder, "reqAccountUpdates": self.reqAccountUpdates, "reqExecutions": self.reqExecutions, "cancelOrder": self.cancelOrder, "reqOpenOrders": self.reqOpenOrders, "reqIds": self.reqIds, "reqNewsBulletins": self.reqNewsBulletins, "cancelNewsBulletins": self.cancelNewsBulletins, "setServerLogLevel": self.setServerLogLevel, "reqAutoOpenOrders": self.reqAutoOpenOrders, "reqAllOpenOrders": self.reqAllOpenOrders, "reqManagedAccts": self.reqManagedAccts, "requestFA": self.requestFA, "replaceFA": self.replaceFA, "reqFundamentalData": self.reqFundamentalData, "cancelFundamentalData": self.cancelFundamentalData, "calculateImpliedVolatility": self.calculateImpliedVolatility, "cancelCalculateImpliedVolatility": self.cancelCalculateImpliedVolatility, "calculateOptionPrice": self.calculateOptionPrice, "cancelCalculateOptionPrice": self.cancelCalculateOptionPrice, "reqGlobalCancel": self.reqGlobalCancel, "reqMarketDataType": self.reqMarketDataType, "reqPositions": self.reqPositions, "cancelPositions": self.cancelPositions, "reqAccountSummary": self.reqAccountSummary, "cancelAccountSummary": self.cancelAccountSummary, "queryDisplayGroups": self.queryDisplayGroups, "subscribeToGroupEvents": self.subscribeToGroupEvents, "updateDisplayGroup": self.updateDisplayGroup, "unsubscribeFromGroupEvents": self.unsubscribeFromGroupEvents, } return funcMap def runCommand(self, **kwargs): """ takes in the commands from the run command function and then calls the appropriate command """ cmd = kwargs["cmd"] self.funcMap[cmd](**kwargs) def subscribeStock(self, **kwargs): symbol = kwargs["symbol"] contract = Contract() contract.m_symbol = symbol contract.m_exchange = "SMART" contract.m_currency = "USD" contract.m_secType = "STK" self.subscriptions[symbol] = self.subscriptionCounter self.tickerMap[self.subscriptionCounter] = symbol self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter += 1 def subscribeFX(self, **kwargs): """ base = base of the currency pair priceCur = currency for pricing ex. USD, JPY means buy/sell USD with price of JPY """ base = kwargs["base"] priceCur = kwargs["priceCur"] contract = Contract() contract.m_symbol = base contract.m_exchange = "IDEALPRO" contract.m_currency = priceCur contract.m_secType = "CASH" symbol = ".".join([base, priceCur]) self.subscriptions[symbol] = self.subscriptionCounter self.tickerMap[self.subscriptionCounter] = symbol self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter += 1 def unsubscribeStock(self, **kwargs): symbol = kwargs["symbol"] if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.tickerMap.pop(self.subscriptions.pop(symbol)) def unsubscribeFX(self, **kwargs): base = kwargs["base"] priceCur = kwargs["priceCur"] symbol = ".".join([base, priceCur]) if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.tickerMap.pop(self.subscriptions.pop(symbol)) ###Helper functions def _createContract(self, **kwargs): contract = Contract() if "contract_conId" in kwargs: contract.m_conId = kwargs["contract_conId"] if "contract_symbol" in kwargs: contract.m_symbol = kwargs["contract_symbol"] if "contract_secType" in kwargs: contract.m_secType = kwargs["contract_secType"] if "contract_expiry" in kwargs: contract.m_expiry = kwargs["contract_expiry"] if "contract_strike" in kwargs: contract.m_strike = kwargs["contract_strike"] if "contract_right" in kwargs: contract.m_right = kwargs["contract_right"] if "contract_multiplier" in kwargs: contract.m_multiplier = kwargs["contract_multiplier"] if "contract_exchange" in kwargs: contract.m_exchange = kwargs["contract_exchange"] if "contract_currency" in kwargs: contract.m_currency = kwargs["contract_currency"] if "contract_localSymbol" in kwargs: contract.m_localSymbol = kwargs["contract_localSymbol"] if "contract_tradingClass" in kwargs: contract.m_tradingClass = kwargs["contract_tradingClass"] if "contract_primaryExch" in kwargs: contract.m_primaryExch = kwargs[ "contract_primaryExch"] # pick a non-aggregate (ie not the SMART exchange) exchange that the contract trades on. DO NOT SET TO SMART. if "contract_includeExpired" in kwargs: contract.m_includeExpired = kwargs[ "contract_includeExpired"] # can not be set to true for contracts. if "contract_secIdType" in kwargs: contract.m_secIdType = kwargs[ "contract_secIdType"] # CUSIP;SEDOL;ISIN;RIC if "contract_secId" in kwargs: contract.m_secId = kwargs["contract_secId"] return contract def _createOrder(self, **kwargs): order = Order() # main order fields if "order_orderId" in kwargs: order.m_orderId = kwargs["order_orderId"] order.m_clientId = self.id if "order_permId" in kwargs: order.m_permId = kwargs["order_permId"] if "order_action" in kwargs: order.m_action = kwargs[ "order_action"] #values are BUY, SELL, SSHORT if "order_totalQuantity" in kwargs: order.m_totalQuantity = kwargs["order_totalQuantity"] if "order_orderType" in kwargs: order.m_orderType = kwargs["order_orderType"] if "order_lmtPrice" in kwargs: order.m_lmtPrice = kwargs["order_lmtPrice"] if "order_auxPrice" in kwargs: order.m_auxPrice = kwargs["order_auxPrice"] # extended order fields if "order_tif" in kwargs: order.m_tif = kwargs[ "order_tif"] # "Time in Force" - DAY, GTC, etc. if "order_activeStartTime" in kwargs: order.m_activeStartTime = kwargs[ "order_activeStartTime"] # GTC orders if "order_activeStopTime" in kwargs: order.m_activeStopTime = kwargs[ "order_activeStopTime"] # GTC orders YYYYMMDD hh:mm:ss (optional time zone) if "order_ocaGroup" in kwargs: order.m_ocaGroup = kwargs[ "order_ocaGroup"] # one cancels all group name if "order_ocaType" in kwargs: order.m_ocaType = kwargs[ "order_ocaType"] # 1 = CANCEL_WITH_BLOCK, 2 = REDUCE_WITH_BLOCK, 3 = REDUCE_NON_BLOCK if "order_orderRef" in kwargs: order.m_orderRef = kwargs["order_orderRef"] if "order_transmit" in kwargs: order.m_transmit = kwargs[ "order_transmit"] # if false, order will be created but not transmited if "order_parentId" in kwargs: order.m_parentId = kwargs[ "order_parentId"] # Parent order Id, to associate Auto STP or TRAIL orders with the original order. if "order_blockOrder" in kwargs: order.m_blockOrder = kwargs["order_blockOrder"] if "order_sweepToFill" in kwargs: order.m_sweepToFill = kwargs["order_sweepToFill"] if "order_displaySize" in kwargs: order.m_displaySize = kwargs["order_displaySize"] if "order_triggerMethod" in kwargs: order.m_triggerMethod = kwargs[ "order_triggerMethod"] # 0=Default, 1=Double_Bid_Ask, 2=Last, 3=Double_Last, 4=Bid_Ask, 7=Last_or_Bid_Ask, 8=Mid-point if "order_outsideRth" in kwargs: order.m_outsideRth = kwargs["order_outsideRth"] if "order_hidden" in kwargs: order.m_hidden = kwargs["order_hidden"] if "order_goodAfterTime" in kwargs: order.m_goodAfterTime = kwargs[ "order_goodAfterTime"] # FORMAT: 20060505 08:00:00 {time zone} if "order_goodTillDate" in kwargs: order.m_goodTillDate = kwargs[ "order_goodTillDate"] # FORMAT: 20060505 08:00:00 {time zone} order must be GTD if "order_overridePercentageConstraints" in kwargs: order.m_overridePercentageConstraints = kwargs[ "order_overridePercentageConstraints"] if "order_rule80A" in kwargs: order.m_rule80A = kwargs[ "order_rule80A"] # Individual = 'I', Agency = 'A', AgentOtherMember = 'W', IndividualPTIA = 'J', AgencyPTIA = 'U', AgentOtherMemberPTIA = 'M', IndividualPT = 'K', AgencyPT = 'Y', AgentOtherMemberPT = 'N' if "order_allOrNone" in kwargs: order.m_allOrNone = kwargs["order_allOrNone"] if "order_minQty" in kwargs: order.m_minQty = kwargs["order_minQty"] if "order_percentOffset" in kwargs: order.m_percentOffset = kwargs[ "order_percentOffset"] # REL orders only specify the decimal, e.g. .04 not 4 if "order_trailStopPrice" in kwargs: order.m_trailStopPrice = kwargs[ "order_trailStopPrice"] # for TRAILLIMIT orders only if "order_trailingPercent" in kwargs: order.m_trailingPercent = kwargs[ "order_trailingPercent"] # specify the percentage, e.g. 3, not .03 # Financial advisors only if "order_faGroup" in kwargs: order.m_faGroup = kwargs["order_faGroup"] if "order_faProfile" in kwargs: order.m_faProfile = kwargs["order_faProfile"] if "order_faMethod" in kwargs: order.m_faMethod = kwargs["order_faMethod"] if "order_faPercentage" in kwargs: order.m_faPercentage = kwargs["order_faPercentage"] # Institutional orders only if "order_openClose" in kwargs: order.m_openClose = kwargs["order_openClose"] # O=Open, C=Close if "order_origin" in kwargs: order.m_origin = kwargs["order_origin"] # 0=Customer, 1=Firm if "order_shortSaleSlot" in kwargs: order.m_shortSaleSlot = kwargs[ "order_shortSaleSlot"] # 1 if you hold the shares, 2 if they will be delivered from elsewhere. Only for Action="SSHORT if "order_designatedLocation" in kwargs: order.m_designatedLocation = kwargs[ "order_designatedLocation"] # set when slot=2 only. if "order_exemptCode" in kwargs: order.m_exemptCode = kwargs["order_exemptCode"] # SMART routing only if "order_discretionaryAmt" in kwargs: order.m_discretionaryAmt = kwargs["order_discretionaryAmt"] if "order_eTradeOnly" in kwargs: order.m_eTradeOnly = kwargs["order_eTradeOnly"] if "order_firmQuoteOnly" in kwargs: order.m_firmQuoteOnly = kwargs["order_firmQuoteOnly"] if "order_nbboPriceCap" in kwargs: order.m_nbboPriceCap = kwargs["order_nbboPriceCap"] if "order_optOutSmartRouting" in kwargs: order.m_optOutSmartRouting = kwargs["order_optOutSmartRouting"] # BOX or VOL ORDERS ONLY if "order_auctionStrategy" in kwargs: order.m_auctionStrategy = kwargs[ "order_auctionStrategy"] # 1=AUCTION_MATCH, 2=AUCTION_IMPROVEMENT, 3=AUCTION_TRANSPARENT # BOX ORDERS ONLY if "order_startingPrice" in kwargs: order.m_startingPrice = kwargs["order_startingPrice"] if "order_stockRefPrice" in kwargs: order.m_stockRefPrice = kwargs["order_stockRefPrice"] if "order_delta" in kwargs: order.m_delta = kwargs["order_delta"] # pegged to stock or VOL orders if "order_stockRangeLower" in kwargs: order.m_stockRangeLower = kwargs["order_stockRangeLower"] if "order_stockRangeUpper" in kwargs: order.m_stockRangeUpper = kwargs["order_stockRangeUpper"] # VOLATILITY ORDERS ONLY if "order_volatility" in kwargs: order.m_volatility = kwargs[ "order_volatility"] # enter percentage not decimal, e.g. 2 not .02 if "order_volatilityType" in kwargs: order.m_volatilityType = kwargs[ "order_volatilityType"] # 1=daily, 2=annual if "order_continuousUpdate" in kwargs: order.m_continuousUpdate = kwargs["order_continuousUpdate"] if "order_referencePriceType" in kwargs: order.m_referencePriceType = kwargs[ "order_referencePriceType"] # 1=Bid/Ask midpoint, 2 = BidOrAsk if "order_deltaNeutralOrderType" in kwargs: order.m_deltaNeutralOrderType = kwargs[ "order_deltaNeutralOrderType"] if "order_deltaNeutralAuxPrice" in kwargs: order.m_deltaNeutralAuxPrice = kwargs["order_deltaNeutralAuxPrice"] if "order_deltaNeutralConId" in kwargs: order.m_deltaNeutralConId = kwargs["order_deltaNeutralConId"] if "order_deltaNeutralSettlingFirm" in kwargs: order.m_deltaNeutralSettlingFirm = kwargs[ "order_deltaNeutralSettlingFirm"] if "order_deltaNeutralClearingAccount" in kwargs: order.m_deltaNeutralClearingAccount = kwargs[ "order_deltaNeutralClearingAccount"] if "order_deltaNeutralClearingIntent" in kwargs: order.m_deltaNeutralClearingIntent = kwargs[ "order_deltaNeutralClearingIntent"] if "order_deltaNeutralOpenClose" in kwargs: order.m_deltaNeutralOpenClose = kwargs[ "order_deltaNeutralOpenClose"] if "order_deltaNeutralShortSale" in kwargs: order.m_deltaNeutralShortSale = kwargs[ "order_deltaNeutralShortSale"] if "order_deltaNeutralShortSaleSlot" in kwargs: order.m_deltaNeutralShortSaleSlot = kwargs[ "order_deltaNeutralShortSaleSlot"] if "order_deltaNeutralDesignatedLocation" in kwargs: order.m_deltaNeutralDesignatedLocation = kwargs[ "order_deltaNeutralDesignatedLocation"] # COMBO ORDERS ONLY if "order_basisPoints" in kwargs: order.m_basisPoints = kwargs[ "order_basisPoints"] # EFP orders only, download only if "order_basisPointsType" in kwargs: order.m_basisPointsType = kwargs[ "order_basisPointsType"] # EFP orders only, download only # SCALE ORDERS ONLY if "order_scaleInitLevelSize" in kwargs: order.m_scaleInitLevelSize = kwargs["order_scaleInitLevelSize"] if "order_scaleSubsLevelSize" in kwargs: order.m_scaleSubsLevelSize = kwargs["order_scaleSubsLevelSize"] if "order_scalePriceIncrement" in kwargs: order.m_scalePriceIncrement = kwargs["order_scalePriceIncrement"] if "order_scalePriceAdjustValue" in kwargs: order.m_scalePriceAdjustValue = kwargs[ "order_scalePriceAdjustValue"] if "order_scalePriceAdjustInterval" in kwargs: order.m_scalePriceAdjustInterval = kwargs[ "order_scalePriceAdjustInterval"] if "order_scaleProfitOffset" in kwargs: order.m_scaleProfitOffset = kwargs["order_scaleProfitOffset"] if "order_scaleAutoReset" in kwargs: order.m_scaleAutoReset = kwargs["order_scaleAutoReset"] if "order_scaleInitPosition" in kwargs: order.m_scaleInitPosition = kwargs["order_scaleInitPosition"] if "order_scaleInitFillQty" in kwargs: order.m_scaleInitFillQty = kwargs["order_scaleInitFillQty"] if "order_scaleRandomPercent" in kwargs: order.m_scaleRandomPercent = kwargs["order_scaleRandomPercent"] if "order_scaleTable" in kwargs: order.m_scaleTable = kwargs["order_scaleTable"] # HEDGE ORDERS ONLY if "order_hedgeType" in kwargs: order.m_hedgeType = kwargs[ "order_hedgeType"] # 'D' - delta, 'B' - beta, 'F' - FX, 'P' - pair if "order_hedgeParam" in kwargs: order.m_hedgeParam = kwargs[ "order_hedgeParam"] # beta value for beta hedge (in range 0-1), ratio for pair hedge # Clearing info if "order_account" in kwargs: order.m_account = kwargs["order_account"] # IB account if "order_settlingFirm" in kwargs: order.m_settlingFirm = kwargs["order_settlingFirm"] if "order_clearingAccount" in kwargs: order.m_clearingAccount = kwargs[ "order_clearingAccount"] # True beneficiary of the order if "order_clearingIntent" in kwargs: order.m_clearingIntent = kwargs[ "order_clearingIntent"] # "" (Default), "IB", "Away", "PTA" (PostTrade) # ALGO ORDERS ONLY if "order_algoStrategy" in kwargs: order.m_algoStrategy = kwargs["order_algoStrategy"] if "order_algoParams" in kwargs: order.m_algoParams = kwargs["order_algoParams"] # What-if if "order_whatIf" in kwargs: order.m_whatIf = kwargs["order_whatIf"] # Not Held if "order_notHeld" in kwargs: order.m_notHeld = kwargs["order_notHeld"] # Smart combo routing params if "order_smartComboRoutingParams" in kwargs: order.m_smartComboRoutingParams = kwargs[ "order_smartComboRoutingParams"] # order combo legs #if "order_orderComboLegs" in kwargs: order.m_orderComboLegs = kwargs["order_orderComboLegs"] = new Vector<OrderComboLeg>() # order misc options if "order_orderMiscOptions" in kwargs: order.m_orderMiscOptions = kwargs["order_orderMiscOptions"] return order def connected(self, **kwargs): return self.client.connected def reqCurrentTime(self, **kwargs): return self.client.reqCurrentTime() def faMsgTypeName(self, **kwargs): return self.client.faMsgTypeName(int) def serverVersion(self, **kwargs): return self.client.serverVersion() def TwsConnectionTime(self, **kwargs): return self.client.TwsConnectionTime() def wrapper(self, **kwargs): return self.client.wrapper() def reader(self, **kwargs): return self.client.reader() def isConnected(self, **kwargs): return self.client.isConnected() def eConnect(self, **kwargs): host = kwargs["host"] port = kwargs["port"] id = kwargs["id"] self.client.eConnect(host, port, id) # def EClientSocket(self, **kwargs): # self.client.EClientSocket(AnyWrapper) # # # def eConnect(self, **kwargs): # self.client.eConnect(String, int, int, boolean) # # def createReader(self, **kwargs): # self.client.createReader(EClientSocket, DataInputStream) # # def eConnect(self, **kwargs): # self.client.eConnect(Socket, int) # # def eConnect(self, **kwargs): # self.client.eConnect(Socket) # def eDisconnect(self, **kwargs): self.client.eDisconnect() ###client functions for call backs #Not using scanners at the moment # def cancelScannerSubscription(self, **kwargs): # subscriptionId = kwargs["id"] # self.client.cancelScannerSubscription(int) # # def reqScannerParameters(self, **kwargs): # self.client.reqScannerParameters() # # def reqScannerSubscription(self, **kwargs): # self.client.reqScannerSubscription(int, ScannerSubscription, Vector<TagValue>) def reqMktData(self, **kwargs): """ function to request market data """ #contract information: requestId = kwargs["tickerId"] contract = self._createContract(**kwargs) tickList = kwargs.get("tickList", "") snapshot = kwargs.get("snapshot", False) self.client.reqMktData(requestId, contract, tickList, snapshot, []) def cancelHistoricalData(self, **kwargs): requestId = kwargs["tickerId"] self.client.cancelHistoricalData(requestId) def cancelRealTimeBars(self, **kwargs): requestId = kwargs["tickerId"] self.client.cancelRealTimeBars(requestId) def reqHistoricalData(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContratct() endDateTime = kwargs["endDateTime"] #format of yyyymmdd HH:mm:ss ttt durationStr = kwargs[ "durationStr"] #can look like 1000 S (int [S D W]) barSizeSetting = kwargs[ "barSizeSetting"] #valid values are: 1 sec|5 secs|15 secs|30 secs|1 min|2 mins|3 mins|5 mins|15 mins|30 mins|1 hour|1 day whatToShow = kwargs[ "whatToShow"] #valid values are: TRADES|MIDPOINT|BID|ASK|BID_ASK|HISTORICAL_VOLATILITY|OPTION_IMPLIED_VOLATILITY useRTH = bool( kwargs["useRTH"]) #0 for all data, 1 for market hours only formatDate = kwargs[ "formatDate"] #1 for yyyymmdd{space}{space}hh:mm:dd, 2 for timestamp value self.client.reqHistoricalData(requestId, contract, endDateTime, durationStr, barSizeSetting, whatToShow, useRTH, formatDate, []) def reqRealTimeBars(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContratct() barSize = 5 whatToShow = kwargs[ "whatToShow"] #valid values are: TRADES|MIDPOINT|BID|ASK|BID_ASK|HISTORICAL_VOLATILITY|OPTION_IMPLIED_VOLATILITY useRTH = bool( kwargs["useRTH"]) #0 for all data, 1 for market hours only self.client.reqRealTimeBars(requestId, contract, barSize, whatToShow, useRTH, []) def reqContractDetails(self, **kwargs): requestId = kwargs["reqId"] contract = self._createContract(**kwargs) self.client.reqContractDetails(requestId, contract) def reqMktDepth(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContract(**kwargs) depthRows = kwargs.get("depthRows", 1) self.client.reqMktDepth(requestId, contract, depthRows, []) def cancelMktData(self, **kwargs): """ cancels the market data request """ requestId = kwargs["tickerId"] self.client.cancelMktData(requestId) def cancelMktDepth(self, **kwargs): requestId = kwargs["tickerId"] self.client.cancelMktDepth(requestId) def exerciseOptions(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContract(**kwargs) exerciseAction = kwargs["exercise_action"] exerciseQty = kwargs["exercise_qty"] account = "" override = 0 #wonder what exchange this should be though if contract.m_exchange == "SMART": raise ("Exchange cannot be smart") self.client.exerciseOptions(requestId, contract, exerciseAction, exerciseQty, account, override) def placeOrder(self, **kwargs): requestId = kwargs["id"] contract = self._createContract(**kwargs) order = self._createOrder(**kwargs) self.client.placeOrder(requestId, contract, order) def reqAccountUpdates(self, **kwargs): subscribe = bool(kwargs["subscribe"]) acctCode = kwargs["acctCode"] self.client.reqAccountUpdates(subscribe, acctCode) def reqExecutions(self, **kwargs): requestId = kwargs["reqId"] executionFilter = ExecutionFilter() self.client.reqExecutions(requestId, executionFilter) def cancelOrder(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelOrder(requestId) def reqOpenOrders(self, **kwargs): self.client.reqOpenOrders() def reqIds(self, **kwargs): numIds = kwargs["numIds"] self.client.reqIds(numIds) def reqNewsBulletins(self, **kwargs): news = kwargs["news"] self.client.reqNewsBulletins(news) def cancelNewsBulletins(self, **kwargs): self.client.cancelNewsBulletins() def setServerLogLevel(self, **kwargs): # 1 = SYSTEM # 2 = ERROR # 3 = WARNING # 4 = INFORMATION # 5 = DETAIL logLevel = kwargs["logLevel"] self.client.setServerLogLevel(logLevel) def reqAutoOpenOrders(self, **kwargs): #If set to TRUE, newly created TWS orders will be implicitly associated with the client. If set to FALSE, no association will be made. bAutoBind = kwargs["bAutoBind"] self.client.reqAutoOpenOrders(bAutoBind) def reqAllOpenOrders(self, **kwargs): self.client.reqAllOpenOrders() def reqManagedAccts(self, **kwargs): self.client.reqManagedAccts() def requestFA(self, **kwargs): # 1 = GROUPS # 2 = PROFILE # 3 = ACCOUNT ALIASES faDataType = kwargs["faDataType"] self.client.requestFA(faDataType) def replaceFA(self, **kwargs): #Call this function to modify FA configuration information from the API. Note that this can also be done manually in TWS itself. faDataType = kwargs["faDataType"] cxml = kwargs["cxml"] self.client.replaceFA(faDataType, cxml) def reqFundamentalData(self, **kwargs): # report types # ReportSnapshot (company overview) # ReportsFinSummary (financial summary) # ReportRatios (financial ratios) # ReportsFinStatements (financial statements) # RESC (analyst estimates) # CalendarReport (company calendar) requestId = kwargs["reqId"] contract = self._createContract(**kwargs) reportType = kwargs["reportType"] self.client.reqFundamentalData(requestId, contract, reportType) def cancelFundamentalData(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelFundamentalData(requestId) def calculateImpliedVolatility(self, **kwargs): requestId = kwargs["reqId"] contract = self._createContract(**kwargs) optionPrice = kwargs["optionPrice"] underPrice = kwargs["underPrice"] self.client.calculateImpliedVolatility(requestId, contract, optionPrice, underPrice) def cancelCalculateImpliedVolatility(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelCalculateImpliedVolatility(requestId) def calculateOptionPrice(self, **kwargs): requestId = kwargs["requestId"] contract = self._createContract(**kwargs) volatility = kwargs["volatility"] underPrice = kwargs["underPrice"] self.client.calculateOptionPrice(requestId, contract, volatility, underPrice) def cancelCalculateOptionPrice(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelCalculateOptionPrice(requestId) def reqGlobalCancel(self, **kwargs): self.client.reqGlobalCancel() def reqMarketDataType(self, **kwargs): #1 for real-time streaming market data or 2 for frozen market data. marketDataType = kwargs["marketDataType"] self.client.reqMarketDataType(marketDataType) def reqPositions(self, **kwargs): self.client.reqPositions() def cancelPositions(self, **kwargs): self.client.cancelPositions() def reqAccountSummary(self, **kwargs): #This request can only be made when connected to a Financial Advisor (FA) account. requestId = kwargs["reqId"] group = kwargs["group"] tags = kwargs["tags"] self.client.reqAccountSummary(requestId, group, tags) def cancelAccountSummary(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelAccountSummary(requestId) # def verifyRequest(self, **kwargs): # self.client.verifyRequest(String, String) # # def verifyMessage(self, **kwargs): # self.client.verifyMessage(String) def queryDisplayGroups(self, **kwargs): requestId = kwargs["reqId"] self.client.queryDisplayGroups(requestId) def subscribeToGroupEvents(self, **kwargs): #groupId = The ID of the group, currently it is a number from 1 to 7. This is the display group subscription request sent by the API to TWS. requestId = kwargs["reqId"] groupId = kwargs["groupId"] self.client.subscribeToGroupEvents(requestId, groupId) def updateDisplayGroup(self, **kwargs): # contractInfo: # none = empty selection # contractID@exchange – any non-combination contract. Examples: 8314@SMART for IBM SMART; 8314@ARCA for IBM @ARCA. # combo = if any combo is selected. requestId = kwargs["reqId"] contractInfo = kwargs["contractInfo"] self.client.updateDisplayGroup(requestId, contractInfo) def unsubscribeFromGroupEvents(self, **kwargs): requestId = kwargs["reqId"] self.client.unsubscribeFromGroupEvents(requestId) def getData(self): """ called to get information out of the queue in the wrapper for information passing """ data = self.wrapper.queue.get() #this is specialized code to deal with mapping of ids to symbol information #work to create something more natural that is layer or at a different level? data["tickerId"] = self.tickerMap[data["tickerId"]] return data
class ClientManager: def __init__(self, host="localhost", port=7496, id=1): self.host=host self.port=port self.id=id self.subscriptions = {} self.tickerMap = {} self.subscriptionCounter = 1 self.wrapper = Wrapper() self.client=EClientSocket(self.wrapper) self.client.eConnect(host, port, id) time.sleep(5) def subscribeStock(self, symbol): contract = Contract() contract.m_symbol = symbol contract.m_exchange = "SMART" contract.m_currency = "USD" contract.m_secType = "STK" self.subscriptions[symbol] = self.subscriptionCounter self.tickerMap[self.subscriptionCounter] = symbol self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter+=1 def subscribeFX(self, base, priceCur): """ base = base of the currency pair priceCur = currency for pricing ex. USD, JPY means buy/sell USD with price of JPY """ contract = Contract() contract.m_symbol = base contract.m_exchange = "IDEALPRO" contract.m_currency = priceCur contract.m_secType = "CASH" symbol = ".".join([base, priceCur]) self.subscriptions[symbol] = self.subscriptionCounter self.tickerMap[self.subscriptionCounter] = symbol self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter+=1 def unsubscribeStock(self, symbol): if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.tickerMap.pop(self.subscriptions.pop(symbol)) def unsubscribeFX(self, base, priceCur): symbol = ".".join([base, priceCur]) if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.tickerMap.pop(self.subscriptions.pop(symbol)) def reqCurrentTime(self): print self.client.reqCurrentTime() def connected(self): return self.client.connected def getData(self): data = self.wrapper.queue.get() data["tickerId"] = self.tickerMap[data["tickerId"]] return data
class TWSEngine(stomp.ConnectionListener): """handle the trading related requests""" def __init__(self, host='127.0.0.1', port=7496, client_id=0): self.mgw = None self.host = host self.port = port self.client_id = client_id self.response_wrapper = ResponseWrapper() self.connection = EClientSocket(self.response_wrapper) self.response_wrapper.handler = self self.requested_market_data = {} # memory in case of connection loss def start(self): self.mgw.start() # start the messaging gateway def exit(self): if self.connection.connected: self.disconnect() self.mgw.unsubscribe('/queue/request') self.mgw.disconnect() def connect(self): log.info("connecting to TWS...") self.connection.eConnect(self.host, self.port, self.client_id) def disconnect(self): log.info("disconnecting IB gateway...") self.connection.eDisconnect() # stomp connection listener methods def on_connected(self, headers, body): self.mgw.subscribe('/queue/request') # connect and request the account, order, and portfolio updates self.connect() tries = 10 while not self.connection.connected: time.sleep(5) if not self.connection.connected: if tries == 0: log.error("trading gateway connection failed") return log.error("tws connection trying again...") self.connect() tries -= 1 else: break log.info("connection to TWS established") self.account_data_request() def on_message(self, headers, body): try: message = message_decode(body) except: log.error("unable to decode message body: %s" % body) else: self.handle_incoming(message) # message handler methods def handle_outgoing(self, obj, topic_or_queue='/topic/account'): message = message_encode(obj) log.debug("send: %r to '%s'" % (obj, topic_or_queue)) self.mgw.send(topic_or_queue, message) def handle_incoming(self, message): log.debug("recv: %r" % message) mtype = message['type'] method = getattr(self, "process_%s" % mtype, None) if not method: log.error("no processor found for message type: %s" % mtype) else: method(message) def handle_tick(self, tick): queue = '/queue/ticks/%s' % tick['id'] self.handle_outgoing(tick, queue) def handle_message_code(self, id, code, m): critical = [1100, 1300] error = [1101, 2100, 2101, 2103] warning = [2102, 2105] if id != -1: message = "id: %s, code: %s, message: %s" % (id, code, m) else: message = "code: %s, message: %s" % (code, m) if code in critical: log.critical(message) elif code <= 1000 or code in error: if code in [165, 202]: log.info(message) else: log.error(message) elif code in warning: log.warning(message) else: log.info(message) # code 1101: Connectivity between IB and TWS has been restored- data lost.* # *Market and account data subscription requests must be resubmitted # code 2100: New account data requested from TWS. # API client has been unsubscribed from account data. ** # **Account data subscription requests must be resubmitted if code in [1101, 2100]: self.account_data_request() if code == 1101: # TODO: PM: let client handle this (also with historical gap fill) # e.g. send a message with type 'error' to the /topic/account with the code 1101 for id, contract in self.requested_market_data.items(): self.tick_request(id, contract) # incoming message processors def process_place_order(self, message): message_contract = message['contract'] message_order = message['order'] order_id = message_order['order_id'] contract = self.create_contract(message_contract) order = self.create_order(message_order) self.place_order(order_id, contract, order) def process_cancel_order(self, message): order_id = message['order_id'] self.cancel_order(order_id) def process_historical_data_request(self, message): ticker_id = message['ticker_id'] message_contract = message['contract'] self.historical_data_request(ticker_id, message_contract) def process_tick_request(self, message): ticker_id = message['ticker_id'] message_contract = message['contract'] self.tick_request(ticker_id, message_contract) def process_cancel_market_data(self, message): ticker_id = message['ticker_id'] self.cancel_market_data(ticker_id) # order methods def create_contract(self, c): contract = Contract() contract.m_symbol = c['symbol'] contract.m_secType = c['secType'] contract.m_expiry = c['expiry'] contract.m_exchange = c['exchange'] contract.m_currency = c['currency'] return contract def create_order(self, o): order = Order() order.m_orderId = o['order_id'] order.m_clientId = self.client_id order.m_action = o['action'] order.m_totalQuantity = o['quantity'] if o['type'] == 'MKT': order.m_orderType = o['type'] # guaranteed execution order.m_lmtPrice = 0 order.m_auxPrice = 0 elif o['type'] == 'LMT_entry': order.m_orderType = o['type'][:3] order.m_lmtPrice = o['limit'] order.m_auxPrice = 0 order.m_tif = 'GTD' # TWS timeout gtt = o['trigger_timestamp'] + 300 # valid for 5 minutes enddate = datetime.fromtimestamp(gtt) # TWS expects date format: YYYYMMDD hh:mm:ss in the current # system's timezone gtd = datetime.strftime(enddate, "%Y%m%d %H:%M:%S") order.m_goodTillDate = gtd elif o['type'] == 'LMT_exit': # set group order.m_orderType = o['type'][:3] order.m_lmtPrice = o['limit'] order.m_auxPrice = 0 order.m_ocaGroup = o['ocagroup'] elif o['type'] == 'STP': order.m_orderType = o['type'] order.m_lmtPrice = 0 order.m_auxPrice = o['stop'] order.m_ocaGroup = o['ocagroup'] else: log.error("invalid order type: %s" % o['type']) return order def place_order(self, order_id, contract, order): self.connection.placeOrder(order_id, contract, order) def cancel_order(self, order_id): self.connection.cancelOrder(order_id) # TWS request methods def account_data_request(self): self.connection.reqAccountUpdates(True, "") self.connection.reqOpenOrders() def historical_data_request(self, ticker_id, ticker_contract, duration="2 D", bar_size="1 min"): contract = self.create_contract(ticker_contract) now = datetime.now() enddate = now + timedelta(hours=1) enddatestr = enddate.strftime("%Y%m%d %H:%M:%S") self.connection.reqHistoricalData(ticker_id, contract, enddatestr, duration, bar_size, "TRADES", 0, 2) def tick_request(self, ticker_id, ticker_contract): contract = self.create_contract(ticker_contract) self.connection.reqMktData(ticker_id, contract, None) self.requested_market_data[ticker_id] = ticker_contract def cancel_market_data(self, ticker_id): if self.requested_market_data.get(ticker_id, None): self.connection.cancelMktData(ticker_id) del self.requested_market_data[ticker_id]
class ClientManager: """ object that connects to the TWS gateway --> use an external program to drive this component """ def __init__(self, host="localhost", port=7496, id=1): self.host=host self.port=port self.id=id self.subscriptions = {} self.tickerMap = {} self.funcMap = self._defineFuncMap() self.subscriptionCounter = 1 self.wrapper = Wrapper() self.client=EClientSocket(self.wrapper) self.client.eConnect(host, port, id) time.sleep(5) def _defineFuncMap(self): funcMap = { "reqMktData": self.reqMktData, "cancelHistoricalData": self.cancelHistoricalData, "cancelRealTimeBars": self.cancelRealTimeBars, "reqHistoricalData": self.reqHistoricalData, "reqRealTimeBars": self.reqRealTimeBars, "reqContractDetails": self.reqContractDetails, "reqMktDepth": self.reqMktDepth, "cancelMktData": self.cancelMktData, "cancelMktDepth": self.cancelMktDepth, "exerciseOptions": self.exerciseOptions, "placeOrder": self.placeOrder, "reqAccountUpdates": self.reqAccountUpdates, "reqExecutions": self.reqExecutions, "cancelOrder": self.cancelOrder, "reqOpenOrders": self.reqOpenOrders, "reqIds": self.reqIds, "reqNewsBulletins": self.reqNewsBulletins, "cancelNewsBulletins": self.cancelNewsBulletins, "setServerLogLevel": self.setServerLogLevel, "reqAutoOpenOrders": self.reqAutoOpenOrders, "reqAllOpenOrders": self.reqAllOpenOrders, "reqManagedAccts": self.reqManagedAccts, "requestFA": self.requestFA, "replaceFA": self.replaceFA, "reqFundamentalData": self.reqFundamentalData, "cancelFundamentalData": self.cancelFundamentalData, "calculateImpliedVolatility": self.calculateImpliedVolatility, "cancelCalculateImpliedVolatility": self.cancelCalculateImpliedVolatility, "calculateOptionPrice": self.calculateOptionPrice, "cancelCalculateOptionPrice": self.cancelCalculateOptionPrice, "reqGlobalCancel": self.reqGlobalCancel, "reqMarketDataType": self.reqMarketDataType, "reqPositions": self.reqPositions, "cancelPositions": self.cancelPositions, "reqAccountSummary": self.reqAccountSummary, "cancelAccountSummary": self.cancelAccountSummary, "queryDisplayGroups": self.queryDisplayGroups, "subscribeToGroupEvents": self.subscribeToGroupEvents, "updateDisplayGroup": self.updateDisplayGroup, "unsubscribeFromGroupEvents": self.unsubscribeFromGroupEvents, } return funcMap def runCommand(self, **kwargs): """ takes in the commands from the run command function and then calls the appropriate command """ cmd = kwargs["cmd"] self.funcMap[cmd](**kwargs) def subscribeStock(self, **kwargs): symbol = kwargs["symbol"] contract = Contract() contract.m_symbol = symbol contract.m_exchange = "SMART" contract.m_currency = "USD" contract.m_secType = "STK" self.subscriptions[symbol] = self.subscriptionCounter self.tickerMap[self.subscriptionCounter] = symbol self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter+=1 def subscribeFX(self, **kwargs): """ base = base of the currency pair priceCur = currency for pricing ex. USD, JPY means buy/sell USD with price of JPY """ base = kwargs["base"] priceCur = kwargs["priceCur"] contract = Contract() contract.m_symbol = base contract.m_exchange = "IDEALPRO" contract.m_currency = priceCur contract.m_secType = "CASH" symbol = ".".join([base, priceCur]) self.subscriptions[symbol] = self.subscriptionCounter self.tickerMap[self.subscriptionCounter] = symbol self.client.reqMktData(self.subscriptionCounter, contract, "", False, []) self.subscriptionCounter+=1 def unsubscribeStock(self, **kwargs): symbol = kwargs["symbol"] if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.tickerMap.pop(self.subscriptions.pop(symbol)) def unsubscribeFX(self, **kwargs): base = kwargs["base"] priceCur = kwargs["priceCur"] symbol = ".".join([base, priceCur]) if symbol in self.subscription: self.client.cancelMktData(self.subscriptions[symbol]) self.tickerMap.pop(self.subscriptions.pop(symbol)) ###Helper functions def _createContract(self, **kwargs): contract = Contract() if "contract_conId" in kwargs: contract.m_conId = kwargs["contract_conId"] if "contract_symbol" in kwargs: contract.m_symbol = kwargs["contract_symbol"] if "contract_secType" in kwargs: contract.m_secType = kwargs["contract_secType"] if "contract_expiry" in kwargs: contract.m_expiry = kwargs["contract_expiry"] if "contract_strike" in kwargs: contract.m_strike = kwargs["contract_strike"] if "contract_right" in kwargs: contract.m_right = kwargs["contract_right"] if "contract_multiplier" in kwargs: contract.m_multiplier = kwargs["contract_multiplier"] if "contract_exchange" in kwargs: contract.m_exchange = kwargs["contract_exchange"] if "contract_currency" in kwargs: contract.m_currency = kwargs["contract_currency"] if "contract_localSymbol" in kwargs: contract.m_localSymbol = kwargs["contract_localSymbol"] if "contract_tradingClass" in kwargs: contract.m_tradingClass = kwargs["contract_tradingClass"] if "contract_primaryExch" in kwargs: contract.m_primaryExch = kwargs["contract_primaryExch"] # pick a non-aggregate (ie not the SMART exchange) exchange that the contract trades on. DO NOT SET TO SMART. if "contract_includeExpired" in kwargs: contract.m_includeExpired = kwargs["contract_includeExpired"] # can not be set to true for contracts. if "contract_secIdType" in kwargs: contract.m_secIdType = kwargs["contract_secIdType"] # CUSIP;SEDOL;ISIN;RIC if "contract_secId" in kwargs: contract.m_secId = kwargs["contract_secId"] return contract def _createOrder(self, **kwargs): order = Order() # main order fields if "order_orderId" in kwargs: order.m_orderId = kwargs["order_orderId"] order.m_clientId = self.id if "order_permId" in kwargs: order.m_permId = kwargs["order_permId"] if "order_action" in kwargs: order.m_action = kwargs["order_action"] #values are BUY, SELL, SSHORT if "order_totalQuantity" in kwargs: order.m_totalQuantity = kwargs["order_totalQuantity"] if "order_orderType" in kwargs: order.m_orderType = kwargs["order_orderType"] if "order_lmtPrice" in kwargs: order.m_lmtPrice = kwargs["order_lmtPrice"] if "order_auxPrice" in kwargs: order.m_auxPrice = kwargs["order_auxPrice"] # extended order fields if "order_tif" in kwargs: order.m_tif = kwargs["order_tif"] # "Time in Force" - DAY, GTC, etc. if "order_activeStartTime" in kwargs: order.m_activeStartTime = kwargs["order_activeStartTime"] # GTC orders if "order_activeStopTime" in kwargs: order.m_activeStopTime = kwargs["order_activeStopTime"] # GTC orders YYYYMMDD hh:mm:ss (optional time zone) if "order_ocaGroup" in kwargs: order.m_ocaGroup = kwargs["order_ocaGroup"] # one cancels all group name if "order_ocaType" in kwargs: order.m_ocaType = kwargs["order_ocaType"] # 1 = CANCEL_WITH_BLOCK, 2 = REDUCE_WITH_BLOCK, 3 = REDUCE_NON_BLOCK if "order_orderRef" in kwargs: order.m_orderRef = kwargs["order_orderRef"] if "order_transmit" in kwargs: order.m_transmit = kwargs["order_transmit"] # if false, order will be created but not transmited if "order_parentId" in kwargs: order.m_parentId = kwargs["order_parentId"] # Parent order Id, to associate Auto STP or TRAIL orders with the original order. if "order_blockOrder" in kwargs: order.m_blockOrder = kwargs["order_blockOrder"] if "order_sweepToFill" in kwargs: order.m_sweepToFill = kwargs["order_sweepToFill"] if "order_displaySize" in kwargs: order.m_displaySize = kwargs["order_displaySize"] if "order_triggerMethod" in kwargs: order.m_triggerMethod = kwargs["order_triggerMethod"] # 0=Default, 1=Double_Bid_Ask, 2=Last, 3=Double_Last, 4=Bid_Ask, 7=Last_or_Bid_Ask, 8=Mid-point if "order_outsideRth" in kwargs: order.m_outsideRth = kwargs["order_outsideRth"] if "order_hidden" in kwargs: order.m_hidden = kwargs["order_hidden"] if "order_goodAfterTime" in kwargs: order.m_goodAfterTime = kwargs["order_goodAfterTime"] # FORMAT: 20060505 08:00:00 {time zone} if "order_goodTillDate" in kwargs: order.m_goodTillDate = kwargs["order_goodTillDate"] # FORMAT: 20060505 08:00:00 {time zone} order must be GTD if "order_overridePercentageConstraints" in kwargs: order.m_overridePercentageConstraints = kwargs["order_overridePercentageConstraints"] if "order_rule80A" in kwargs: order.m_rule80A = kwargs["order_rule80A"] # Individual = 'I', Agency = 'A', AgentOtherMember = 'W', IndividualPTIA = 'J', AgencyPTIA = 'U', AgentOtherMemberPTIA = 'M', IndividualPT = 'K', AgencyPT = 'Y', AgentOtherMemberPT = 'N' if "order_allOrNone" in kwargs: order.m_allOrNone = kwargs["order_allOrNone"] if "order_minQty" in kwargs: order.m_minQty = kwargs["order_minQty"] if "order_percentOffset" in kwargs: order.m_percentOffset = kwargs["order_percentOffset"] # REL orders only specify the decimal, e.g. .04 not 4 if "order_trailStopPrice" in kwargs: order.m_trailStopPrice = kwargs["order_trailStopPrice"] # for TRAILLIMIT orders only if "order_trailingPercent" in kwargs: order.m_trailingPercent = kwargs["order_trailingPercent"] # specify the percentage, e.g. 3, not .03 # Financial advisors only if "order_faGroup" in kwargs: order.m_faGroup = kwargs["order_faGroup"] if "order_faProfile" in kwargs: order.m_faProfile = kwargs["order_faProfile"] if "order_faMethod" in kwargs: order.m_faMethod = kwargs["order_faMethod"] if "order_faPercentage" in kwargs: order.m_faPercentage = kwargs["order_faPercentage"] # Institutional orders only if "order_openClose" in kwargs: order.m_openClose = kwargs["order_openClose"] # O=Open, C=Close if "order_origin" in kwargs: order.m_origin = kwargs["order_origin"] # 0=Customer, 1=Firm if "order_shortSaleSlot" in kwargs: order.m_shortSaleSlot = kwargs["order_shortSaleSlot"] # 1 if you hold the shares, 2 if they will be delivered from elsewhere. Only for Action="SSHORT if "order_designatedLocation" in kwargs: order.m_designatedLocation = kwargs["order_designatedLocation"] # set when slot=2 only. if "order_exemptCode" in kwargs: order.m_exemptCode = kwargs["order_exemptCode"] # SMART routing only if "order_discretionaryAmt" in kwargs: order.m_discretionaryAmt = kwargs["order_discretionaryAmt"] if "order_eTradeOnly" in kwargs: order.m_eTradeOnly = kwargs["order_eTradeOnly"] if "order_firmQuoteOnly" in kwargs: order.m_firmQuoteOnly = kwargs["order_firmQuoteOnly"] if "order_nbboPriceCap" in kwargs: order.m_nbboPriceCap = kwargs["order_nbboPriceCap"] if "order_optOutSmartRouting" in kwargs: order.m_optOutSmartRouting = kwargs["order_optOutSmartRouting"] # BOX or VOL ORDERS ONLY if "order_auctionStrategy" in kwargs: order.m_auctionStrategy = kwargs["order_auctionStrategy"] # 1=AUCTION_MATCH, 2=AUCTION_IMPROVEMENT, 3=AUCTION_TRANSPARENT # BOX ORDERS ONLY if "order_startingPrice" in kwargs: order.m_startingPrice = kwargs["order_startingPrice"] if "order_stockRefPrice" in kwargs: order.m_stockRefPrice = kwargs["order_stockRefPrice"] if "order_delta" in kwargs: order.m_delta = kwargs["order_delta"] # pegged to stock or VOL orders if "order_stockRangeLower" in kwargs: order.m_stockRangeLower = kwargs["order_stockRangeLower"] if "order_stockRangeUpper" in kwargs: order.m_stockRangeUpper = kwargs["order_stockRangeUpper"] # VOLATILITY ORDERS ONLY if "order_volatility" in kwargs: order.m_volatility = kwargs["order_volatility"] # enter percentage not decimal, e.g. 2 not .02 if "order_volatilityType" in kwargs: order.m_volatilityType = kwargs["order_volatilityType"] # 1=daily, 2=annual if "order_continuousUpdate" in kwargs: order.m_continuousUpdate = kwargs["order_continuousUpdate"] if "order_referencePriceType" in kwargs: order.m_referencePriceType = kwargs["order_referencePriceType"] # 1=Bid/Ask midpoint, 2 = BidOrAsk if "order_deltaNeutralOrderType" in kwargs: order.m_deltaNeutralOrderType = kwargs["order_deltaNeutralOrderType"] if "order_deltaNeutralAuxPrice" in kwargs: order.m_deltaNeutralAuxPrice = kwargs["order_deltaNeutralAuxPrice"] if "order_deltaNeutralConId" in kwargs: order.m_deltaNeutralConId = kwargs["order_deltaNeutralConId"] if "order_deltaNeutralSettlingFirm" in kwargs: order.m_deltaNeutralSettlingFirm = kwargs["order_deltaNeutralSettlingFirm"] if "order_deltaNeutralClearingAccount" in kwargs: order.m_deltaNeutralClearingAccount = kwargs["order_deltaNeutralClearingAccount"] if "order_deltaNeutralClearingIntent" in kwargs: order.m_deltaNeutralClearingIntent = kwargs["order_deltaNeutralClearingIntent"] if "order_deltaNeutralOpenClose" in kwargs: order.m_deltaNeutralOpenClose = kwargs["order_deltaNeutralOpenClose"] if "order_deltaNeutralShortSale" in kwargs: order.m_deltaNeutralShortSale = kwargs["order_deltaNeutralShortSale"] if "order_deltaNeutralShortSaleSlot" in kwargs: order.m_deltaNeutralShortSaleSlot = kwargs["order_deltaNeutralShortSaleSlot"] if "order_deltaNeutralDesignatedLocation" in kwargs: order.m_deltaNeutralDesignatedLocation = kwargs["order_deltaNeutralDesignatedLocation"] # COMBO ORDERS ONLY if "order_basisPoints" in kwargs: order.m_basisPoints = kwargs["order_basisPoints"] # EFP orders only, download only if "order_basisPointsType" in kwargs: order.m_basisPointsType = kwargs["order_basisPointsType"] # EFP orders only, download only # SCALE ORDERS ONLY if "order_scaleInitLevelSize" in kwargs: order.m_scaleInitLevelSize = kwargs["order_scaleInitLevelSize"] if "order_scaleSubsLevelSize" in kwargs: order.m_scaleSubsLevelSize = kwargs["order_scaleSubsLevelSize"] if "order_scalePriceIncrement" in kwargs: order.m_scalePriceIncrement = kwargs["order_scalePriceIncrement"] if "order_scalePriceAdjustValue" in kwargs: order.m_scalePriceAdjustValue = kwargs["order_scalePriceAdjustValue"] if "order_scalePriceAdjustInterval" in kwargs: order.m_scalePriceAdjustInterval = kwargs["order_scalePriceAdjustInterval"] if "order_scaleProfitOffset" in kwargs: order.m_scaleProfitOffset = kwargs["order_scaleProfitOffset"] if "order_scaleAutoReset" in kwargs: order.m_scaleAutoReset = kwargs["order_scaleAutoReset"] if "order_scaleInitPosition" in kwargs: order.m_scaleInitPosition = kwargs["order_scaleInitPosition"] if "order_scaleInitFillQty" in kwargs: order.m_scaleInitFillQty = kwargs["order_scaleInitFillQty"] if "order_scaleRandomPercent" in kwargs: order.m_scaleRandomPercent = kwargs["order_scaleRandomPercent"] if "order_scaleTable" in kwargs: order.m_scaleTable = kwargs["order_scaleTable"] # HEDGE ORDERS ONLY if "order_hedgeType" in kwargs: order.m_hedgeType = kwargs["order_hedgeType"] # 'D' - delta, 'B' - beta, 'F' - FX, 'P' - pair if "order_hedgeParam" in kwargs: order.m_hedgeParam = kwargs["order_hedgeParam"] # beta value for beta hedge (in range 0-1), ratio for pair hedge # Clearing info if "order_account" in kwargs: order.m_account = kwargs["order_account"] # IB account if "order_settlingFirm" in kwargs: order.m_settlingFirm = kwargs["order_settlingFirm"] if "order_clearingAccount" in kwargs: order.m_clearingAccount = kwargs["order_clearingAccount"] # True beneficiary of the order if "order_clearingIntent" in kwargs: order.m_clearingIntent = kwargs["order_clearingIntent"] # "" (Default), "IB", "Away", "PTA" (PostTrade) # ALGO ORDERS ONLY if "order_algoStrategy" in kwargs: order.m_algoStrategy = kwargs["order_algoStrategy"] if "order_algoParams" in kwargs: order.m_algoParams = kwargs["order_algoParams"] # What-if if "order_whatIf" in kwargs: order.m_whatIf = kwargs["order_whatIf"] # Not Held if "order_notHeld" in kwargs: order.m_notHeld = kwargs["order_notHeld"] # Smart combo routing params if "order_smartComboRoutingParams" in kwargs: order.m_smartComboRoutingParams = kwargs["order_smartComboRoutingParams"] # order combo legs #if "order_orderComboLegs" in kwargs: order.m_orderComboLegs = kwargs["order_orderComboLegs"] = new Vector<OrderComboLeg>() # order misc options if "order_orderMiscOptions" in kwargs: order.m_orderMiscOptions = kwargs["order_orderMiscOptions"] return order def connected(self, **kwargs): return self.client.connected def reqCurrentTime(self, **kwargs): return self.client.reqCurrentTime() def faMsgTypeName(self, **kwargs): return self.client.faMsgTypeName(int) def serverVersion(self, **kwargs): return self.client.serverVersion() def TwsConnectionTime(self, **kwargs): return self.client.TwsConnectionTime() def wrapper(self, **kwargs): return self.client.wrapper() def reader(self, **kwargs): return self.client.reader() def isConnected(self, **kwargs): return self.client.isConnected() def eConnect(self, **kwargs): host = kwargs["host"] port = kwargs["port"] id = kwargs["id"] self.client.eConnect(host, port, id) # def EClientSocket(self, **kwargs): # self.client.EClientSocket(AnyWrapper) # # # def eConnect(self, **kwargs): # self.client.eConnect(String, int, int, boolean) # # def createReader(self, **kwargs): # self.client.createReader(EClientSocket, DataInputStream) # # def eConnect(self, **kwargs): # self.client.eConnect(Socket, int) # # def eConnect(self, **kwargs): # self.client.eConnect(Socket) # def eDisconnect(self, **kwargs): self.client.eDisconnect() ###client functions for call backs #Not using scanners at the moment # def cancelScannerSubscription(self, **kwargs): # subscriptionId = kwargs["id"] # self.client.cancelScannerSubscription(int) # # def reqScannerParameters(self, **kwargs): # self.client.reqScannerParameters() # # def reqScannerSubscription(self, **kwargs): # self.client.reqScannerSubscription(int, ScannerSubscription, Vector<TagValue>) def reqMktData(self, **kwargs): """ function to request market data """ #contract information: requestId = kwargs["tickerId"] contract = self._createContract(**kwargs) tickList = kwargs.get("tickList", "") snapshot = kwargs.get("snapshot", False) self.client.reqMktData(requestId, contract, tickList, snapshot, []) def cancelHistoricalData(self, **kwargs): requestId = kwargs["tickerId"] self.client.cancelHistoricalData(requestId) def cancelRealTimeBars(self, **kwargs): requestId = kwargs["tickerId"] self.client.cancelRealTimeBars(requestId) def reqHistoricalData(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContratct() endDateTime = kwargs["endDateTime"] #format of yyyymmdd HH:mm:ss ttt durationStr = kwargs["durationStr"] #can look like 1000 S (int [S D W]) barSizeSetting = kwargs["barSizeSetting"] #valid values are: 1 sec|5 secs|15 secs|30 secs|1 min|2 mins|3 mins|5 mins|15 mins|30 mins|1 hour|1 day whatToShow = kwargs["whatToShow"] #valid values are: TRADES|MIDPOINT|BID|ASK|BID_ASK|HISTORICAL_VOLATILITY|OPTION_IMPLIED_VOLATILITY useRTH = bool(kwargs["useRTH"]) #0 for all data, 1 for market hours only formatDate = kwargs["formatDate"] #1 for yyyymmdd{space}{space}hh:mm:dd, 2 for timestamp value self.client.reqHistoricalData(requestId, contract, endDateTime, durationStr, barSizeSetting, whatToShow, useRTH, formatDate, []) def reqRealTimeBars(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContratct() barSize = 5 whatToShow = kwargs["whatToShow"] #valid values are: TRADES|MIDPOINT|BID|ASK|BID_ASK|HISTORICAL_VOLATILITY|OPTION_IMPLIED_VOLATILITY useRTH = bool(kwargs["useRTH"]) #0 for all data, 1 for market hours only self.client.reqRealTimeBars(requestId, contract, barSize, whatToShow, useRTH, []) def reqContractDetails(self, **kwargs): requestId = kwargs["reqId"] contract = self._createContract(**kwargs) self.client.reqContractDetails(requestId, contract) def reqMktDepth(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContract(**kwargs) depthRows = kwargs.get("depthRows", 1) self.client.reqMktDepth(requestId, contract, depthRows, []) def cancelMktData(self, **kwargs): """ cancels the market data request """ requestId = kwargs["tickerId"] self.client.cancelMktData(requestId) def cancelMktDepth(self, **kwargs): requestId = kwargs["tickerId"] self.client.cancelMktDepth(requestId) def exerciseOptions(self, **kwargs): requestId = kwargs["tickerId"] contract = self._createContract(**kwargs) exerciseAction = kwargs["exercise_action"] exerciseQty = kwargs["exercise_qty"] account = "" override = 0 #wonder what exchange this should be though if contract.m_exchange == "SMART": raise("Exchange cannot be smart") self.client.exerciseOptions(requestId, contract, exerciseAction, exerciseQty, account, override) def placeOrder(self, **kwargs): requestId = kwargs["id"] contract = self._createContract(**kwargs) order = self._createOrder(**kwargs) self.client.placeOrder(requestId, contract, order) def reqAccountUpdates(self, **kwargs): subscribe = bool(kwargs["subscribe"]) acctCode = kwargs["acctCode"] self.client.reqAccountUpdates(subscribe, acctCode) def reqExecutions(self, **kwargs): requestId = kwargs["reqId"] executionFilter = ExecutionFilter() self.client.reqExecutions(requestId, executionFilter) def cancelOrder(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelOrder(requestId) def reqOpenOrders(self, **kwargs): self.client.reqOpenOrders() def reqIds(self, **kwargs): numIds = kwargs["numIds"] self.client.reqIds(numIds) def reqNewsBulletins(self, **kwargs): news = kwargs["news"] self.client.reqNewsBulletins(news) def cancelNewsBulletins(self, **kwargs): self.client.cancelNewsBulletins() def setServerLogLevel(self, **kwargs): # 1 = SYSTEM # 2 = ERROR # 3 = WARNING # 4 = INFORMATION # 5 = DETAIL logLevel = kwargs["logLevel"] self.client.setServerLogLevel(logLevel) def reqAutoOpenOrders(self, **kwargs): #If set to TRUE, newly created TWS orders will be implicitly associated with the client. If set to FALSE, no association will be made. bAutoBind = kwargs["bAutoBind"] self.client.reqAutoOpenOrders(bAutoBind) def reqAllOpenOrders(self, **kwargs): self.client.reqAllOpenOrders() def reqManagedAccts(self, **kwargs): self.client.reqManagedAccts() def requestFA(self, **kwargs): # 1 = GROUPS # 2 = PROFILE # 3 = ACCOUNT ALIASES faDataType = kwargs["faDataType"] self.client.requestFA(faDataType) def replaceFA(self, **kwargs): #Call this function to modify FA configuration information from the API. Note that this can also be done manually in TWS itself. faDataType = kwargs["faDataType"] cxml = kwargs["cxml"] self.client.replaceFA(faDataType, cxml) def reqFundamentalData(self, **kwargs): # report types # ReportSnapshot (company overview) # ReportsFinSummary (financial summary) # ReportRatios (financial ratios) # ReportsFinStatements (financial statements) # RESC (analyst estimates) # CalendarReport (company calendar) requestId = kwargs["reqId"] contract = self._createContract(**kwargs) reportType =kwargs["reportType"] self.client.reqFundamentalData(requestId, contract, reportType) def cancelFundamentalData(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelFundamentalData(requestId) def calculateImpliedVolatility(self, **kwargs): requestId = kwargs["reqId"] contract = self._createContract(**kwargs) optionPrice = kwargs["optionPrice"] underPrice = kwargs["underPrice"] self.client.calculateImpliedVolatility(requestId, contract, optionPrice, underPrice) def cancelCalculateImpliedVolatility(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelCalculateImpliedVolatility(requestId) def calculateOptionPrice(self, **kwargs): requestId = kwargs["requestId"] contract = self._createContract(**kwargs) volatility = kwargs["volatility"] underPrice = kwargs["underPrice"] self.client.calculateOptionPrice(requestId, contract, volatility, underPrice) def cancelCalculateOptionPrice(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelCalculateOptionPrice(requestId) def reqGlobalCancel(self, **kwargs): self.client.reqGlobalCancel() def reqMarketDataType(self, **kwargs): #1 for real-time streaming market data or 2 for frozen market data. marketDataType = kwargs["marketDataType"] self.client.reqMarketDataType(marketDataType) def reqPositions(self, **kwargs): self.client.reqPositions() def cancelPositions(self, **kwargs): self.client.cancelPositions() def reqAccountSummary(self, **kwargs): #This request can only be made when connected to a Financial Advisor (FA) account. requestId = kwargs["reqId"] group = kwargs["group"] tags = kwargs["tags"] self.client.reqAccountSummary(requestId, group, tags) def cancelAccountSummary(self, **kwargs): requestId = kwargs["reqId"] self.client.cancelAccountSummary(requestId) # def verifyRequest(self, **kwargs): # self.client.verifyRequest(String, String) # # def verifyMessage(self, **kwargs): # self.client.verifyMessage(String) def queryDisplayGroups(self, **kwargs): requestId = kwargs["reqId"] self.client.queryDisplayGroups(requestId) def subscribeToGroupEvents(self, **kwargs): #groupId = The ID of the group, currently it is a number from 1 to 7. This is the display group subscription request sent by the API to TWS. requestId = kwargs["reqId"] groupId = kwargs["groupId"] self.client.subscribeToGroupEvents(requestId, groupId) def updateDisplayGroup(self, **kwargs): # contractInfo: # none = empty selection # contractID@exchange – any non-combination contract. Examples: 8314@SMART for IBM SMART; 8314@ARCA for IBM @ARCA. # combo = if any combo is selected. requestId = kwargs["reqId"] contractInfo = kwargs["contractInfo"] self.client.updateDisplayGroup(requestId, contractInfo) def unsubscribeFromGroupEvents(self, **kwargs): requestId = kwargs["reqId"] self.client.unsubscribeFromGroupEvents(requestId) def getData(self): """ called to get information out of the queue in the wrapper for information passing """ data = self.wrapper.queue.get() #this is specialized code to deal with mapping of ids to symbol information #work to create something more natural that is layer or at a different level? data["tickerId"] = self.tickerMap[data["tickerId"]] return data