def __init__(self, server): self.server = server self.config = Config(server) self.hostname = self.config.get('HOST') self.port = self.config.get('HTTP_PORT') self.username = self.config.get('USERNAME') self.password = self.config.get('PASSWORD') self.account = self.config.get('API_ACCOUNT') self.order_route = self.config.get('API_ROUTE') self.mode = self.config.get('MODE') self.get_retries = int(self.config.get('GET_RETRIES')) self.get_backoff_factor = float(self.config.get('GET_BACKOFF_FACTOR')) self.url = 'http://%s:%s' % (self.hostname, self.port) self.cmdmap = { 'help': (self.help, False, ()), 'status': (self.status, False, ()), 'version': (self.version, False, ()), 'time': (self.time, False, ()), 'shutdown': (self.shutdown, False, ('message')), 'uptime': (self.uptime, False, ()), 'query_bars': (self.query_bars, True, ('symbol', 'interval', 'start_time', 'end_time')), 'add_symbol': (self.add_symbol, True, ('symbol', )), 'del_symbol': (self.del_symbol, True, ('symbol', )), 'query_symbol': (self.query_symbol, True, ('symbol', )), 'query_symbol_data': (self.query_symbol_data, True, ('symbol', )), 'query_symbols': (self.query_symbols, True, ()), 'set_account': (self.set_account, False, ('account', )), 'set_order_route': (self.set_order_route, True, ('route', )), 'get_order_route': (self.get_order_route, True, ()), 'query_accounts': (self.query_accounts, False, ()), 'query_account': (self.query_account, True, ('account', 'fields')), 'query_positions': (self.query_positions, True, ()), 'query_orders': (self.query_orders, True, ()), 'query_order': (self.query_order, True, ('order_id', )), 'cancel_order': (self.cancel_order, True, ('order_id', )), 'query_executions': (self.query_executions, True, ()), 'market_order': (self.market_order, True, ('symbol', 'quantity')), 'create_staged_order_ticket': (self.create_staged_order_ticket, True, ()), 'stage_market_order': (self.stage_market_order, True, ('tag', 'symbol', 'quantity')), 'limit_order': (self.limit_order, True, ('symbol', 'limit_price', 'quantity')), 'stop_order': (self.stop_order, True, ('symbol', 'stop_price', 'quantity')), 'stoplimit_order': (self.stoplimit_order, True, ('symbol', 'stop_price', 'limit_price', 'quantity')), 'global_cancel': (self.global_cancel, True, ()), 'gateway_logon': (self.gateway_logon, True, ('username', 'password')), 'gateway_logoff': (self.gateway_logoff, True, ()), 'set_primary_exchange': (self.set_primary_exchange, True, ('symbol', 'exchange')), }
def __init__(self, server): self.server = server self.config = Config(server) self.hostname = self.config.get('HOST') self.port = self.config.get('HTTP_PORT') self.username = self.config.get('USERNAME') self.password = self.config.get('PASSWORD') self.account = self.config.get('API_ACCOUNT') self.url = 'http://%s:%s' % (self.hostname, self.port) self.cmdmap = { 'help': (self.help, False, ()), 'status': (self.status, False, ()), 'version': (self.version, False, ()), 'shutdown': (self.shutdown, False, ()), 'uptime': (self.uptime, False, ()), 'query_bars': (self.query_bars, True, ('symbol', 'interval', 'start_time', 'end_time')), 'add_symbol': (self.add_symbol, True, ('symbol',)), 'del_symbol': (self.del_symbol, True, ('symbol',)), 'query_symbol': (self.query_symbol, True, ('symbol',)), 'query_symbols': (self.query_symbols, True, ()), 'set_account': (self.set_account, False, ('account',)), 'query_accounts': (self.query_accounts, False, ()), 'query_account': (self.query_account, True, ('account', 'fields')), 'query_positions': (self.query_positions, True, ()), 'query_orders': (self.query_orders, True, ()), 'query_order': (self.query_order, True, ('order_id',)), 'cancel_order': (self.cancel_order, True, ('order_id',)), 'query_executions': (self.query_executions, True, ()), 'market_order': (self.market_order, True, ('symbol', 'quantity')), 'limit_order': (self.limit_order, True, ('symbol', 'limit_price', 'quantity')), 'stop_order': (self.stop_order, True, ('symbol', 'stop_price', 'quantity')), 'stoplimit_order': (self.stoplimit_order, True, ('symbol', 'stop_price', 'limit_price', 'quantity')), 'global_cancel': (self.global_cancel, True, ()), 'gateway_logon': (self.gateway_logon, True, ('username', 'password')), 'gateway_logoff': (self.gateway_logoff, True, ()), 'set_primary_exchange': (self.set_primary_exchange, True, ('symbol', 'exchange')) }
def __init__(self): self.output('TWS init') self.channel = 'tws' self.config = Config(self.channel) self.username = self.config.get('USERNAME') self.password = self.config.get('PASSWORD') self.http_port = int(self.config.get('HTTP_PORT')) self.tcp_port = int(self.config.get('TCP_PORT')) self.callback_timeout = int(self.config.get('CALLBACK_TIMEOUT')) if not self.callback_timeout: self.callback_timeout = DEFAULT_TWS_CALLBACK_TIMEOUT self.output('callback_timeout=%d' % self.callback_timeout) self.enable_ticker = bool(int(self.config.get('ENABLE_TICKER'))) self.log_api_messages = bool(int(self.config.get('LOG_API_MESSAGES'))) self.output_second_ticks = bool( int(self.config.get('ENABLE_SECONDS_TICK'))) self.suppress_error_codes = [ int(c) for c in self.config.get('SUPPRESS_ERROR_CODES').split(',') ] self.label = 'TWS Gateway' self.current_account = '' self.clients = set([]) self.orders = {} self.pending_orders = {} self.openorder_callbacks = [] self.accounts = [] self.account_data = {} self.pending_account_data_requests = set([]) self.positions = {} self.position_callbacks = [] self.executions = {} self.execution_callbacks = [] self.bardata_callbacks = [] self.cancel_callbacks = [] self.order_callbacks = [] self.addsymbol_callbacks = [] self.accountdata_callbacks = [] self.last_connection_status = '' self.connection_status = 'Initializing' self.LastError = -1 self.next_order_id = -1 self.last_minute = -1 self.handlers = { 'error': self.error_handler, 'tickSize': self.handle_tick_size, 'tickPrice': self.handle_tick_price, 'tickString': self.handle_tick_string, 'nextValidId': self.handle_next_valid_id, 'currentTime': self.handle_time, 'managedAccounts': self.handle_accounts, 'orderStatus': self.handle_order_status, 'openOrder': self.handle_open_order, 'openOrderEnd': self.handle_open_order_end, 'execDetails': self.handle_exec_details, 'execDetailsEnd': self.handle_exec_details_end, 'position': self.handle_position, 'positionEnd': self.handle_position_end, 'historicalData': self.handle_historical_data, 'updateAccountValue': self.handle_account_value, 'accountDownloadEnd': self.handle_account_download_end, } self.ticker_ids = {} self.symbols = {} self.symbols_by_id = {} self.primary_exchange_map = {} self.tws_conn = None repeater = LoopingCall(self.EverySecond) # start repeater on even RTC second t = time.time() t = 1 - (t - int(t)) time.sleep(t) repeater.start(1)
class TWS(object): def __init__(self): self.output('TWS init') self.channel = 'tws' self.config = Config(self.channel) self.username = self.config.get('USERNAME') self.password = self.config.get('PASSWORD') self.http_port = int(self.config.get('HTTP_PORT')) self.tcp_port = int(self.config.get('TCP_PORT')) self.callback_timeout = int(self.config.get('CALLBACK_TIMEOUT')) if not self.callback_timeout: self.callback_timeout = DEFAULT_TWS_CALLBACK_TIMEOUT self.output('callback_timeout=%d' % self.callback_timeout) self.enable_ticker = bool(int(self.config.get('ENABLE_TICKER'))) self.log_api_messages = bool(int(self.config.get('LOG_API_MESSAGES'))) self.output_second_ticks = bool( int(self.config.get('ENABLE_SECONDS_TICK'))) self.suppress_error_codes = [ int(c) for c in self.config.get('SUPPRESS_ERROR_CODES').split(',') ] self.label = 'TWS Gateway' self.current_account = '' self.clients = set([]) self.orders = {} self.pending_orders = {} self.openorder_callbacks = [] self.accounts = [] self.account_data = {} self.pending_account_data_requests = set([]) self.positions = {} self.position_callbacks = [] self.executions = {} self.execution_callbacks = [] self.bardata_callbacks = [] self.cancel_callbacks = [] self.order_callbacks = [] self.addsymbol_callbacks = [] self.accountdata_callbacks = [] self.last_connection_status = '' self.connection_status = 'Initializing' self.LastError = -1 self.next_order_id = -1 self.last_minute = -1 self.handlers = { 'error': self.error_handler, 'tickSize': self.handle_tick_size, 'tickPrice': self.handle_tick_price, 'tickString': self.handle_tick_string, 'nextValidId': self.handle_next_valid_id, 'currentTime': self.handle_time, 'managedAccounts': self.handle_accounts, 'orderStatus': self.handle_order_status, 'openOrder': self.handle_open_order, 'openOrderEnd': self.handle_open_order_end, 'execDetails': self.handle_exec_details, 'execDetailsEnd': self.handle_exec_details_end, 'position': self.handle_position, 'positionEnd': self.handle_position_end, 'historicalData': self.handle_historical_data, 'updateAccountValue': self.handle_account_value, 'accountDownloadEnd': self.handle_account_download_end, } self.ticker_ids = {} self.symbols = {} self.symbols_by_id = {} self.primary_exchange_map = {} self.tws_conn = None repeater = LoopingCall(self.EverySecond) # start repeater on even RTC second t = time.time() t = 1 - (t - int(t)) time.sleep(t) repeater.start(1) def output(self, msg): if 'error' in msg.lower(): log.err(msg) else: log.msg(msg) def open_client(self, client): self.clients.add(client) def close_client(self, client): self.clients.discard(client) symbols = self.symbols.values() for ts in symbols: if client in ts.clients: ts.del_client(client) if not ts.clients: del (self.symbols[ts.symbol]) def set_primary_exchange(self, symbol, exchange): if exchange: self.primary_exchange_map[symbol] = exchange else: del (self.primary_exchange_map[symbol]) return self.primary_exchange_map def CheckPendingResults(self): # check each callback list for timeouts for cblist in [ self.position_callbacks, self.openorder_callbacks, self.execution_callbacks, self.bardata_callbacks, self.order_callbacks, self.cancel_callbacks, self.addsymbol_callbacks, self.accountdata_callbacks ]: dlist = [] for cb in cblist: cb.check_expire() if cb.done: dlist.append(cb) if cblist == self.order_callbacks: mid = str(cb.id) if mid in self.pending_orders.keys(): del (self.pending_orders[mid]) self.output('pending order %s expired' % mid) # delete any callbacks that are done for cb in dlist: cblist.remove(cb) def process_pending_order(self, mid, pid): # if there's a pending order with this msg id, this is the first time we # know the permid for the order, so move it to the real orders dict if mid in self.pending_orders.keys(): self.orders[pid] = self.pending_orders[mid] self.orders[pid]['permid'] = pid del (self.pending_orders[mid]) self.output('pending order %s assigned permid %s' % (mid, pid)) def handle_order_status(self, msg): mid = str(msg.orderId) pid = str(msg.permId) self.process_pending_order(mid, pid) if not pid in self.orders.keys(): self.orders[pid] = {} m = self.orders[pid] if 'status' in m.keys(): oldstatus = json.dumps(m) else: oldstatus = '' m['permid'] = str(msg.permId) m['id'] = msg.orderId m['status'] = msg.status if msg.status == 'Filled' and 'submit_time' in m and not 'fill_time' in m: m['fill_time'] = time.time() m['filled'] = msg.filled m['remaining'] = msg.remaining m['avgfillprice'] = msg.avgFillPrice m['parentid'] = msg.parentId m['lastfillprice'] = msg.lastFillPrice m['clientid'] = msg.clientId m['whyheld'] = msg.whyHeld # callbacks are keyed by message-id, not permid for cb in self.cancel_callbacks: if cb.id == mid: self.output('cancel_callback[%s] completed' % mid) cb.complete(m) for cb in self.order_callbacks: if cb.id == mid: self.output('order_callback[%s] completed' % mid) cb.complete(m) if json.dumps(m) != oldstatus: self.send_order_status(m) def send_order_status(self, order): self.WriteAllClients('order.%s: %s' % (order['permid'], json.dumps(order))) def handle_open_order(self, msg): mid = str(msg.orderId) pid = str(msg.order.m_permId) self.process_pending_order(mid, pid) if not pid in self.orders.keys(): self.orders[pid] = {} m = self.orders[pid] if 'status' in m.keys(): oldstatus = json.dumps(m) else: oldstatus = '' m['id'] = msg.orderId m['symbol'] = msg.contract.m_symbol m['action'] = msg.order.m_action m['quantity'] = msg.order.m_totalQuantity m['account'] = msg.order.m_account m['clientid'] = msg.order.m_clientId m['permid'] = msg.order.m_permId m['price'] = msg.order.m_lmtPrice m['aux_price'] = msg.order.m_auxPrice m['type'] = msg.order.m_orderType m['status'] = msg.orderState.m_status m['warning'] = msg.orderState.m_warningText if oldstatus != json.dumps(m): self.WriteAllClients('open-order.%s: %s' % (m['permid'], json.dumps(m))) def handle_accounts(self, msg): self.accounts = msg.accountsList.split(',') self.WriteAllClients('accounts: %s' % json.dumps(self.accounts)) def set_account(self, account_name, callback): if account_name in self.accounts: if account_name != self.current_account: self.current_account = account_name msg = 'current account set to %s' % account_name self.output(msg) self.WriteAllClients('current-account: %s' % self.current_account) ret = True else: msg = 'account %s not found' % account_name self.output('Error: set_account(): %s' % msg) ret = False if callback: TWS_Callback(self, 0, 'current-account', callback).complete(ret) else: return ret def EverySecond(self): if self.tws_conn: self.tws_conn.reqCurrentTime() else: self.connect() self.CheckPendingResults() if self.LastError == 504: if SHUTDOWN_ON_TWS_DISCONNECT: self.output('TWS API disconnected; forcing shutdown') reactor.stop() else: self.output('TWS API disconnected; attempting connection...') def WriteAllClients(self, msg): #self.output('WriteAllClients: %s.%s' % (self.channel, msg)) msg = str('%s.%s\n' % (self.channel, msg)) for c in self.clients: c.transport.write(msg) def error_handler(self, msg): """Handles the capturing of error messages""" if msg.id is None and msg.errorCode is None: return self.LastError = msg.errorCode if 2100 <= msg.errorCode <= 2110 or msg.errorCode == 2137: status = 'Warning' else: status = 'Error' result = { 'status': status, 'id': msg.id, 'code': msg.errorCode, 'msg': msg.errorMsg } self.output('%s: %s' % (status.lower(), result)) for cb in self.order_callbacks: if str(cb.id) == str(msg.id): cb.complete(result) for cb in self.cancel_callbacks: if str(cb.id) == str(msg.id): cb.complete(result) for cb in self.bardata_callbacks: if str(cb.id) == str(msg.id): cb.complete(['Error: %s' % msg.errorMsg, None]) for cb in self.addsymbol_callbacks: if str(cb.id.ticker_id) == str(msg.id): cb.complete(False) del (self.symbols[self.symbols_by_id[msg.id].symbol]) del (self.symbols_by_id[msg.id]) order = self.find_order_with_id(str(msg.id)) if order: order['previous_status'] = order['status'] order['status'] = status order['errorCode'] = msg.errorCode order['errorMsg'] = msg.errorMsg self.send_order_status(order) if msg.errorCode in [1100, 1300]: self.update_connection_status('Disconnected') elif msg.errorCode in [1101, 1102, 2104]: self.update_connection_status('Up') if not msg.errorCode in self.suppress_error_codes: self.WriteAllClients('%s: %s' % (status.lower(), msg)) def find_order_with_id(self, id): for order in self.orders.values(): if 'id' in order.keys() and str(order['id']) == str(id): return order return None def reply_handler(self, msg): """Handles of server replies""" if self.log_api_messages: self.output('message: %s %s ' % (repr(msg.typeName), msg)) if msg.typeName in self.handlers.keys(): self.handlers[msg.typeName](msg) else: self.output('unhandled: %s' % msg) def handle_time(self, msg): t = time.localtime(msg.time) if t[4] != self.last_minute or self.output_second_ticks: self.last_minute = t[4] self.WriteAllClients('time: %s' % time.strftime('%Y-%m-%d %H:%M:%S', t)) def create_contract(self, symbol, sec_type, exch, prim_exch, curr): """Create a Contract object defining what will be purchased, at which exchange and in which currency. symbol - The ticker symbol for the contract sec_type - The security type for the contract ('STK' is 'stock') exch - The exchange to carry out the contract on prim_exch - The primary exchange to carry out the contract on curr - The currency in which to purchase the contract In cases where SMART exchange results in ambiguity SYMBOL:PRIMARY_EXCHANGE can be passed.""" contract = Contract() contract.m_symbol = symbol contract.m_secType = sec_type contract.m_exchange = exch if symbol in self.primary_exchange_map.keys(): contract.m_primaryExch = self.primary_exchange_map[symbol] else: contract.m_primaryExch = prim_exch contract.m_currency = curr return contract def create_order(self, order_type, quantity, action): """Create an Order object (Market/Limit) to go long/short. order_type - 'MKT', 'LMT' for Market or Limit orders quantity - Integral number of assets to order action - 'BUY' or 'SELL'""" order = Order() order.m_orderType = order_type order.m_totalQuantity = quantity order.m_action = action order.m_account = self.current_account return order def connect(self): self.update_connection_status('Connecting') api_hostname = self.config.get('API_HOST') api_port = int(self.config.get('API_PORT')) api_client_id = int(self.config.get('API_CLIENT_ID')) self.output('Connnecting to TWS API at %s:%d with client id %d' % (api_hostname, api_port, api_client_id)) self.tws_conn = Connection.create(host=api_hostname, port=api_port, clientId=api_client_id) self.tws_conn.registerAll(self.reply_handler) self.tws_conn.connect() def market_order(self, symbol, quantity, callback): return self.submit_order('MKT', 0, 0, symbol, int(quantity), callback) def limit_order(self, symbol, limit_price, quantity, callback): return self.submit_order('LMT', float(limit_price), 0, symbol, int(quantity), callback) def stop_order(self, symbol, stop_price, quantity, callback): return self.submit_order('STP', 0, float(stop_price), symbol, int(quantity), callback) def stoplimit_order(self, symbol, stop_price, limit_price, quantity, callback): return self.submit_order('STP LMT', float(limit_price), float(stop_price), symbol, int(quantity), callback) def submit_order(self, order_type, price, stop_price, symbol, quantity, callback): order_id = self.next_id() tcb = TWS_Callback(self, str(order_id), 'order', callback) if (order_id < 0): ret = { 'status': 'Error', 'errorMsg': 'Cannot create order; next_order_id is not set' } tcb.complete(ret) else: status = 'Initialized' self.pending_orders[str(order_id)] = {} self.pending_orders[str(order_id)]['status'] = status self.pending_orders[str(order_id)]['submit_time'] = time.time() self.output('created pending order %s' % str(order_id)) contract = self.create_contract(symbol, 'STK', 'SMART', 'SMART', 'USD') if quantity > 0: type = 'BUY' else: type = 'SELL' quantity *= -1 order = self.create_order(order_type, quantity, type) if order_type in ['STP', 'STP LMT']: order.m_auxPrice = stop_price if order_type in ['LMT', 'STP LMT']: order.m_lmtPrice = price self.order_callbacks.append(tcb) resp = self.tws_conn.placeOrder(order_id, contract, order) self.output('placeOrder(%s) returned %s' % (repr( (order_id, contract, order)), repr(resp))) def cancel_order(self, id, callback): self.output('cancel_order%s' % repr((id))) mid = str(id) tcb = TWS_Callback(self, mid, 'cancel_order', callback) order = self.find_order_with_id(mid) if order: if order['status'] == 'Cancelled': tcb.complete({ 'status': 'Error', 'errorMsg': 'Already cancelled.', 'id': id }) else: resp = self.tws_conn.cancelOrder(mid) self.output('cancelOrder(%s) returned %s' % (repr(mid), repr(resp))) self.cancel_callbacks.append(tcb) else: tcb.complete({ 'status': 'Error', 'errorMsg': 'Order not found', 'id': mid }) def symbol_enable(self, symbol, client, callback): if not symbol in self.symbols.keys(): self.addsymbol_callbacks.append( TWS_Callback(self, TWS_Symbol(self, symbol, client), 'add-symbol', callback)) else: self.symbols[symbol].add_client(client) TWS_Callback(self, 0, 'add-symbol', callback).complete(True) def symbol_disable(self, symbol, client): if symbol in self.symbols.keys(): ts = self.symbols[symbol] ts.del_client(client) if not ts.clients: del (self.symbols[symbol]) return True def handle_tick_size(self, msg): symbol = self.symbols_by_id[msg.tickerId] # if self.enable_ticker: # self.output('%s %s %d %s %d' % (repr(msg), symbol, msg.field, TickType().getField(msg.field), msg.size)) if msg.field == 0: # bid_size symbol.bid_size = msg.size if self.enable_ticker: symbol.update_quote() elif msg.field == 3: # ask_size symbol.ask_size = msg.size if self.enable_ticker: symbol.update_quote() elif msg.field == 5: # last_size symbol.size = msg.size elif msg.field == 8: # volume symbol.volume = msg.size if self.enable_ticker: symbol.update_trade() def handle_tick_price(self, msg): for cb in self.addsymbol_callbacks: if str(cb.id.ticker_id) == str(msg.tickerId) and not cb.done: cb.complete(True) # if self.enable_ticker: # self.output('%s %d %s %s' % (repr(msg), msg.field, TickType().getField(msg.field), msg.price)) symbol = self.symbols_by_id[msg.tickerId] if msg.field == 1: # bid symbol.bid = msg.price if self.enable_ticker: symbol.update_quote() elif msg.field == 2: # ask symbol.ask = msg.price if self.enable_ticker: symbol.update_quote() elif msg.field == 4: # last symbol.last = msg.price elif msg.field == 9: # close symbol.close = msg.price def handle_tick_string(self, msg): pass # if self.enable_ticker: # self.output('%s %d %s %s' % (repr(msg), msg.tickType, TickType().getField(msg.tickType), msg.value)) def handle_next_valid_id(self, msg): self.next_order_id = msg.orderId msg = 'next_valid_id: %d' % msg.orderId self.WriteAllClients(msg) self.output(msg) def disconnect(self): # Disconnect from TWS self.output('TWS disconnected') self.update_connection_status('Disconnected') self.WriteAllClients('error: TWS API Disconnected') self.tws_conn.disconnect() def update_connection_status(self, status): self.connection_status = status if status != self.last_connection_status: self.last_connection_status = status self.WriteAllClients('connection-status-changed: %s' % status) def next_id(self): id = self.next_order_id self.next_order_id += 1 return id def request_accounts(self, callback): TWS_Callback(self, 0, 'request-accounts', callback).complete(self.accounts) def request_positions(self, callback): if not self.position_callbacks: self.positions = {} self.tws_conn.reqPositions() id = self.next_id() self.position_callbacks.append( TWS_Callback(self, 0, 'positions', callback)) return id def handle_position(self, msg): if not msg.account in self.positions.keys(): self.positions[msg.account] = {} # only return STOCK positions if msg.contract.m_secType == 'STK': pos = self.positions[msg.account] pos[msg.contract.m_symbol] = msg.pos def handle_position_end(self, msg): for cb in self.position_callbacks: cb.complete(self.positions) self.position_callbacks = [] def request_orders(self, callback): if not self.openorder_callbacks: self.tws_conn.reqAllOpenOrders() self.openorder_callbacks.append( TWS_Callback(self, 0, 'orders', callback)) def request_order(self, oid, callback): TWS_Callback(self, 0, 'request-order', callback).complete(self.orders[oid]) def handle_open_order_end(self, msg): for cb in self.openorder_callbacks: cb.complete(self.orders) self.openorder_callbacks = [] def request_executions(self, callback): if not self.execution_callbacks: self.executions = {} filter = ExecutionFilter() id = self.next_id() self.tws_conn.reqExecutions(id, filter) self.execution_callbacks.append( TWS_Callback(self, 0, 'executions', callback)) def request_account_data(self, account, fields, callback): need_request = False if account not in self.pending_account_data_requests: self.account_data[account] = {} need_request = True cb = TWS_Callback(self, account, 'account_data', callback) cb.data = fields self.accountdata_callbacks.append(cb) if need_request: self.output('requesting account updates: %s' % account) self.pending_account_data_requests.add(account) self.tws_conn.reqAccountUpdates(False, account) self.tws_conn.reqAccountUpdates(True, account) else: self.output( 'NOT requesting account updates: %s (one is already pending)' % account) def handle_account_value(self, msg): self.output( '%s %s %s %s %s' % (repr(msg), msg.key, msg.value, msg.currency, msg.accountName)) if not msg.accountName in self.account_data.keys(): self.account_data[msg.accountName] = {} self.account_data[msg.accountName][msg.key] = (msg.value, msg.currency) def handle_account_download_end(self, msg): self.output('%s %s' % (repr(msg), msg.accountName)) dcb = [] for cb in self.accountdata_callbacks: if cb.id == msg.accountName: account_data = self.account_data[msg.accountName] # if field list specified, only return those fields, else return all fields if cb.data: response_data = {} for field in cb.data: response_data[field] = account_data[ field] if field in account_data.keys() else None else: response_data = account_data cb.complete(response_data) dcb.append(cb) self.tws_conn.reqAccountUpdates(False, msg.accountName) self.output('cancelling account updates: %s' % msg.accountName) self.pending_account_data_requests.discard(msg.accountName) for cb in dcb: del self.accountdata_callbacks[self.accountdata_callbacks.index( cb)] def handle_exec_details(self, msg): self.output('%s %s %s %s %s' % (repr(msg), msg.execution.m_side, msg.contract.m_symbol, msg.execution.m_cumQty, msg.execution.m_price)) self.executions[msg.execution.m_execId] = {} e = self.executions[msg.execution.m_execId] e['execId'] = msg.execution.m_execId e['symbol'] = msg.contract.m_symbol e['account'] = msg.execution.m_acctNumber e['avgprice'] = msg.execution.m_avgPrice e['cumqty'] = msg.execution.m_cumQty e['exchange'] = msg.execution.m_exchange e['clientid'] = msg.execution.m_clientId e['orderid'] = msg.execution.m_orderId e['permid'] = msg.execution.m_permId e['shares'] = msg.execution.m_shares e['price'] = msg.execution.m_price e['side'] = msg.execution.m_side e['time'] = msg.execution.m_time self.WriteAllClients('execution.%s: %s' % (e['execId'], json.dumps(e))) def handle_exec_details_end(self, msg): for cb in self.execution_callbacks: cb.complete(self.executions) self.execution_callbacks = [] def request_global_cancel(self): self.tws_conn.reqGlobalCancel() def query_bars(self, symbol, period, bar_start, bar_end, callback): id = self.next_id() self.output('bardata request id=%s' % id) # 30 second timeout for bar data cb = TWS_Callback(self, id, 'bardata', callback, 30) contract = self.create_contract(symbol, 'STK', 'SMART', 'SMART', 'USD') if type(bar_start) != types.IntType: bar_start = datetime.datetime.strptime(bar_start, '%Y-%m-%d %H:%M:%S') if type(bar_end) != types.IntType: bar_end = datetime.datetime.strptime(bar_end, '%Y-%m-%d %H:%M:%S') # try: if 1 == 1: endDateTime = bar_end.strftime('%Y%m%d %H:%M:%S') durationStr = '%s S' % (bar_end - bar_start).seconds barSizeSetting = { '1': '1 min', '5': '5 mins' }[str(period)] # legal period values are '1' and '5' whatToShow = 'TRADES' useRTH = 0 formatDate = 1 self.bardata_callbacks.append(cb) self.output('edt:%s ds:%s bss:%s' % (endDateTime, durationStr, barSizeSetting)) self.tws_conn.reqHistoricalData(id, contract, endDateTime, durationStr, barSizeSetting, whatToShow, useRTH, formatDate) # except: if 1 == 2: cb.complete([ 'Error', 'query_bars(%s) failed!' % repr( (bar_symbol, bar_period, bar_start, bar_end)), 'Count: 0' ]) def handle_historical_data(self, msg): for cb in self.bardata_callbacks: if cb.id == msg.reqId: if not cb.data: cb.data = [] if msg.date.startswith('finished'): cb.complete(['OK', cb.data]) else: cb.data.append(dict(msg.items())) # self.output('historical_data: %s' % msg) #repr((id, start_date, bar_open, bar_high, bar_low, bar_close, bar_volume, count, WAP, hasGaps))) def query_connection_status(self): return self.connection_status
class API(): def __init__(self, server): self.server = server self.config = Config(server) self.hostname = self.config.get('HOST') self.port = self.config.get('HTTP_PORT') self.username = self.config.get('USERNAME') self.password = self.config.get('PASSWORD') self.account = self.config.get('API_ACCOUNT') self.url = 'http://%s:%s' % (self.hostname, self.port) self.cmdmap = { 'help': (self.help, False, ()), 'status': (self.status, False, ()), 'version': (self.version, False, ()), 'time': (self.time, False, ()), 'shutdown': (self.shutdown, False, ()), 'uptime': (self.uptime, False, ()), 'query_bars': (self.query_bars, True, ('symbol', 'interval', 'start_time', 'end_time')), 'add_symbol': (self.add_symbol, True, ('symbol', )), 'del_symbol': (self.del_symbol, True, ('symbol', )), 'query_symbol': (self.query_symbol, True, ('symbol', )), 'query_symbol_data': (self.query_symbol_data, True, ('symbol', )), 'query_symbols': (self.query_symbols, True, ()), 'set_account': (self.set_account, False, ('account', )), 'set_order_route': (self.set_order_route, True, ('route', )), 'get_order_route': (self.get_order_route, True, ()), 'query_accounts': (self.query_accounts, False, ()), 'query_account': (self.query_account, True, ('account', 'fields')), 'query_positions': (self.query_positions, True, ()), 'query_orders': (self.query_orders, True, ()), 'query_order': (self.query_order, True, ('order_id', )), 'cancel_order': (self.cancel_order, True, ('order_id', )), 'query_executions': (self.query_executions, True, ()), 'market_order': (self.market_order, True, ('symbol', 'quantity')), 'create_staged_order_ticket': (self.create_staged_order_ticket, True, ()), 'stage_market_order': (self.stage_market_order, True, ('tag', 'symbol', 'quantity')), 'limit_order': (self.limit_order, True, ('symbol', 'limit_price', 'quantity')), 'stop_order': (self.stop_order, True, ('symbol', 'stop_price', 'quantity')), 'stoplimit_order': (self.stoplimit_order, True, ('symbol', 'stop_price', 'limit_price', 'quantity')), 'global_cancel': (self.global_cancel, True, ()), 'gateway_logon': (self.gateway_logon, True, ('username', 'password')), 'gateway_logoff': (self.gateway_logoff, True, ()), 'set_primary_exchange': (self.set_primary_exchange, True, ('symbol', 'exchange')), } def cmd(self, cmd, args): if cmd in self.cmdmap.keys(): func, require_account, parms = self.cmdmap[cmd] if require_account: if not self.set_account(self.account): raise Exception('Error: set_account required') return func(*args) else: raise Exception('Error: unknown command: %s\n' % cmd) def call_txtrader_api(self, function_name, args): url = '%s/%s' % (self.url, function_name) headers = {'Content-type': 'application/json'} r = requests.post(url, json=args, headers=headers, auth=(self.username, self.password)) if r.status_code != requests.codes.ok: r.raise_for_status() ret = r.json() r.close() return ret def help(self, *args): return self.call_txtrader_api('help', {}) def status(self, *args): return self.call_txtrader_api('status', {}) def version(self, *args): return self.call_txtrader_api('version', {}) def shutdown(self, *args): return self.call_txtrader_api('shutdown', {}) def uptime(self, *args): return self.call_txtrader_api('uptime', {}) def time(self, *args): return self.call_txtrader_api('time', {}) def query_bars(self, *args): args = { 'symbol': args[0], 'period': args[1], 'start': args[2], 'end': args[3] } return self.call_txtrader_api('query_bars', args) def add_symbol(self, *args): return self.call_txtrader_api('add_symbol', {'symbol': args[0]}) def del_symbol(self, *args): return self.call_txtrader_api('del_symbol', {'symbol': args[0]}) def query_symbols(self, *args): return self.call_txtrader_api('query_symbols', {}) def query_symbol(self, *args): return self.call_txtrader_api('query_symbol', {'symbol': args[0]}) def query_symbol_data(self, *args): return self.call_txtrader_api('query_symbol_data', {'symbol': args[0]}) def query_accounts(self, *args): return self.call_txtrader_api('query_accounts', {}) def query_account(self, *args): account = args[0] fields = None if (len(args) > 1) and args[1]: if type(args[1]) == str: fields = args[1].split(',') elif type(args[1]) == ListType: fields = args[1] args = {'account': account} if fields: args['fields'] = fields return self.call_txtrader_api('query_account', args) def set_account(self, *args): account = args[0] ret = self.call_txtrader_api('set_account', {'account': account}) if ret: self.account = account return ret def query_positions(self, *args): return self.call_txtrader_api('query_positions', {}) def query_orders(self, *args): return self.call_txtrader_api('query_orders', {}) def query_order(self, *args): return self.call_txtrader_api('query_order', {'id': args[0]}) def cancel_order(self, *args): return self.call_txtrader_api('cancel_order', {'id': args[0]}) def query_executions(self, *args): return self.call_txtrader_api('query_executions', {}) def create_staged_order_ticket(self, *args): return self.call_txtrader_api('create_staged_order_ticket', {}) def market_order(self, *args): symbol, quantity = args[0:2] return self.call_txtrader_api('market_order', { 'account': self.account, 'symbol': symbol, 'quantity': int(quantity) }) def stage_market_order(self, *args): tag, symbol, quantity = args[0:3] return self.call_txtrader_api( 'stage_market_order', { 'tag': tag, 'account': self.account, 'symbol': symbol, 'quantity': int(quantity) }) def limit_order(self, *args): symbol, limit_price, quantity = args[0:3] return self.call_txtrader_api( 'limit_order', { 'account': self.account, 'symbol': symbol, 'limit_price': float(limit_price), 'quantity': int(quantity) }) def stop_order(self, *args): symbol, stop_price, quantity = args[0:3] return self.call_txtrader_api( 'stop_order', { 'account': self.account, 'symbol': symbol, 'stop_price': float(limit_price), 'quantity': int(quantity) }) def stoplimit_order(self, *args): symbol, stop_price, limit_price, quantity = args[0:4] return self.call_txtrader_api( 'stoplimit_order', { 'account': self.account, 'symbol': symbol, 'stop_price': float(limit_price), 'limit_price': float(limit_price), 'quantity': int(quantity) }) def global_cancel(self, *args): return self.call_txtrader_api('global_cancel', {}) def gateway_logon(self, *args): username, password = args[0:2] return self.call_txtrader_api('gateway_logon', { 'username': username, 'password': password }) def gateway_logoff(self, *args): return self.call_txtrader_api('gateway_logoff', {}) def set_primary_exchange(self, *args): return self.call_txtrader_api('set_primary_exchange', { 'symbol': args[0], 'exchange': args[1] }) def get_order_route(self, *args): return self.call_txtrader_api('get_order_route', {}) def set_order_route(self, *args): route = args[0] print('route: %s' % repr(route)) return self.call_txtrader_api('set_order_route', {'route': route})
class API(object): def __init__(self, server=None): #sys.stderr.write('txTrader.client.API.__init__(%s, %s)\n' % (repr(self), repr(server))) self.server = server self.config = Config(server) self.hostname = self.config.get('HOST') self.port = self.config.get('HTTP_PORT') self.username = self.config.get('USERNAME') self.password = self.config.get('PASSWORD') self.account = self.config.get('API_ACCOUNT') self.order_route = self.config.get('API_ROUTE') self.mode = self.config.get('MODE') self.get_retries = int(self.config.get('GET_RETRIES')) self.get_backoff_factor = float(self.config.get('GET_BACKOFF_FACTOR')) self.url = 'http://%s:%s' % (self.hostname, self.port) self.cmdmap = { 'help': (self.help, False, ()), 'status': (self.status, False, ()), 'version': (self.version, False, ()), 'time': (self.time, False, ()), 'shutdown': (self.shutdown, False, ('message')), 'uptime': (self.uptime, False, ()), 'query_bars': (self.query_bars, True, ('symbol', 'interval', 'start_time', 'end_time')), 'add_symbol': (self.add_symbol, True, ('symbol', )), 'del_symbol': (self.del_symbol, True, ('symbol', )), 'query_symbol': (self.query_symbol, True, ('symbol', )), 'query_symbol_data': (self.query_symbol_data, True, ('symbol', )), 'query_symbol_bars': (self.query_symbol_bars, True, ('symbol', )), 'query_symbols': (self.query_symbols, True, ()), 'set_account': (self.set_account, False, ('account', )), 'set_order_route': (self.set_order_route, True, ('route', )), 'get_order_route': (self.get_order_route, True, ()), 'query_accounts': (self.query_accounts, False, ()), 'query_account': (self.query_account, True, ('account', 'fields')), 'query_positions': (self.query_positions, True, ()), 'query_orders': (self.query_orders, True, ()), 'query_tickets': (self.query_tickets, True, ()), 'query_order': (self.query_order, True, ('order_id', )), 'cancel_order': (self.cancel_order, True, ('order_id', )), 'query_executions': (self.query_executions, True, ()), 'query_order_executions': (self.query_order_executions, True, ('order_id', )), 'market_order': (self.market_order, True, ('symbol', 'quantity')), 'create_staged_order_ticket': (self.create_staged_order_ticket, True, ()), 'stage_market_order': (self.stage_market_order, True, ('tag', 'symbol', 'quantity')), 'limit_order': (self.limit_order, True, ('symbol', 'limit_price', 'quantity')), 'stop_order': (self.stop_order, True, ('symbol', 'stop_price', 'quantity')), 'stoplimit_order': (self.stoplimit_order, True, ('symbol', 'stop_price', 'limit_price', 'quantity')), 'global_cancel': (self.global_cancel, True, ()), 'gateway_logon': (self.gateway_logon, True, ('username', 'password')), 'gateway_logoff': (self.gateway_logoff, True, ()), 'set_primary_exchange': (self.set_primary_exchange, True, ('symbol', 'exchange')), } def cmd(self, cmd, args): if cmd in self.cmdmap.keys(): func, require_account, parms = self.cmdmap[cmd] if require_account: if not self.set_account(self.account): raise Exception('Error: set_account required') return func(*args) else: raise Exception('Error: unknown command: %s\n' % cmd) def call_txtrader_post(self, function_name, args): #print('call_txtrader_post(%s, %s)' % (repr(function_name), repr(args))) url = '%s/%s' % (self.url, function_name) headers = {'Content-type': 'application/json'} r = requests.post(url, json=args, headers=headers, auth=(self.username, self.password)) if r.status_code != requests.codes.ok: r.raise_for_status() ret = r.json() r.close() return ret def call_txtrader_get(self, function_name, args): url = '%s/%s' % (self.url, function_name) headers = {'Content-type': 'application/json'} r = requests_retry_session(retries=self.get_retries, backoff_factor=self.get_backoff_factor).get( url, params=args, headers=headers, auth=(self.username, self.password)) if r.status_code != requests.codes.ok: r.raise_for_status() ret = r.json() r.close() return ret def help(self, *args): helptext = self.call_txtrader_get('help', {}) commands = helptext.keys() commands.sort() print('\nTxTrader [%s] commands:\n%s' % (self.mode, '=' * 80)) for c in commands: print('%s\n' % (helptext[c].strip().replace('\n\n', '\n'))) return None def status(self, *args): return self.call_txtrader_get('status', {}) def version(self, *args): return self.call_txtrader_get('version', {}) def shutdown(self, *args): return self.call_txtrader_post('shutdown', {'message': args[0]}) def uptime(self, *args): return self.call_txtrader_get('uptime', {}) def time(self, *args): return self.call_txtrader_get('time', {}) def query_bars(self, *args): args = { 'symbol': args[0], 'period': args[1], 'start': args[2], 'end': args[3] } return self.call_txtrader_get('query_bars', args) def add_symbol(self, *args): return self.call_txtrader_post('add_symbol', {'symbol': args[0]}) def del_symbol(self, *args): return self.call_txtrader_post('del_symbol', {'symbol': args[0]}) def query_symbols(self, *args): return self.call_txtrader_get('query_symbols', {}) def query_symbol(self, *args): return self.call_txtrader_get('query_symbol', {'symbol': args[0]}) def query_symbol_data(self, *args): return self.call_txtrader_get('query_symbol_data', {'symbol': args[0]}) def query_symbol_bars(self, *args): return self.call_txtrader_get('query_symbol_bars', {'symbol': args[0]}) def query_accounts(self, *args): return self.call_txtrader_get('query_accounts', {}) def query_account(self, *args): account = args[0] fields = None if (len(args) > 1) and args[1]: if isinstance(args[1], str): fields = args[1] elif isinstance(args[1], list): fields = args[1].join(',') args = {'account': account} if fields: args['fields'] = fields return self.call_txtrader_get('query_account', args) def set_account(self, *args): account = args[0] ret = self.call_txtrader_post('set_account', {'account': account}) if ret: self.account = account return ret def query_positions(self, *args): return self.call_txtrader_get('query_positions', {}) def query_orders(self, *args): return self.call_txtrader_get('query_orders', {}) def query_tickets(self, *args): return self.call_txtrader_get('query_tickets', {}) def query_order(self, *args): return self.call_txtrader_get('query_order', {'id': args[0]}) def cancel_order(self, *args): return self.call_txtrader_post('cancel_order', {'id': args[0]}) def query_executions(self, *args): return self.call_txtrader_get('query_executions', {}) def query_order_executions(self, *args): return self.call_txtrader_get('query_order_executions', {'id': args[0]}) def create_staged_order_ticket(self, *args): return self.call_txtrader_post('create_staged_order_ticket', {}) def market_order(self, *args): symbol, quantity = args[0:2] return self.call_txtrader_post( 'market_order', { 'account': self.account, 'route': self.order_route, 'symbol': symbol, 'quantity': int(quantity) }) def stage_market_order(self, *args): tag, symbol, quantity = args[0:3] return self.call_txtrader_post( 'stage_market_order', { 'tag': tag, 'account': self.account, 'route': self.order_route, 'symbol': symbol, 'quantity': int(quantity) }) def limit_order(self, *args): symbol, limit_price, quantity = args[0:3] return self.call_txtrader_post( 'limit_order', { 'account': self.account, 'route': self.order_route, 'symbol': symbol, 'limit_price': float(limit_price), 'quantity': int(quantity) }) def stop_order(self, *args): symbol, stop_price, quantity = args[0:3] return self.call_txtrader_post( 'stop_order', { 'account': self.account, 'route': self.order_route, 'symbol': symbol, 'stop_price': float(limit_price), 'quantity': int(quantity) }) def stoplimit_order(self, *args): symbol, stop_price, limit_price, quantity = args[0:4] return self.call_txtrader_post( 'stoplimit_order', { 'account': self.account, 'route': self.order_route, 'symbol': symbol, 'stop_price': float(limit_price), 'limit_price': float(limit_price), 'quantity': int(quantity) }) def global_cancel(self, *args): return self.call_txtrader_post('global_cancel', {}) def gateway_logon(self, *args): username, password = args[0:2] return self.call_txtrader_post('gateway_logon', { 'username': username, 'password': password }) def gateway_logoff(self, *args): return self.call_txtrader_post('gateway_logoff', {}) def set_primary_exchange(self, *args): return self.call_txtrader_post('set_primary_exchange', { 'symbol': args[0], 'exchange': args[1] }) def get_order_route(self, *args): # post locally configured order route to server and return it return self.set_order_route(self.order_route) def set_order_route(self, *args): ret = self.call_txtrader_post('set_order_route', {'route': args[0]}) if ret: self.order_route = ret return ret