def __init__(self, callback): tws = EPosixClientSocket(callback) (host, port, clientid) = return_IB_connection_info() tws.eConnect(host, port, clientid) self.tws = tws self.cb = callback
def __init__(self, client_id: int): """Initialises an instance for the specified client id.""" self._client_id = client_id self._requests_lock = threading.Lock() self._requests = {} self._wrapper = _MulticastWrapper(self._requests, self._requests_lock) self._socket = EPosixClientSocket(self._wrapper)
def __init__(self, callback, port, clientid): tws = EPosixClientSocket(callback) host = '' tws.eConnect(host, port, clientid) self.tws = tws self.cb = callback
def __init__(self): self.accountNumber = '' self.optionExpiry = '20121221' # This needs manual updating! self.maxAskBidRatio = 1.25 self.maxAskLastPriceRatio = 1.02 self.maxOrderQueueLength = 3 # Create a file for TWS logging self.twslog_fh = open('/home/mchan/git/Artemis/twslog.txt', 'a', 0) self.twslog_fh.write("Session Started " + str(datetime.datetime.now()) + "\n") self.callback = ArtemisIBWrapperSilent.ArtemisIBWrapper() self.tws = EPosixClientSocket(self.callback) self.orderIdCount = 1 # This will be updated automatically self.requestIdCount = 1 self.invested = False self.maxLimitPriceFactor = 1.02 # No limit orders above 2% of current ask price # Connect the socket self.socketnum = 30 self.tws.eConnect("", 7496, self.socketnum, poll_interval=1) # Strategy Generic object, has methods for interpreting consensus out/under performance self.Strat = strategy.Strategy() # Queue for orders self.orderQueue = [] # Setup DB connector self.db = dbutil.db(h='127.0.0.1', schema='mchan') # Query Cash Account Balance self.updateBuyingPowerNextId()
def __init__(self, callback): """ Create like this callback = IBWrapper() client = IBclient(callback) """ client_socket = EPosixClientSocket(callback) (host, port, clientid) = return_IB_connection_info() client_socket.eConnect(host, port, clientid) self.client_socket = client_socket self.callback = callback
def __init__(self, port=4001, client_id=12): super(SwigIBClientForInstrument, self).__init__() self.tws = EPosixClientSocket(self) self.port = port self.client_id = client_id self.got_history = Event() self.got_contract = Event() self.got_err = Event() self.order_filled = Event() self.order_ids = Queue()
def __init__(self, callback): """ Create like this callback = IBWrapper() client=IBclient(callback) """ tws = EPosixClientSocket(callback) (host, port, clientid) = return_IB_connection_info() tws.eConnect(host, port, clientid) self.tws = tws
def __init__(self, callback): """ Create like this callback = IBWrapper() client=IBclient(callback) """ tws = EPosixClientSocket(callback) (host, port, clientid) = return_IB_connection_info() tws.eConnect(host, port, clientid) self.tws = tws self.cb = callback
def __init__(self, callback, accountid="DU305658"): """ Create like this callback = IBWrapper() client=IBclient(callback) """ tws = EPosixClientSocket(callback) (host, port, clientid) = return_IB_connection_info() tws.eConnect(host, port, clientid) self.tws = tws self.accountid = accountid self.cb = callback self.logger = logging.getLogger("renaissance")
def __init__(self, callback, clientid=None, accountid="DU202715"): """ Create like this callback = IBWrapper() client=IBclient(callback) """ tws = EPosixClientSocket(callback) (host, port, clientid)=return_IB_connection_info(clientid) tws.eConnect(host, port, clientid) self.tws=tws self.cb=callback self.accountid = accountid self.clientid = clientid
class testTWS(object): def __init__(self): self.callback = ArtemisIBWrapper() self.tws = EPosixClientSocket(self.callback) self.tws.eConnect("", 7496, 44, poll_interval=1) def run(self): # Simple contract for GOOG contract = Contract() #contract.conId = 114376112 contract.exchange = "SMART" contract.symbol = "ATK" contract.secType = "STK" #contract.right = "PUT" contract.currency = "USD" #contract.secType = 'OPT' #contract.strike = 24 #contract.expiry = '20121116' today = datetime.today() order = Order() order.orderId = 89 order.clientId = 44 order.action = "BUY" order.totalQuantity = 1 # may have to calculate a smarter number order.orderType = "MKT" order.tif = "DAY" order.transmit = True order.sweepToFill = True order.outsideRth = True contract.symbol = "alkjdf" self.callback.askPrice = None self.tws.reqMktData(2, contract, "", 1) max_wait = timedelta(seconds=30) + datetime.now() while self.callback.askPrice is None: if datetime.now() > max_wait: print "max wait giving up" break print self.callback.askPrice
import strategy import fowscanner import datetime import multiprocessing import time import sys from swigibpy import EWrapper, EPosixClientSocket, Contract sys.path.append('/home/mchan/git/Artemis/SwigIbPy') from ArtemisIBWrapper import ArtemisIBWrapper callback = ArtemisIBWrapper() tws = EPosixClientSocket(callback) # Connect the socket socketnum = 10 tws.eConnect("", 7496, socketnum, poll_interval=1) for i in range(0,4): socketnum += 1 tws.eDisconnect() print "Socket number: ", socketnum tws.eConnect("", 7496, socketnum, poll_interval=1) time.sleep(3)
def error(self, id, errCode, errString): global clientid global tws global connection_state global pacing global last_time global cooldowntime s = "IB[{}]: {}".format(errCode, errString) if id > -1: s += " (ID: {})".format(id) logging.debug(s) if errCode == ErrorCode.clientid_in_use: logging.info( "Client ID {} in use, reconnecting ...".format(clientid)) clientid += 1 tws = EPosixClientSocket(self) tws.eConnect("", 7496, clientid) elif errCode == ErrorCode.md_connection_ok: logging.info("IB[{}]: {}".format(errCode, errString)) api_started.set() # TODO: use a better string here! elif errCode == ErrorCode.historical_data_error and "Historical data request pacing violation" in errString: logging.info( "Historical data pacing violation: retrying last batch and start using pacing between data requests..." ) logging.info(errString) if not pacing: pacing = 10 dt = prev_last_time.strftime("%Y%m%d %H:%M:%S") logging.info("Cooling down for {} seconds...".format(cooldowntime)) sleep(cooldowntime) cooldowntime += 15 # sometimes we just need to cool down for a longer time tws.reqHistoricalData(0, contract, dt, duration, barsize, datatype, rth_only, 1) elif errCode == ErrorCode.historical_data_error and "invalid step" in errString: logging.info("IB[{}]: {}".format(errCode, errString)) historical_data_received.set() elif errCode == ErrorCode.historical_data_error and "HMDS query returned no data" in errString: logging.info("IB[{}]: {}".format(errCode, errString)) historical_data_received.set() elif (errCode == ErrorCode.historical_data_error and "Trader Workstation exited" in errString) or \ errCode == ErrorCode.cannot_connect_to_tws: logging.info("IB[{}]: {}".format(errCode, errString)) tws.exited = True historical_data_received.set() # requesting historical data from period too long time ago elif errCode == ErrorCode.error_validating_request and "Historical data queries on this contract requesting any data earlier than" in errString: dt = prev_last_time.strftime(dt_format) logging.info( "IB cannot provide data from period ending {}, it's too far back in the history." .format(dt)) historical_data_received.set() elif errCode == ErrorCode.error_validating_request: s = "IB[{}]: {}".format(errCode, errString) if id > -1: s += " (ID: {})".format(id) logging.fatal(s) historical_data_received.set() elif errCode == ErrorCode.connection_lost: # TODO: some logic to retry after connection has been momentarily lost, and eventually give up... logging.info("Connection lost, saving data end aborting...") if not output_file: sys.exit(ExitCode.error_can_continue) historical_data_received.set() elif errCode == ErrorCode.no_security_def_found: logging.info("IB[{}]: {}".format(errCode, errString)) if not output_file: sys.exit(ExitCode.error_can_continue) historical_data_received.set() else: s = "IB[{}]: {}".format(errCode, errString) if id > -1: s += " (ID: {})".format(id) logging.info(s)
def connect(self, port=7496): if self.is_connected(): self.disconnect() cid = self.get_next_cid() self.tws = EPosixClientSocket(self.wrapper) self.tws.eConnect('', port, cid)
class TwsClient(object): logger = logging.getLogger(__name__) """Represents Interactive Broker's TWS.""" _next_request_id = 0 def __init__(self, client_id: int): """Initialises an instance for the specified client id.""" self._client_id = client_id self._requests_lock = threading.Lock() self._requests = {} self._wrapper = _MulticastWrapper(self._requests, self._requests_lock) self._socket = EPosixClientSocket(self._wrapper) @property def client_id(self): return self._client_id def connect(self, host: str = "", port: int = 7496) -> Disconnecting: """Connects to TWS.""" if not self._socket.eConnect(host, port, self.client_id): raise RuntimeError("Client[%d] Failed to connect at Host: %s, Port: %d" % \ (self._client_id, host, port)) TwsClient.logger.info("Client[%d] connected at Host: %s, Port: %d" % (self._client_id, host, port)) return Disconnecting(self._socket) def reqHistoricalData(self, handler, contract: Contract, end_datetime: str, duration: str = "1 D", bar_size: BarSize = BarSize.Min1, what_to_show: WhatToShow = WhatToShow.Trades, use_rth: UseRth = UseRth.WithinTradingHour, format_date: FormatDate = FormatDate.InString): """""" request = self._createRequest(RequestType.HistoricalData, handler) self._socket.reqHistoricalData(request.request_id, contract, end_datetime, duration, bar_size.value, what_to_show.value, use_rth.value, format_date.value) return request def reqMarketData(self, handler, contract: Contract, generic_tick: str, snapshot: bool = False): """""" request = self._createRequest(RequestType.MarketData, handler) self._socket.reqMktData(request.request_id, contract, generic_tick, snapshot) return request def reqOpenOrders(self): return self._socket.reqOpenOrders() def cancelRequest(self, request: Request): """""" req_id = request.request_id with self._requests_lock: if self._requests.get(req_id) != request: return False del self._requests[req_id] try: { RequestType.HistoricalData: lambda: self._socket.cancelHistoricalData(req_id), RequestType.MarketData: lambda: self.cancelMktData(req_id) }[request.request_type]() except KeyError: raise LookupError( "Client[%d] Reqest: %d - Unable to cancel unknown request type [%s]." % (self._client_id, req_id, request.request_type.value)) def cancelMktData(self, req_id): TwsClient.logger.info('MarketData request[%d] is cancelled.' % req_id) self._socket.cancelMktData(req_id) def _createRequest(self, req_type: RequestType, handler) -> Request: TwsClient._next_request_id += 1 req_id = TwsClient._next_request_id request = Request(self, req_type, req_id, handler) with self._requests_lock: self._requests[req_id] = request return request
class SwigIBClientForInstrument(EWrapper): '''Callback object passed to TWS, these functions will be called directly by TWS. ''' def __init__(self, port=4001, client_id=12): super(SwigIBClientForInstrument, self).__init__() self.tws = EPosixClientSocket(self) self.port = port self.client_id = client_id self.got_history = Event() self.got_contract = Event() self.got_err = Event() self.order_filled = Event() self.order_ids = Queue() def execDetails(self, id, contract, execution): pass def managedAccounts(self, openOrderEnd): pass ### Order def nextValidId(self, validOrderId): '''Capture the next order id''' self.order_ids.put(validOrderId) def request_contract_details(self, contract): today = datetime.today() print("Requesting contract details...") # Perform the request self.tws.reqContractDetails( 43, # reqId, contract, # contract, ) print("\n====================================================================") print(" Contract details requested, waiting %ds for TWS responses" % WAIT_TIME) print("====================================================================\n") try: self.got_contract.wait(timeout=WAIT_TIME) except KeyboardInterrupt: pass finally: if not self.got_contract.is_set(): print('Failed to get contract within %d seconds' % WAIT_TIME) def contractDetails(self, reqId, contractDetails): print("Contract details received (request id %i):" % reqId) print("callable: %s" % contractDetails.callable) print("category: %s" % contractDetails.category) print("contractMonth: %s" % contractDetails.contractMonth) print("convertible: %s" % contractDetails.convertible) print("coupon: %s" % contractDetails.coupon) print("industry: %s" % contractDetails.industry) print("liquidHours: %s" % contractDetails.liquidHours) print("longName: %s" % contractDetails.longName) print("marketName: %s" % contractDetails.marketName) print("minTick: %s" % contractDetails.minTick) print("nextOptionPartial: %s" % contractDetails.nextOptionPartial) print("orderTypes: %s" % contractDetails.orderTypes) print("priceMagnifier: %s" % contractDetails.priceMagnifier) print("putable: %s" % contractDetails.putable) if contractDetails.secIdList is not None: for secId in contractDetails.secIdList: print("secIdList: %s" % secId) else: print("secIdList: None") print("subcategory: %s" % contractDetails.subcategory) print("tradingHours: %s" % contractDetails.tradingHours) print("timeZoneId: %s" % contractDetails.timeZoneId) print("underConId: %s" % contractDetails.underConId) print("evRule: %s" % contractDetails.evRule) print("evMultiplier: %s" % contractDetails.evMultiplier) contract = contractDetails.summary print("\nContract Summary:") print("exchange: %s" % contract.exchange) print("symbol: %s" % contract.symbol) print("secType: %s" % contract.secType) print("currency: %s" % contract.currency) print("tradingClass: %s" % contract.tradingClass) if contract.comboLegs is not None: for comboLeg in contract.comboLegs: print("comboLegs: %s - %s" % (comboLeg.action, comboLeg.exchange)) else: print("comboLegs: None") # inst_id = seq_mgr.get_next_sequence("instruments") print("\nBond Values:") print("bondType: %s" % contractDetails.bondType) print("couponType: %s" % contractDetails.couponType) print("cusip: %s" % contractDetails.cusip) print("descAppend: %s" % contractDetails.descAppend) print("issueDate: %s" % contractDetails.issueDate) print("maturity: %s" % contractDetails.maturity) print("nextOptionDate: %s" % contractDetails.nextOptionDate) print("nextOptionType: %s" % contractDetails.nextOptionType) print("notes: %s" % contractDetails.notes) print("ratings: %s" % contractDetails.ratings) print("validExchanges: %s" % contractDetails.validExchanges) self.got_contract.set()
print("descAppend: %s" % contractDetails.descAppend) print("issueDate: %s" % contractDetails.issueDate) print("maturity: %s" % contractDetails.maturity) print("nextOptionDate: %s" % contractDetails.nextOptionDate) print("nextOptionType: %s" % contractDetails.nextOptionType) print("notes: %s" % contractDetails.notes) print("ratings: %s" % contractDetails.ratings) print("validExchanges: %s" % contractDetails.validExchanges) # Instantiate our callback object callback = ContractDetailsExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost tws.eConnect("", 7496, 42) # Simple contract for GOOG contract = Contract() contract.exchange = "SMART" contract.symbol = "GOOG" contract.secType = "STK" contract.currency = "USD" today = datetime.today() print("Requesting contract details...") # Perform the request
def openOrder(self, orderID, contract, order, orderState): print("Order opened for %s" % contract.symbol) prompt = input("WARNING: This example will place an order on your IB " "account, are you sure? (Type yes to continue): ") if prompt.lower() != 'yes': sys.exit() # Instantiate our callback object callback = PlaceOrderExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost tws.eConnect("", 7496, 42) # Simple contract for GOOG contract = Contract() contract.symbol = "IBM" contract.secType = "STK" contract.exchange = "SMART" contract.currency = "USD" if orderId is None: print('Waiting for valid order id') sleep(1) while orderId is None:
def error(self, id, errCode, errString): global clientid global tws global connection_state global pacing global last_time global cooldowntime s = "IB[{}]: {}".format(errCode, errString) if id > -1: s += " (ID: {})".format(id) logging.debug(s) if errCode == ErrorCode.clientid_in_use: logging.info("Client ID {} in use, reconnecting ...".format(clientid)) clientid += 1 tws = EPosixClientSocket(self) tws.eConnect("", 7496, clientid) elif errCode == ErrorCode.md_connection_ok: logging.info("IB[{}]: {}".format(errCode, errString)) api_started.set() # TODO: use a better string here! elif errCode == ErrorCode.historical_data_error and "Historical data request pacing violation" in errString: logging.info("Historical data pacing violation: retrying last batch and start using pacing between data requests...") logging.info(errString) if not pacing: pacing = 10 dt = prev_last_time.strftime("%Y%m%d %H:%M:%S") logging.info("Cooling down for {} seconds...".format(cooldowntime)) sleep(cooldowntime) cooldowntime += 15 # sometimes we just need to cool down for a longer time tws.reqHistoricalData(0, contract, dt, duration, barsize, datatype, rth_only, 1) elif errCode == ErrorCode.historical_data_error and "invalid step" in errString: logging.info("IB[{}]: {}".format(errCode, errString)) historical_data_received.set() elif errCode == ErrorCode.historical_data_error and "HMDS query returned no data" in errString: logging.info("IB[{}]: {}".format(errCode, errString)) historical_data_received.set() elif (errCode == ErrorCode.historical_data_error and "Trader Workstation exited" in errString) or \ errCode == ErrorCode.cannot_connect_to_tws: logging.info("IB[{}]: {}".format(errCode, errString)) tws.exited = True historical_data_received.set() # requesting historical data from period too long time ago elif errCode == ErrorCode.error_validating_request and "Historical data queries on this contract requesting any data earlier than" in errString: dt = prev_last_time.strftime(dt_format) logging.info("IB cannot provide data from period ending {}, it's too far back in the history.".format(dt)) historical_data_received.set() elif errCode == ErrorCode.error_validating_request: s = "IB[{}]: {}".format(errCode, errString) if id > -1: s += " (ID: {})".format(id) logging.fatal(s) historical_data_received.set() elif errCode == ErrorCode.connection_lost: # TODO: some logic to retry after connection has been momentarily lost, and eventually give up... logging.info("Connection lost, saving data end aborting...") if not output_file: sys.exit(ExitCode.error_can_continue) historical_data_received.set() elif errCode == ErrorCode.no_security_def_found: logging.info("IB[{}]: {}".format(errCode, errString)) if not output_file: sys.exit(ExitCode.error_can_continue) historical_data_received.set() else: s = "IB[{}]: {}".format(errCode, errString) if id > -1: s += " (ID: {})".format(id) logging.info(s)
if date[:8] == 'finished': print("History request complete") self.got_history.set() else: date = datetime.strptime(date, "%Y%m%d").strftime("%d %b %Y") print(("reqId: %d, History %s - Open: %s, High: %s, Low: %s, Close: " "%s, Volume: %d") % (reqId, date, open, high, low, close, volume)) ''' # Instantiate our callback object callback = HistoricalDataExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback, reconnect_auto=True) # Connect to tws running on localhost if not tws.eConnect("", 7496, 42): raise RuntimeError('Failed to connect to TWS') today = datetime.today() for index, row in contractlist.iterrows(): print 'Index:', index, ', Sym:', row['sym'] #self.reqMktData(index, create_contract(row['sym']), '233', False) # Request some historical data. tws.reqHistoricalData( index, # tickerId, create_contract(row['sym']), # contract, today.strftime("%Y%m%d %H:%M:%S %Z"), # endDateTime,
'8 hour': '1 M', '1 day': '1 Y', '1W': '1 Y', '1M': '1 Y' } if args.d: duration = args.d else: duration = max_duration[barsize] # need to get extra info from tws in order to proceed callbacks = MyCallbacks() tws = EPosixClientSocket(callbacks) tws.exited = False # used to show whether TWS has suddenly exited # generate clientid based on time of day so that we won't likely get duplicate clientids timenow = datetime.utcnow().time() clientid = timenow.hour * 60 * 60 + timenow.minute * 60 + timenow.second tws.eConnect("", 7496, clientid) api_started.wait(10) if tws.exited: sys.exit(2) logging.info("API functional, getting started...")
def enterPositions(self, weights, execution_sleep=True): print "----------------------MAKING TRADES ON IB---------------------------" # Instantiate our callback object callback = self.PlaceOrderExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost tws.eConnect("", 7496, 42) # account updates tws.reqAccountUpdates(True, self.accountNumber) sleep(1) print "available funds: %s" % (self.availableFunds) print "net liquidation value: %s" % (self.netLiquidationValue) ###DELAY UNTIL MARKET HOURS if execution_sleep: day_of_week = datetime.now().isoweekday() # if weekday, and we scanned after midnight, set execution time to this morning at 10:30 am time_now = datetime.now() if ( day_of_week in range(1, 6) and (time_now.hour >= 0 and time_now.hour < 10) and (time_now.minute >= 0 and time_now.minute < 30) ): execution_time = datetime( year=time_now.year, month=time_now.month, day=time_now.day, hour=10, minute=30 ) # otherwise, set to next trading day, morning at 10:30am else: execution_time = datetime.now() execution_time = execution_time + dt.timedelta(days=1) while execution_time.isoweekday() > 5: execution_time = execution_time + dt.timedelta(days=1) execution_time = datetime( year=execution_time.year, month=execution_time.month, day=execution_time.day, hour=10, minute=30 ) to_sleep = (execution_time - datetime.now()).total_seconds() print "----------sleeping until execution time of %s---------------" % (execution_time) # sleep until that time sleep(to_sleep) for stock in weights: print ("\n=====================================================================") print (" Trading " + stock) print ("=====================================================================\n") stock_price = Trader.get_quote([stock])[0][self.QUOTE_LAST] print "%s last stock price: %s" % (stock, stock_price) contract = Contract() contract.symbol = stock contract.secType = "STK" contract.exchange = "SMART" contract.currency = "USD" if self.orderId is None: print ("Waiting for valid order id") sleep(1) while self.orderId is None: print ("Still waiting for valid order id...") sleep(1) # Order details order = Order() order.action = "BUY" # order.lmtPrice = 140 order.orderType = "MKT" dollar_value = self.availableFunds * weights[stock] order.totalQuantity = int(round(dollar_value / stock_price, 0)) # order.algoStrategy = "AD" order.tif = "DAY" # order.algoParams = algoParams order.transmit = True print ( "Placing order for %d %s's, dollar value $%s (id: %d)" % (order.totalQuantity, contract.symbol, dollar_value, self.orderId) ) # Place the order tws.placeOrder(self.orderId, contract, order) # orderId, # contract, # order print ("\n=====================================================================") print (" Order placed, waiting for TWS responses") print ("=====================================================================\n") sleep(3) # reset orderid for next self.orderId = self.orderId + 1 print ("\n=====================================================================") print (" Trade done.") print ("=====================================================================\n") print ("******************* Press ENTER to quit when done *******************\n") input() print ("\nDisconnecting...") tws.eDisconnect()
import time from swigibpy import EWrapper, EPosixClientSocket, Contract, Order import sys sys.path.append('/home/mchan/git/Artemis/SwigIbPy/') from DataDownloadIBWrapper import ArtemisIBWrapper #from ArtemisIBWrapper import ArtemisIBWrapper ### # Instantiate our callback object callback = ArtemisIBWrapper() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost tws.eConnect("", 7496, 46, poll_interval=1) accountNumber = '' contract = Contract() contract.exchange = "SMART" contract.symbol = "TOT" contract.secType = "STK" #contract.right = "PUT" contract.currency = "USD" #contract.secType = 'OPT' #contract.strike = 24 #contract.expiry = '20121116' today = datetime.today()
class IBBroker(Broker): cid = 0 # connection id oid = 0 # order id tid = 0 # tick id (for fetching quotes) tws = None # Trader WorkStation wrapper = None # instance of EWrapper sid_to_tid = {} # map of security id to tick id def __init__(self, wrapper=None): Broker.__init__(self) # initialize a default wrapper if wrapper: self.wrapper = wrapper else: self.wrapper = WrapperDefault() # initialize the wrapper's portfolio object self.wrapper.portfolio = IBPortfolio() # get next order id def get_next_oid(self): IBBroker.oid += 1 return IBBroker.oid # get next connection id def get_next_cid(self): IBBroker.cid += 1 return IBBroker.cid # get next tick request id (for getting quotes) def get_next_tid(self): self.tid += 1 return self.tid # connect to TWS def connect(self, port=7496): if self.is_connected(): self.disconnect() cid = self.get_next_cid() self.tws = EPosixClientSocket(self.wrapper) self.tws.eConnect('', port, cid) # disconnect from TWS def disconnect(self): self.tws.eDisconnect() # check if TWS is connected def is_connected(self): if self.tws is None: return False return self.tws.isConnected() # Convert Zipline order signs into IB action strings def order_action(self, iSign): if iSign > 0: return 'BUY' elif iSign < 0: return 'SELL' raise Exception('Order of zero shares has no IB side: %i' % iSign) # get an IB contract by ticker def get_contract_by_sid(self, sid): contract = Contract() contract.symbol = sid contract.secType = 'STK' contract.exchange = 'SMART' contract.currency = 'USD' return contract # get a default IB market order def get_market_order(self, sid, amt): order = Order() order.action = self.order_action(amt) order.totalQuantity = abs(amt) order.orderType = 'MKT' order.tif = 'DAY' order.outsideRth = False return order # get a default IB limit order def get_limit_order(self, sid, amt, lmtPrice): order = Order() order.action = self.order_action(amt) order.totalQuantity = abs(amt) order.orderType = 'LMT' order.tif = 'DAY' order.outsideRth = False order.lmtPrice = lmtPrice return order # send the IB (contract, order) order to TWS def place_order(self, contract, order): oid = self.get_next_oid() self.tws.placeOrder(oid, contract, order) return oid # send order with Zipline style order arguments # <TODO> stop_price is not implemented def order(self, sid, amt, limit_price=None, stop_price=None): contract = self.get_contract_by_sid(sid) amt = int(amt) if limit_price is None: order = self.get_market_order(sid, amt) else: order = self.get_limit_order(sid, amt, limit_price) return self.place_order(contract, order) # subscribe to market data ticks def subscribe(self, sid): tid = self.get_next_tid() self.sid_to_tid[sid] = tid contract = self.get_contract_by_sid(sid) self.tws.reqMktData(tid, contract, '', False) return tid # subscribe to market data ticks for a list of tickers def subscribe_list(self, tickers): for tkr in tickers: self.subscribe(tkr) # cancel a market data subscription def unsubscribe(self, sid): if sid not in self.sid_to_tid.keys(): return tid = self.sid_to_tid[sid] self.tws.cancelMktData(tid) # cancel all market data subscriptions def unsubscribe_all(self): sids = self.sid_to_tid.keys() for sid in sids: self.unsubscribe(sid) # fetch a quote by ticker id tid def get_quote_by_tid(self, tid): return self.wrapper.tid_to_price[tid] # fetch a quote by ticker sid def get_quote(self, sid): if sid not in self.sid_to_tid: self.subscribe(sid) return (None, None) tid = self.sid_to_tid[sid] if tid not in self.wrapper.tid_to_price: price = None else: price = self.wrapper.tid_to_price[tid] if tid not in self.wrapper.tid_to_size: size = None else: size = self.wrapper.tid_to_size[tid] return (price, size) # fetch a price by ticker sid def get_price(self, sid): if sid not in self.sid_to_tid: self.subscribe(sid) return None tid = self.sid_to_tid[sid] if tid not in self.wrapper.tid_to_price: return None else: price_dict = self.wrapper.tid_to_price[tid] if 'price' in price_dict: return price_dict['price'] return None # get a Pandas DataFrame of current positions def get_positions_frame(self): ib_dict = {} for sid, position in self.wrapper.portfolio.sid_to_position.iteritems( ): # <TODO> don't use vars here #ib_dict[sid] = vars(position) ib_dict[sid] = { 'marketValue': position.marketValue, 'realizedPNL': position.realizedPNL, 'marketPrice': position.marketPrice, 'unrealizedPNL': position.unrealizedPNL, 'accountName': position.accountName, 'averageCost': position.averageCost, 'sid': position.sid, 'position': position.position } return pd.DataFrame.from_dict(ib_dict, orient='index')
if date[:8] == 'finished': print("History request complete") self.got_history.set() else: date = datetime.strptime(date, "%Y%m%d").strftime("%d %b %Y") print(("History %s - Open: %s, High: %s, Low: %s, Close: " "%s, Volume: %d") % (date, open, high, low, close, volume)) # Instantiate our callback object callback = HistoricalDataExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback, reconnect_auto=True) # Connect to tws running on localhost if not tws.eConnect("", 7496, 42): raise RuntimeError('Failed to connect to TWS') # Simple contract for GOOG contract = Contract() contract.exchange = "SMART" contract.symbol = "GOOG" contract.secType = "STK" contract.currency = "USD" today = datetime.today() print("Requesting historical data for %s" % contract.symbol)
barCount, WAP, hasGaps): if date[:8] == 'finished': print "History request complete" else: date = datetime.strptime(date, "%Y%m%d").strftime("%d %b %Y") print("History %s - Open: %s, High: %s, Low: %s, Close: " + "%s, Volume: %d") % (date, open, high, low, close, volume) # Instantiate our callback object callback = HistoricalDataExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost tws.eConnect("", 7496, 42) # Simple contract for DELL dell = Contract() dell.exchange = "SMART" dell.symbol = "DELL" dell.secType = "STK" dell.currency = "USD" today = datetime.today() print "Requesting historical data for %s" % dell.symbol # Request some historical data.
def __init__(self): self.callback = ArtemisIBWrapper() self.tws = EPosixClientSocket(self.callback) self.tws.eConnect("", 7496, 44, poll_interval=1)
class SwigIBClient(EWrapper): '''Callback object passed to TWS, these functions will be called directly by TWS. ''' def __init__(self, port=4001, client_id=12): super(SwigIBClient, self).__init__() self.tws = EPosixClientSocket(self) self.port = port self.client_id = client_id self.got_history = Event() self.got_contract = Event() self.got_err = Event() self.order_filled = Event() self.order_ids = Queue() def execDetails(self, id, contract, execution): pass def managedAccounts(self, openOrderEnd): pass ### Order def nextValidId(self, validOrderId): '''Capture the next order id''' self.order_ids.put(validOrderId) def orderStatus(self, id, status, filled, remaining, avgFillPrice, permId, parentId, lastFilledPrice, clientId, whyHeld): print(("Order #%s - %s (filled %d, remaining %d, avgFillPrice %f," "last fill price %f)") % (id, status, filled, remaining, avgFillPrice, lastFilledPrice)) if remaining <= 0: self.order_filled.set() def openOrder(self, orderID, contract, order, orderState): print("Order opened for %s" % contract.symbol) def openOrderEnd(self): pass def commissionReport(self, commissionReport): print 'Commission %s %s P&L: %s' % (commissionReport.currency, commissionReport.commission, commissionReport.realizedPNL) ### Historical data def historicalData(self, reqId, date, open, high, low, close, volume, barCount, WAP, hasGaps): if date[:8] == 'finished': print("History request complete") self.got_history.set() else: date = datetime.strptime(date, "%Y%m%d").strftime("%d %b %Y") print(("History %s - Open: %s, High: %s, Low: %s, Close: " "%s, Volume: %d") % (date, open, high, low, close, volume)) ### Contract details def contractDetailsEnd(self, reqId): print("Contract details request complete, (request id %i)" % reqId) def contractDetails(self, reqId, contractDetails): print("Contract details received (request id %i):" % reqId) print("callable: %s" % contractDetails.callable) print("category: %s" % contractDetails.category) print("contractMonth: %s" % contractDetails.contractMonth) print("convertible: %s" % contractDetails.convertible) print("coupon: %s" % contractDetails.coupon) print("industry: %s" % contractDetails.industry) print("liquidHours: %s" % contractDetails.liquidHours) print("longName: %s" % contractDetails.longName) print("marketName: %s" % contractDetails.marketName) print("minTick: %s" % contractDetails.minTick) print("nextOptionPartial: %s" % contractDetails.nextOptionPartial) print("orderTypes: %s" % contractDetails.orderTypes) print("priceMagnifier: %s" % contractDetails.priceMagnifier) print("putable: %s" % contractDetails.putable) if contractDetails.secIdList is not None: for secId in contractDetails.secIdList: print("secIdList: %s" % secId) else: print("secIdList: None") print("subcategory: %s" % contractDetails.subcategory) print("tradingHours: %s" % contractDetails.tradingHours) print("timeZoneId: %s" % contractDetails.timeZoneId) print("underConId: %s" % contractDetails.underConId) print("evRule: %s" % contractDetails.evRule) print("evMultiplier: %s" % contractDetails.evMultiplier) contract = contractDetails.summary print("\nContract Summary:") print("exchange: %s" % contract.exchange) print("symbol: %s" % contract.symbol) print("secType: %s" % contract.secType) print("currency: %s" % contract.currency) print("tradingClass: %s" % contract.tradingClass) if contract.comboLegs is not None: for comboLeg in contract.comboLegs: print("comboLegs: %s - %s" % (comboLeg.action, comboLeg.exchange)) else: print("comboLegs: None") print("\nBond Values:") print("bondType: %s" % contractDetails.bondType) print("couponType: %s" % contractDetails.couponType) print("cusip: %s" % contractDetails.cusip) print("descAppend: %s" % contractDetails.descAppend) print("issueDate: %s" % contractDetails.issueDate) print("maturity: %s" % contractDetails.maturity) print("nextOptionDate: %s" % contractDetails.nextOptionDate) print("nextOptionType: %s" % contractDetails.nextOptionType) print("notes: %s" % contractDetails.notes) print("ratings: %s" % contractDetails.ratings) print("validExchanges: %s" % contractDetails.validExchanges) self.got_contract.set() ### Error def error(self, id, errCode, errString): if errCode == 165 or (errCode >= 2100 and errCode <= 2110): print("TWS warns %s" % errString) elif errCode == 502: print('Looks like TWS is not running, ' 'start it up and try again') sys.exit() elif errCode == 501: print("TWS reports error in client: %s" % errString) elif errCode >= 1100 and errCode < 2100: print("TWS reports system error: %s" % errString) elif errCode == 321: print("TWS complaining about bad request: %s" % errString) else: super(SwigIBClient, self).error(id, errCode, errString) self.got_err.set() def winError(self, msg, lastError): print("TWS reports API error: %s" % msg) self.got_err.set() def pyError(self, type, val, tb): sys.print_exception(type, val, tb) ### def connect(self): if not self.tws.eConnect("", self.port, self.client_id): raise RuntimeError('Failed to connect to TWS') def disconnect(self): print("\nDisconnecting...") self.tws.eDisconnect() def create_contract(self): # Simple contract for GOOG contract = Contract() contract.exchange = "SMART" contract.symbol = "GOOG" contract.secType = "STK" contract.currency = "USD" return contract def request_contract_details(self, contract): today = datetime.today() print("Requesting contract details...") # Perform the request self.tws.reqContractDetails( 42, # reqId, contract, # contract, ) print("\n====================================================================") print(" Contract details requested, waiting %ds for TWS responses" % WAIT_TIME) print("====================================================================\n") try: self.got_contract.wait(timeout=WAIT_TIME) except KeyboardInterrupt: pass finally: if not self.got_contract.is_set(): print('Failed to get contract within %d seconds' % WAIT_TIME) def request_hist_data(self, contract): today = datetime.today() print("Requesting historical data for %s" % contract.symbol) # Request some historical data. self.tws.reqHistoricalData( 2, # tickerId, contract, # contract, today.strftime("%Y%m%d %H:%M:%S %Z"), # endDateTime, "1 W", # durationStr, "1 day", # barSizeSetting, "TRADES", # whatToShow, 0, # useRTH, 1 # formatDate ) print("\n====================================================================") print(" History requested, waiting %ds for TWS responses" % WAIT_TIME) print(" History requested, waiting %ds for TWS responses" % WAIT_TIME) print("====================================================================\n") try: self.got_history.wait(timeout=WAIT_TIME) except KeyboardInterrupt: pass finally: if not self.got_history.is_set(): print('Failed to get history within %d seconds' % WAIT_TIME) def subscribe_market_data(self, contract): pass def unsubscribe_market_data(self, contract): pass def place_order(self, contract): print('Waiting for valid order id') order_id = self.order_ids.get(timeout=WAIT_TIME) if not order_id: raise RuntimeError('Failed to receive order id after %ds' % WAIT_TIME) # Order details algoParams = TagValueList() algoParams.append(TagValue("componentSize", "3")) algoParams.append(TagValue("timeBetweenOrders", "60")) algoParams.append(TagValue("randomizeTime20", "1")) algoParams.append(TagValue("randomizeSize55", "1")) algoParams.append(TagValue("giveUp", "1")) algoParams.append(TagValue("catchUp", "1")) algoParams.append(TagValue("waitForFill", "1")) algoParams.append(TagValue("startTime", "20110302-14:30:00 GMT")) algoParams.append(TagValue("endTime", "20110302-21:00:00 GMT")) order = Order() order.action = 'BUY' order.lmtPrice = 140 order.orderType = 'LMT' order.totalQuantity = 10 order.algoStrategy = "AD" order.tif = 'DAT' order.algoParams = algoParams # order.transmit = False print("Placing order for %d %s's (id: %d)" % (order.totalQuantity, contract.symbol, order_id)) # Place the order self.tws.placeOrder( order_id, # orderId, contract, # contract, order # order ) print("\n====================================================================") print(" Order placed, waiting %ds for TWS responses" % WAIT_TIME) print("====================================================================\n") print("Waiting for order to be filled..") try: self.order_filled.wait(WAIT_TIME) except KeyboardInterrupt: pass finally: if not self.order_filled.is_set(): print('Failed to fill order')
def openOrder(self, orderID, contract, order, orderState): print "Order opened for %s" % contract.symbol prompt = raw_input("WARNING: This example will place an order on your IB " "account, are you sure? (Type yes to continue): ") if prompt.lower() != 'yes': sys.exit() # Instantiate our callback object callback = PlaceOrderExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost tws.eConnect("", 7496, 42) # Simple contract for GOOG contract = Contract() contract.exchange = "SMART" contract.symbol = "DELL" contract.secType = "STK" contract.currency = "USD" if orderId is None: print 'Waiting for valid order id' sleep(1) while orderId is None:
class TradeManager(object): def __init__(self): self.accountNumber = '' self.optionExpiry = '20121221' # This needs manual updating! self.maxAskBidRatio = 1.25 self.maxAskLastPriceRatio = 1.02 self.maxOrderQueueLength = 3 # Create a file for TWS logging self.twslog_fh = open('/home/mchan/git/Artemis/twslog.txt', 'a', 0) self.twslog_fh.write("Session Started " + str(datetime.datetime.now()) + "\n") self.callback = ArtemisIBWrapperSilent.ArtemisIBWrapper() self.tws = EPosixClientSocket(self.callback) self.orderIdCount = 1 # This will be updated automatically self.requestIdCount = 1 self.invested = False self.maxLimitPriceFactor = 1.02 # No limit orders above 2% of current ask price # Connect the socket self.socketnum = 30 self.tws.eConnect("", 7496, self.socketnum, poll_interval=1) # Strategy Generic object, has methods for interpreting consensus out/under performance self.Strat = strategy.Strategy() # Queue for orders self.orderQueue = [] # Setup DB connector self.db = dbutil.db(h='127.0.0.1', schema='mchan') # Query Cash Account Balance self.updateBuyingPowerNextId() def updateBuyingPowerNextId(self): self.callback.myNextValidId = None self.callback.buyingPower = None self.tws.reqAccountUpdates(1, self.accountNumber) while (self.callback.buyingPower is None or self.callback.myNextValidId is None): pass self.buyingPower = float(self.callback.buyingPower) self.orderIdCount = int(self.callback.myNextValidId) print "Buying Power recognized: ", self.buyingPower, " Next valid id recognized: ", self.orderIdCount self.tws.reqAccountUpdates(0, self.accountNumber) def calcInvSize(self): ''' Calculates proper investment size ''' # We take the total size of the portfolio, cash plus stock, and we divide by four # The reasoning is that we want to avoid the day pattern trader restriction # Dividing our portfolio size by four ensures that we have enough capital # to trade for the four trading opportunities that will happen until we can # finally sell our positions # This also allows for diversification self.updateBuyingPowerNextId() portfolioList = self.getPortfolio() secMarketPositions = 0 for myContract, myPosition, myMarketValue in portfolioList: secMarketPositions += myMarketValue totalPortfolioSize = secMarketPositions + self.buyingPower investmentSize = min(self.buyingPower, (totalPortfolioSize/4.0)) print "CALCULATE INVESTMENT SIZE: ", str(investmentSize) return investmentSize def twsReconnect(self): print "Reconnecting TWS" self.twslog_fh.write("Reconnecting TWS" + str(datetime.datetime.now()) + '\n') self.tws.eDisconnect() try: self.tws.eConnect("", 7496, self.socketnum, poll_interval=1) except TWSError, e: print e print "Attempting to reconnect:" for i in range(0,5): time.sleep(5) print "Try ", i try: self.tws.eConnect("", 7496, self.socketnum, poll_interval=1) break except TWSError, e: print e
class TradeManager(object): def __init__(self): self.accountNumber = '' self.optionExpiry = '20121221' # This needs manual updating! self.maxAskBidRatio = 1.25 self.maxAskLastPriceRatio = 1.02 self.maxOrderQueueLength = 3 # Create a file for TWS logging self.twslog_fh = open('/home/mchan/git/Artemis/twslog.txt', 'a', 0) self.twslog_fh.write("Session Started " + str(datetime.datetime.now()) + "\n") self.callback = ArtemisIBWrapperSilent.ArtemisIBWrapper() self.tws = EPosixClientSocket(self.callback) self.orderIdCount = 1 # This will be updated automatically self.requestIdCount = 1 self.invested = False self.maxLimitPriceFactor = 1.02 # No limit orders above 2% of current ask price # Connect the socket self.socketnum = 30 self.tws.eConnect("", 7496, self.socketnum, poll_interval=1) # Strategy Generic object, has methods for interpreting consensus out/under performance self.Strat = strategy.Strategy() # Queue for orders self.orderQueue = [] # Setup DB connector self.db = dbutil.db(h='127.0.0.1', schema='mchan') # Query Cash Account Balance self.updateBuyingPowerNextId() def updateBuyingPowerNextId(self): self.callback.myNextValidId = None self.callback.buyingPower = None self.tws.reqAccountUpdates(1, self.accountNumber) while (self.callback.buyingPower is None or self.callback.myNextValidId is None): pass self.buyingPower = float(self.callback.buyingPower) self.orderIdCount = int(self.callback.myNextValidId) print "Buying Power recognized: ", self.buyingPower, " Next valid id recognized: ", self.orderIdCount self.tws.reqAccountUpdates(0, self.accountNumber) def calcInvSize(self): ''' Calculates proper investment size ''' # We take the total size of the portfolio, cash plus stock, and we divide by four # The reasoning is that we want to avoid the day pattern trader restriction # Dividing our portfolio size by four ensures that we have enough capital # to trade for the four trading opportunities that will happen until we can # finally sell our positions # This also allows for diversification self.updateBuyingPowerNextId() portfolioList = self.getPortfolio() secMarketPositions = 0 for myContract, myPosition, myMarketValue in portfolioList: secMarketPositions += myMarketValue totalPortfolioSize = secMarketPositions + self.buyingPower investmentSize = min(self.buyingPower, (totalPortfolioSize / 4.0)) print "CALCULATE INVESTMENT SIZE: ", str(investmentSize) return investmentSize def twsReconnect(self): print "Reconnecting TWS" self.twslog_fh.write("Reconnecting TWS" + str(datetime.datetime.now()) + '\n') self.tws.eDisconnect() try: self.tws.eConnect("", 7496, self.socketnum, poll_interval=1) except TWSError, e: print e print "Attempting to reconnect:" for i in range(0, 5): time.sleep(5) print "Try ", i try: self.tws.eConnect("", 7496, self.socketnum, poll_interval=1) break except TWSError, e: print e
class SwigIBClientForInstrument(EWrapper): '''Callback object passed to TWS, these functions will be called directly by TWS. ''' def __init__(self, port=4001, client_id=12): super(SwigIBClientForInstrument, self).__init__() self.tws = EPosixClientSocket(self) self.port = port self.client_id = client_id self.got_history = Event() self.got_contract = Event() self.got_err = Event() self.order_filled = Event() self.order_ids = Queue() def execDetails(self, id, contract, execution): pass def managedAccounts(self, openOrderEnd): pass ### Order def nextValidId(self, validOrderId): '''Capture the next order id''' self.order_ids.put(validOrderId) def request_contract_details(self, contract): today = datetime.today() print("Requesting contract details...") # Perform the request self.tws.reqContractDetails( 43, # reqId, contract, # contract, ) print( "\n====================================================================" ) print(" Contract details requested, waiting %ds for TWS responses" % WAIT_TIME) print( "====================================================================\n" ) try: self.got_contract.wait(timeout=WAIT_TIME) except KeyboardInterrupt: pass finally: if not self.got_contract.is_set(): print('Failed to get contract within %d seconds' % WAIT_TIME) def contractDetails(self, reqId, contractDetails): print("Contract details received (request id %i):" % reqId) print("callable: %s" % contractDetails.callable) print("category: %s" % contractDetails.category) print("contractMonth: %s" % contractDetails.contractMonth) print("convertible: %s" % contractDetails.convertible) print("coupon: %s" % contractDetails.coupon) print("industry: %s" % contractDetails.industry) print("liquidHours: %s" % contractDetails.liquidHours) print("longName: %s" % contractDetails.longName) print("marketName: %s" % contractDetails.marketName) print("minTick: %s" % contractDetails.minTick) print("nextOptionPartial: %s" % contractDetails.nextOptionPartial) print("orderTypes: %s" % contractDetails.orderTypes) print("priceMagnifier: %s" % contractDetails.priceMagnifier) print("putable: %s" % contractDetails.putable) if contractDetails.secIdList is not None: for secId in contractDetails.secIdList: print("secIdList: %s" % secId) else: print("secIdList: None") print("subcategory: %s" % contractDetails.subcategory) print("tradingHours: %s" % contractDetails.tradingHours) print("timeZoneId: %s" % contractDetails.timeZoneId) print("underConId: %s" % contractDetails.underConId) print("evRule: %s" % contractDetails.evRule) print("evMultiplier: %s" % contractDetails.evMultiplier) contract = contractDetails.summary print("\nContract Summary:") print("exchange: %s" % contract.exchange) print("symbol: %s" % contract.symbol) print("secType: %s" % contract.secType) print("currency: %s" % contract.currency) print("tradingClass: %s" % contract.tradingClass) if contract.comboLegs is not None: for comboLeg in contract.comboLegs: print("comboLegs: %s - %s" % (comboLeg.action, comboLeg.exchange)) else: print("comboLegs: None") # inst_id = seq_mgr.get_next_sequence("instruments") print("\nBond Values:") print("bondType: %s" % contractDetails.bondType) print("couponType: %s" % contractDetails.couponType) print("cusip: %s" % contractDetails.cusip) print("descAppend: %s" % contractDetails.descAppend) print("issueDate: %s" % contractDetails.issueDate) print("maturity: %s" % contractDetails.maturity) print("nextOptionDate: %s" % contractDetails.nextOptionDate) print("nextOptionType: %s" % contractDetails.nextOptionType) print("notes: %s" % contractDetails.notes) print("ratings: %s" % contractDetails.ratings) print("validExchanges: %s" % contractDetails.validExchanges) self.got_contract.set()
barCount, WAP, hasGaps): if date[:8] == 'finished': print "History request complete" else: date = datetime.strptime(date, "%Y%m%d").strftime("%d %b %Y") print ( "History %s - Open: %s, High: %s, Low: %s, Close: " + "%s, Volume: %d" ) % (date, open, high, low, close, volume) # Instantiate our callback object callback = HistoricalDataExample() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost tws.eConnect("", 7496, 42) # Simple contract for DELL dell = Contract() dell.exchange = "SMART" dell.symbol = "DELL" dell.secType = "STK" dell.currency = "USD" today = datetime.today() print "Requesting historical data for %s" % dell.symbol # Request some historical data.
class IBBroker(Broker): cid = 0 # connection id oid = 0 # order id tid = 0 # tick id (for fetching quotes) tws = None # Trader WorkStation wrapper = None # instance of EWrapper sid_to_tid = {} # map of security id to tick id def __init__(self, wrapper=None): Broker.__init__(self) # initialize a default wrapper if wrapper: self.wrapper = wrapper else: self.wrapper = WrapperDefault() # initialize the wrapper's portfolio object self.wrapper.portfolio = IBPortfolio() # get next order id def get_next_oid(self): IBBroker.oid += 1 return IBBroker.oid # get next connection id def get_next_cid(self): IBBroker.cid += 1 return IBBroker.cid # get next tick request id (for getting quotes) def get_next_tid(self): self.tid += 1 return self.tid # connect to TWS def connect(self, port=7496): if self.is_connected(): self.disconnect() cid = self.get_next_cid() self.tws = EPosixClientSocket(self.wrapper) self.tws.eConnect('', port, cid) # disconnect from TWS def disconnect(self): self.tws.eDisconnect() # check if TWS is connected def is_connected(self): if self.tws is None: return False return self.tws.isConnected() # Convert Zipline order signs into IB action strings def order_action(self, iSign): if iSign > 0: return 'BUY' elif iSign < 0: return 'SELL' raise Exception('Order of zero shares has no IB side: %i' % iSign) # get an IB contract by ticker def get_contract_by_sid(self, sid): contract = Contract() contract.symbol = sid contract.secType = 'STK' contract.exchange = 'SMART' contract.currency = 'USD' return contract # get a default IB market order def get_market_order(self, sid, amt): order = Order(); order.action = self.order_action(amt) order.totalQuantity = abs(amt) order.orderType = 'MKT' order.tif = 'DAY' order.outsideRth = False return order # get a default IB limit order def get_limit_order(self, sid, amt, lmtPrice): order = Order(); order.action = self.order_action(amt) order.totalQuantity = abs(amt) order.orderType = 'LMT' order.tif = 'DAY' order.outsideRth = False order.lmtPrice = lmtPrice return order # send the IB (contract, order) order to TWS def place_order(self, contract, order): oid = self.get_next_oid() self.tws.placeOrder(oid, contract, order) return oid # send order with Zipline style order arguments # <TODO> stop_price is not implemented def order(self, sid, amt, limit_price=None, stop_price=None): contract = self.get_contract_by_sid(sid) amt = int(amt) if limit_price is None: order = self.get_market_order(sid, amt) else: order = self.get_limit_order(sid, amt, limit_price) return self.place_order(contract, order) # subscribe to market data ticks def subscribe(self, sid): tid = self.get_next_tid() self.sid_to_tid[sid] = tid contract = self.get_contract_by_sid(sid) self.tws.reqMktData(tid, contract, '', False) return tid # subscribe to market data ticks for a list of tickers def subscribe_list(self, tickers): for tkr in tickers: self.subscribe(tkr) # cancel a market data subscription def unsubscribe(self, sid): if sid not in self.sid_to_tid.keys(): return tid = self.sid_to_tid[sid] self.tws.cancelMktData(tid) # cancel all market data subscriptions def unsubscribe_all(self): sids = self.sid_to_tid.keys() for sid in sids: self.unsubscribe(sid) # fetch a quote by ticker id tid def get_quote_by_tid(self, tid): return self.wrapper.tid_to_price[tid] # fetch a quote by ticker sid def get_quote(self, sid): if sid not in self.sid_to_tid: self.subscribe(sid) return (None, None) tid = self.sid_to_tid[sid] if tid not in self.wrapper.tid_to_price: price = None else: price = self.wrapper.tid_to_price[tid] if tid not in self.wrapper.tid_to_size: size = None else: size = self.wrapper.tid_to_size[tid] return (price, size) # fetch a price by ticker sid def get_price(self, sid): if sid not in self.sid_to_tid: self.subscribe(sid) return None tid = self.sid_to_tid[sid] if tid not in self.wrapper.tid_to_price: return None else: price_dict = self.wrapper.tid_to_price[tid] if 'price' in price_dict: return price_dict['price'] return None # get a Pandas DataFrame of current positions def get_positions_frame(self): ib_dict = {} for sid, position in self.wrapper.portfolio.sid_to_position.iteritems(): # <TODO> don't use vars here #ib_dict[sid] = vars(position) ib_dict[sid] = {'marketValue': position.marketValue, 'realizedPNL': position.realizedPNL, 'marketPrice': position.marketPrice, 'unrealizedPNL': position.unrealizedPNL, 'accountName': position.accountName, 'averageCost': position.averageCost, 'sid': position.sid, 'position': position.position} return pd.DataFrame.from_dict(ib_dict, orient='index')
from datetime import datetime, timedelta import time from swigibpy import EWrapper, EPosixClientSocket, Contract, Order import sys sys.path.append('/home/mchan/git/Artemis/SwigIbPy/') from ArtemisIBWrapper import ArtemisIBWrapper ### # Instantiate our callback object callback = ArtemisIBWrapper() # Instantiate a socket object, allowing us to call TWS directly. Pass our # callback object so TWS can respond. tws = EPosixClientSocket(callback) # Connect to tws running on localhost #tws.eConnect("", 7496, 47, poll_interval=1) tws.eConnect("", 7496, 47) accountNumber = '' # Simple contract for GOOG contract = Contract() #contract.conId = 114376112 contract.exchange = "SMART" contract.symbol = "PRXL" contract.secType = "STK" #contract.right = "PUT" contract.currency = "USD" #contract.secType = 'OPT' #contract.strike = 24