예제 #1
0
    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')),
        }
예제 #2
0
    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'))
        }
예제 #3
0
 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)
예제 #4
0
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
예제 #5
0
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})
예제 #6
0
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