Пример #1
0
class IbGateway(VtGateway):
    """IB接口"""

    #----------------------------------------------------------------------
    def __init__(self, eventEngine, gatewayName='IB'):
        """Constructor"""
        super(IbGateway, self).__init__(eventEngine, gatewayName)
        
        self.host = EMPTY_STRING        # 连接地址
        self.port = EMPTY_INT           # 连接端口
        self.clientId = EMPTY_INT       # 用户编号
        
        self.tickerId = 0               # 订阅行情时的代码编号    
        self.tickDict = {}              # tick快照字典,key为tickerId,value为VtTickData对象
        
        self.orderId  = 0               # 订单编号
        self.orderDict = {}             # 报单字典,key为orderId,value为VtOrderData对象
        
        self.accountDict = {}           # 账户字典
        
        self.connected = False          # 连接状态
        
        self.wrapper = IbWrapper(self)                  # 回调接口
        self.connection = EClientSocket(self.wrapper)   # 主动接口

    #----------------------------------------------------------------------
    def connect(self):
        """连接"""
        # 载入json文件
        fileName = self.gatewayName + '_connect.json'
        fileName = os.getcwd() + '/ibGateway/' + fileName
        
        try:
            f = file(fileName)
        except IOError:
            log = VtLogData()
            log.gatewayName = self.gatewayName
            log.logContent = u'读取连接配置出错,请检查'
            self.onLog(log)
            return
        
        # 解析json文件
        setting = json.load(f)
        try:
            self.host = str(setting['host'])
            self.port = int(setting['port'])
            self.clientId = int(setting['clientId'])
        except KeyError:
            log = VtLogData()
            log.gatewayName = self.gatewayName
            log.logContent = u'连接配置缺少字段,请检查'
            self.onLog(log)
            return            
        
        # 发起连接
        self.connection.eConnect(self.host, self.port, self.clientId)
        
        # 查询服务器时间
        self.connection.reqCurrentTime()
        
        # 请求账户数据主推更新
        self.connection.reqAccountUpdates(True, '')
    
    #----------------------------------------------------------------------
    def subscribe(self, subscribeReq):
        """订阅行情"""
        # 订阅行情
        self.tickerId += 1
        
        contract = Contract()
        contract.m_symbol = str(subscribeReq.symbol)
        contract.m_exchange = exchangeMap.get(subscribeReq.exchange, '')
        contract.m_secType = productClassMap.get(subscribeReq.productClass, '')
        contract.m_currency = currencyMap.get(subscribeReq.currency, '')
        contract.m_expiry = subscribeReq.expiry
        contract.m_strike = subscribeReq.strikePrice
        contract.m_right = optionTypeMap.get(subscribeReq.optionType, '')
    
        self.connection.reqMktData(self.tickerId, contract, '', False)
        
        # 创建Tick对象并保存到字典中
        tick = VtTickData()
        tick.symbol = subscribeReq.symbol
        tick.exchange = subscribeReq.exchange
        tick.vtSymbol = '.'.join([tick.symbol, tick.exchange])
        tick.gatewayName = self.gatewayName
        self.tickDict[self.tickerId] = tick
    
    #----------------------------------------------------------------------
    def sendOrder(self, orderReq):
        """发单"""
        # 增加报单号1,最后再次进行查询
        # 这里双重设计的目的是为了防止某些情况下,连续发单时,nextOrderId的回调推送速度慢导致没有更新
        self.orderId += 1
        
        # 创建合约对象
        contract = Contract()
        contract.m_symbol = str(orderReq.symbol)
        contract.m_exchange = exchangeMap.get(orderReq.exchange, '')
        contract.m_secType = productClassMap.get(orderReq.productClass, '')
        contract.m_currency = currencyMap.get(orderReq.currency, '')
        
        contract.m_expiry = orderReq.expiry
        contract.m_strike = orderReq.strikePrice
        contract.m_right = optionTypeMap.get(orderReq.optionType, '')
        
        # 创建委托对象
        order = Order()
        order.m_orderId = self.orderId
        order.m_clientId = self.clientId
        
        order.m_action = directionMap.get(orderReq.direction, '')
        order.m_lmtPrice = orderReq.price
        order.m_totalQuantity = orderReq.volume
        order.m_orderType = priceTypeMap.get(orderReq.priceType, '')
        
        # 发送委托
        self.connection.placeOrder(self.orderId, contract, order)
        
        # 查询下一个有效编号
        self.connection.reqIds(1)
    
    #----------------------------------------------------------------------
    def cancelOrder(self, cancelOrderReq):
        """撤单"""
        self.connection.cancelOrder(cancelOrderReq.orderID)
    
    #----------------------------------------------------------------------
    def qryAccount(self):
        """查询账户资金"""
        log = VtLogData()
        log.gatewayName = self.gatewayName        
        log.logContent = u'IB接口账户信息提供主推更新,无需查询'
        self.onLog(log) 
    
    #----------------------------------------------------------------------
    def qryPosition(self):
        """查询持仓"""
        log = VtLogData()
        log.gatewayName = self.gatewayName        
        log.logContent = u'IB接口持仓信息提供主推更新,无需查询'
        self.onLog(log) 
    
    #----------------------------------------------------------------------
    def close(self):
        """关闭"""
        self.connection.eDisconnect()
Пример #2
0
class IBBroker(BaseBroker):
    def __init__(self):
        basicConfig()
        # These two variables are initialized in Connect method
        self._connection = None
        self._wrapper = None
        self._request_id = 0

    def _get_next_request_id(self):
        self._request_id += 1
        return self._request_id

    def get_security(self, symbol):
        contract = IBSecurity()
        contract.Symbol = symbol
        contract.symbol_id = 0
        contract.Currency = 'USD'
        return contract

    def _get_next_valid_order_id(self):
        """
        You must assign a unique order ID to each order you place. IB's servers
        keep track of the next available order ID you can use; this function
        requests that value from IB's servers, waits until IB sends a response,
        then returns the ID.
        """
        last_time = self._wrapper._time_received_next_valid_order_id
        self._connection.reqIds(1)
        # Wait until IB sends the next valid ID
        while last_time == self._wrapper._time_received_next_valid_order_id:
            very_short_sleep()
        return self._wrapper._next_valid_order_id

    def _request_current_time(self):
        self._connection.reqCurrentTime()

    def connect(self):
        self._wrapper = ReferenceWrapper()
        self._connection = EClientSocket(self._wrapper)
        self._connection.eConnect(IB_HOST, IB_PORT, IB_CLIENT_ID)

    def disconnect(self):
        if self._connection.isConnected():
            self._connection.eDisconnect()

    def send_pre_trade(self, trade_info): # trade info is fa profile

        self._connection.requestFA(self._connection.PROFILES)
        self._connection.replaceFA(self._connection.PROFILES, trade_info)

    def send_order(self, order):
        order.__class__ = IBOrder # casting to IBOrder
        order.prepare_IB_order()
        order_id = self._get_next_valid_order_id()
        contract = self.get_security(order.Symbol)
        #order.m_transmit = True # forces IB to transmit order straight away
        self._connection.placeOrder(order_id, contract, order) # places order
        order.Status = Order.StatusChoice.Sent.value # order status is set to SENT
        order.Order_Id = order_id # sets broker specific ID
        while not self._wrapper.isOpeningOfOrdersFinished(order_id):
            err = self._wrapper.getError(order_id)
            if err is not None:
                raise Exception(err)
            very_short_sleep()
            #if(self._wrapper.isError(id)):
            #   raise Exception(self.wrapper.isError(id))

    def update_orders(self, orders):
        requestId = self._get_next_request_id()
        exf = ExecutionFilter()
        distribution = {}
        self._connection.reqExecutions(requestId, exf)  #
        while not self._wrapper.isExecutionRequestFinished(requestId):
            err = self._wrapper.getError(requestId)
            if err is not None:
                raise Exception(err)
            very_short_sleep()
        executions = self._wrapper.getExecutions(requestId)
        for order in orders:
            price = 0
            shares = 0
            if executions is not None:
                for execution in executions:
                    if execution.m_shares > 0 and execution.m_orderId == order.Order_Id and not execution.m_acctNumber.startswith('DF'):
                        price = execution.m_price
                        if order.Symbol not in distribution:
                            distribution[order.Symbol] = {}
                        if execution.m_acctNumber not in distribution[order.Symbol]:
                            distribution[order.Symbol][execution.m_acctNumber] = 0
                        distribution[order.Symbol][execution.m_acctNumber] += execution.m_shares
                        shares += execution.m_shares
                if price != 0:
                    order.setFills(price, shares)
        return distribution

    def get_account_info(self, broker_account):
        requestId = self._get_next_request_id()
        self._connection.reqAccountSummary(requestId, 'All', 'AccountType,TotalCashValue')
        while not self._wrapper.isExecutionRequestFinished(requestId):
            err = self._wrapper.getError(requestId)
            max_resp = self._wrapper.getMaxRequestFailureError()
            if err is not None:
                raise Exception(err)
            if max_resp:
                raise Exception("Maximum number of account summary requests exceeded")
            very_short_sleep()
        return self._wrapper.getAccountInfo(broker_account.ib_account)
Пример #3
0
    #                      --->   orderStatus**
    # reqAutoOpenOrders    --->   openOrder*
    #                      --->   orderStatus**
    # reqIds               --->   nextValidId           self.next_ValidId
    #                      --->   deltaNeutralValidation
    # exerciseOptions
    # reqGlobalCancel
    ###################################################################################'''
    print "Testing Orders Group \n"
    # Example 1 - placing order to buy stock
    tws.reqIds(1)  # Need to request next valid order Id
    time.sleep(2)  # wait for response from server
    order_id = callback.next_ValidId
    contract_info1 = create.create_contract('GOOG', 'STK', 'SMART', 'USD')
    order_info1 = create.create_order(accountName, 'MKT', 100, 'BUY')
    tws.placeOrder(order_id, contract_info1, order_info1)

    # Example 2 - placing order to buy FX
    tws.reqIds(1)
    time.sleep(1)
    order_id = callback.next_ValidId
    contract_info2 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD')
    order_info2 = create.create_order(accountName, 'MKT', 100000, 'BUY')
    tws.placeOrder(order_id, contract_info2, order_info2)

    #tws.cancelOrder(order_id)   # Cancel example 2 order
    #tws.reqOpenOrders()
    #tws.reqAllOpenOrders()
    #tws.reqAutoOpenOrders(1)    # clientId had to be 0 for this to work
    tws.reqGlobalCancel()
Пример #4
0
    elif (signal != 'n'):
        start_time2 = timeit.default_timer()
        # tws.reqIds(1)
        order_id = callback.next_ValidId + 1
        callback.next_ValidId = order_id

        # contract and order creation
        ctrct = ["ES", "FUT", "GLOBEX", "USD", '', '', '20170616', '50', "DU228380"]  #
        contract_info = create.create_contract(ctrct[0], ctrct[1], ctrct[2],
                                               ctrct[3], ctrct[4], ctrct[5], ctrct[6], ctrct[7])
        order_info = create.create_order(ctrct[8], o_type, qty, signal, price, True)
        print(o_type, qty, signal, price)
        # time.sleep(2)

        # place order
        tws.placeOrder(order_id, contract_info, order_info)

        # sleep for 5 seconds(discuss)
        time.sleep(3)
        # getting order confirmation###

        confirm = pd.DataFrame(callback.order_Status,
                               columns=['orderId', 'status', 'filled', 'remaining', 'avgFillPrice',
                                        'permId', 'parentId', 'lastFillPrice', 'clientId', 'whyHeld'])

        check = confirm.tail(1)
        filled = check.iloc[0]['filled']
        remain = check.iloc[0]['remaining']
        # filled=confirm.iloc[-1, :].filled
        # remain = confirm.iloc[-1, :].remaining
        # details to push into csv
Пример #5
0
class IBClient(object):
    """IB Socket client"""

    def __init__(self, client_name='IB', host='localhost', port=7496, client_id=0):
        """Constructor"""
        self.client_name = client_name
        self.host = host  # host IP address in a string; e.g. '127.0.0.1', 'localhost'
        self.port = port  # socket port; TWS default value: 7496; TWS demo account default value: 7497
        self.client_id = client_id  # socket client id

        self.connected = False  # status of the socket connection

        self.tickerId = 0  # known as ticker ID or request ID
        self.ipc_msg_dict = {}  # key: ticker ID or request ID; value: request and response objects; response objects ususally carrys data, Events, and Status
        self.order_id = 0  # current available order ID
        self.order_dict = {}  # key: ticker ID or request ID; value: request and response objects; response objects ususally carrys data, Events, and Status

        self.context = None  # key: ticker ID or request ID; value: request and response objects; response objects ususally carrys data, Events, and Status
        self.data = None

        self.wrapper = IBMsgWrapper(self)  # the instance with IB message callback methods
        self.connection = EClientSocket(self.wrapper)  # low layer socket client

        # TWS's data connection status
        self.hmdf_status_dict = {}
        for farm in IB_FARM_NAME_LS:
            self.hmdf_status_dict[farm] = 'unknown'

        # EVENTS
        self.conn_down_event = Event()  # sock connection event
        self.mdf_conn_event = Event()  # market data connection event
        self.hdf_conn_event = Event()  # hist data connection event

        self.order_event = Event()
        self.account_event = Event()
        self.get_order_event = Event()

        # LOCKER
        self.req_id_locker = threading.Lock()

        # CONSTANT VALUES
        self.PRICE_DF_HEADER1 = ['time', 'open', 'high', 'low', 'close', 'volume']
        self.PRICE_DF_HEADER2 = ['symbol', 'time', 'open', 'high', 'low', 'close', 'volume']

    def connect(self):
        """ Connect to socket host, e.g. TWS """
        self.connection.eConnect(self.host, self.port, self.client_id)

        timeout = 5.
        count = 0.
        while not self.connected and count < timeout:
            count += 0.05
            sleep(0.05)

        if self.connected:
            self.order_id = self.connection.reqIds(-1)
            if self.context is not None:
                # TODO: may need to move this to a thread or at user layer
                self.enable_account_info_update()
        else:
            print('failed to connect.')

        return self.connected

    def close(self):
        """ disconnect from IB host """
        self.disconnect()

    def disconnect(self):
        """ disconnect from IB host """
        if self.context is not None:
            self.disable_account_info_update()

        self.connection.eDisconnect()
        self.connected = False

    def register_strategy(self, context, data):
        """  TBA """
        self.context = context
        self.data = data

    def __get_new_request_id(self):
        '''' genew request ID (ticker ID) in a thread safe way '''
        self.req_id_locker.acquire()
        self.tickerId += 1
        __id = self.tickerId
        self.req_id_locker.release()
        return __id

    #
    # Tick Data Methods
    #
    def request_tick_data(self, contract):
        """ Subscribe tick data for a specified contract
        Args:
            contract: a legal IBPY Contract object or a string for U.S. stock only
        Returns:
            tickerId:  the ID of this request. this ID could be used to cancel request later.
            tick_data: a reference to the tick data dictionary which will be updated with latest quote.
        """
        if isinstance(contract, Contract):
            pass
        elif isinstance(contract, str):
            contract = new_stock_contract(contract)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        __id = self.__get_new_request_id()
        request = RequestDetails('reqMktData', 'Snapshot', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        # False - indicating request live quotes instead of a snapshot
        self.connection.reqMktData(__id, contract, '', False)

        return __id, self.ipc_msg_dict[__id][1].tick_data

    def get_tick_snapshot(self, contract, max_wait_time=5):
        """ Get a snapshot with default tick types and corresponding tick data for a given contract

        Note: 1) no generic ticks can be specified.
              2) only return data fields which have changed within an 11 second interval.
              If it is necessary for an API client to receive a certain data field, it is better
              to subscribe to market data until that field has been returned and then cancel the market data request.

        Known Issues:
              1) When called outside of market hours, get_tick_snapshot request could take more than 10 sec
                 to reach the end (tickSnapshotEnd)
              2) Need to check Issue#1 during market hours

        Args:
            contract: a legal IBPY Contract object or a string for U.S. stock only

        Returns:
            a copy of tick data dictionary
        Raises:
            None
        """
        if isinstance(contract, Contract):
            pass
        elif isinstance(contract, str):
            contract = new_stock_contract(contract)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        __id = self.__get_new_request_id()

        request = RequestDetails('reqMktData', 'Snapshot', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        # send reqMktData req
        # True - indicating request live quotes instead of a snapshot
        #
        # Important:
        # When set it to 'True', each regulatory snapshot made will incur a fee of 0.01 USD to the account.
        # This applies to both live and paper accounts.
        self.connection.reqMktData(__id, contract, '', True)

        response.event.wait(max_wait_time)
        if response.event.is_set():
            # tickPrice() and tickeSize() may write after tickSnapshotEnd() completed.
            sleep(0.5)
            snapshot = copy(response.tick_data)
            # remove the from dict and free the memory
            response.event.clear()
            self.ipc_msg_dict.pop(__id)
        else:
            response.event.clear()
            self.ipc_msg_dict.pop(__id)
            raise RuntimeError('reqMktData (get_tick_snapshot) is timeout. max_wait_time=%d' % (max_wait_time))

        return snapshot

    def cancel_tick_request(self, tickerId):
        """ Cancel tick data request for a given ticker ID (request ID)

        Args:
            tickerId: the ticker request to cancel
        Returns:
            None
        Raises:
            None
        """
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        # TODO: check if tickerID is in the list
        self.connection.cancelMktData(tickerId)
        self.ipc_msg_dict.pop(tickerId)
        return

    def request_realtime_price(self, contract, price_type='TRADES'):
        """ Get real-time price/volume for a specific contract, e.g. stocks, futures and option contracts.
            IB API support only 5 sec duration between two real-time bar (price) records.
        Args:
            contract: one IB contract instance
            price_type: 'TRADES', 'MIDPOINT', 'BID',  'ASK'
        Returns:
            tickerId: the request ID; it's also the key to get response msg from ipc_msg_dict
            realtime_price: a reference to the real-time price (OCHL) list which will be updated
                            with latest price (OCHL) record.
        Raises:
            None
        """
        if isinstance(contract, Contract):
            pass
        elif isinstance(contract, str):
            contract = new_stock_contract(contract)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if price_type not in ['TRADES', 'MIDPOINT', 'BID', 'ASK']:
            raise TypeError("Got incorrect price_type")

        __id = self.__get_new_request_id()
        request = RequestDetails('reqHistoricalData', price_type, contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)
        # only 5 sec duration supported
        # price_type: 'TRADES', 'MIDPOINT', 'BID',  'ASK'
        # useRTH - set to True
        self.connection.reqRealTimeBars(__id, contract, 5, price_type, True)

        return __id, self.ipc_msg_dict[__id][1].rt_price

    def cancel_realtime_price(self, req_id):
        """ Cancel realtime price/volumne request.
        Args:
            req_id: the ticker ID (or request ID)
        Returns:
            None
        """
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')
        self.connection.cancelRealTimeBars(req_id)

        # remove request/response data from ipc_msg_dict
        self.ipc_msg_dict.pop(req_id)
        return

    #
    # Historical Data Methods
    #
    def get_price_history(self, contract, ts_end, duration='1 M', frequency='daily', max_wait_time=30):
        """ Get price/volumne history for a specific contract, e.g. stocks, futures and option ocntract.

        Args:
            contract: one IB contract instance
            ts_end: a string in '%Y%m%d' or '%Y%m%d %H:%M:%S' format
            duration: string
                        X S	Seconds
                        X D	Day
                        X W	Week
                        X M	Month
                        X Y	Year
            frequency: {‘daily’, ‘minute’}, optional; Resolution of the data to be returned.
            max_wait_time: int; max num of sec to wait after calling reqHistoricalData
        Returns:
            pandas Panel/DataFrame/Series – The pricing data that was requested.

                            Open  High   Low  Close     Volume
                Date
                2017-12-15  6.96  6.96  6.86   6.90  366523000
                2017-12-18  6.88  7.02  6.87   6.98  303664000
                2017-12-19  7.00  7.02  6.98   7.01  299342000

        Raises:
            None

        """
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(contract, Contract):
            pass
        elif isinstance(contract, str):
            contract = new_stock_contract(contract)
        else:
            raise TypeError("contract must be a Contract object or string")

        if frequency == 'daily':
            bar_size = '1 day'
        elif frequency == 'minute':
            bar_size = '1 min'
        elif frequency == 'second':
            bar_size = '1 sec'
        elif frequency == '5 seconds':
            bar_size = '5 secs'
        else:
            raise ValueError("get_price_history: incorrect frequency value")

        if len(ts_end) == 8 or len(ts_end) == 17:
            if len(ts_end) == 8:
                ts_end = ts_end + ' 23:59:59'
        else:
            print('get_price_history: incorrect ts_end format')
            return

        __id = self.__get_new_request_id()
        request = RequestDetails('reqHistoricalData', '', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        self.connection.reqHistoricalData(tickerId=__id, contract=contract, endDateTime=ts_end, durationStr=duration,
                                          barSizeSetting=bar_size, whatToShow='TRADES', useRTH=0, formatDate=1)

        df = None
        response.event.wait(max_wait_time)
        if response.event.is_set():
            df = pd.DataFrame(response.price_hist, columns=self.PRICE_DF_HEADER1)
            # clean up the time format
            date = df['time'][0]

            if len(date) == 8:
                df['time'] = pd.to_datetime(df['time'], format='%Y%m%d')
            elif len(date) == 18:
                # len('20161020 23:46:00') --> 2 Spaces!!!!!
                # adj_date = datetime.strptime(date, "%Y%m%d  %H:%M:%S")
                df['time'] = pd.to_datetime(df['time'], format="%Y%m%d  %H:%M:%S")
            else:
                # adj_date = datetime.strptime(date, "%Y%m%d %H:%M:%S")
                df['time'] = pd.to_datetime(df['time'], format="%Y%m%d %H:%M:%S")

            # TODO: check for timezone
            # exchange = request.contract.m_exchange
            # server_timezone = pytz.timezone("Asia/Shanghai")  # timezone where the server runs
            # mkt_timezone = pytz.timezone(IBEXCHANGE.get_timezone(exchange))  # Get Exchange's timezone
            # adj_date = server_timezone.localize(adj_date).astimezone(
            #     mkt_timezone)  # covert server time to Exchange's time
            # adj_date = adj_date.strftime("%Y%m%d %H:%M:%S")  # from datetime to string

            df = df.set_index('time')
            # remove the from dict and free the memory
            response.event.clear()
            self.ipc_msg_dict.pop(__id)
        else:
            self.ipc_msg_dict.pop(__id)
            print('reqHistoricalData is timeout.')
            raise RuntimeError('reqHistoricalData is timeout.')

        return df

    def get_stock_price_history(self, security_list, ts_end, duration='1 M', frequency='daily', max_wait_time=30):
        """Get price/volumne history for a list of stocks.

        Args:
            security_list: a list of security symbols, .e.g. ['IBM', 'DATA']
            endDateTime: a string in '%Y%m%d' or '%Y%m%d %H:%M:%S' format
            durationStr: see IB API doc.
            frequency: {‘daily’, ‘minute’}, optional; Resolution of the data to be returned.
            max_wait_time: int; max num of sec to wait after calling reqHistoricalData
        Returns:
            pandas Panel/DataFrame/Series – The pricing data that was requested.
        Raises:
            None

        """
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        num_secs = len(security_list)
        if num_secs <= 0:
            return

        if frequency == 'daily':
            bar_size = '1 day'
        elif frequency == 'minute':
            bar_size = '1 min'
        elif frequency == 'second':
            bar_size = '1 sec'
        elif frequency == '5 seconds':
            bar_size = '5 secs'
        else:
            print('get_stock_price_history: incorrect frequency')
            return

        if len(ts_end) == 8 or len(ts_end) == 17:
            if len(ts_end) == 8:
                ts_end = ts_end + ' 23:59:59'
        else:
            print('get_stock_price_history: incorrect ts_end format')
            return

        # ['Symbol', 'Date', 'Open', 'High', 'Low', 'Close', 'Volume']
        df = pd.DataFrame(columns=self.PRICE_DF_HEADER2)
        for sec in security_list:

            __id = self.__get_new_request_id()

            contract = new_stock_contract(sec)
            request = RequestDetails('reqHistoricalData', '', contract)
            response = ResponseDetails()
            self.ipc_msg_dict[__id] = (request, response)

            self.connection.reqHistoricalData(tickerId=__id, contract=contract, endDateTime=ts_end,
                                              durationStr=duration, barSizeSetting=bar_size, whatToShow='TRADES',
                                              useRTH=0, formatDate=1)

            response.event.wait(max_wait_time)
            if response.event.is_set():

                df_tmp = pd.DataFrame(response.price_hist, columns=self.PRICE_DF_HEADER1)
                # clean up the time format
                date = df_tmp['time'][0]

                if len(date) == 8:
                    df_tmp['time'] = pd.to_datetime(df_tmp['time'], format='%Y%m%d')
                elif len(date) == 18:
                    # len('20161020 23:46:00') --> 2 Spaces!!!!!
                    # adj_date = datetime.strptime(date, "%Y%m%d  %H:%M:%S")
                    df_tmp['time'] = pd.to_datetime(df_tmp['time'], format="%Y%m%d  %H:%M:%S")
                else:
                    # adj_date = datetime.strptime(date, "%Y%m%d %H:%M:%S")
                    df_tmp['time'] = pd.to_datetime(df_tmp['time'], format="%Y%m%d %H:%M:%S")

                # TODO: check for timezone
                # exchange = request.contract.m_exchange
                # server_timezone = pytz.timezone("Asia/Shanghai")  # timezone where the server runs
                # mkt_timezone = pytz.timezone(IBEXCHANGE.get_timezone(exchange))  # Get Exchange's timezone
                # adj_date = server_timezone.localize(adj_date).astimezone(
                #     mkt_timezone)  # covert server time to Exchange's time
                # adj_date = adj_date.strftime("%Y%m%d %H:%M:%S")  # from datetime to string

                df_tmp['symbol'] = pd.DataFrame([sec] * len(df_tmp))
                df = df.append(df_tmp)
                # remove the from dict and free the memory
                self.ipc_msg_dict.pop(__id)
                response.event.clear()

            else:
                self.ipc_msg_dict.pop(__id)
                raise RuntimeError('reqHistoricalData is timeout.')

        return df

    def get_contract_price_history(self, contract, ts_end, duration='1 M', frequency='daily', max_wait_time=30):
        # Same function as get_price_history
        return self.get_price_history(self, contract, ts_end, duration, frequency, max_wait_time)

    #
    # Placing/Changing/Canceling Order Methods
    #
    def order_amount(self, contract, amount, style=MarketOrder()):
        ''' Place an order. Order X units of security Y.
            Warning: only mkt order and limited order work; calling stoploss/stoplimited order will result in IB disconnection.
        :param contract: A IB Contract object.
        :param amount: The integer amount of shares. Positive means buy, negative means sell.
        :param style:
        :return:
        '''
        if amount == 0:
            return -1
        elif amount > 0:
            action = 'BUY'
        else:
            action = 'SELL'

        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if not isinstance(contract, Contract):
            raise TypeError("contract must be a contract object")
        # request next valid order ID from IB host; this request will update self.order_id
        self.connection.reqIds(-1)  # note: input param is always ignored;
        sleep(0.05)

        order = Order()
        order.m_orderId = self.order_id
        order.m_client_id = self.client_id
        order.m_action = action
        order.m_totalQuantity = abs(amount)
        order.m_orderType = style.order_type
        if style.limit_price is not None:
            order.m_lmtPrice = style.limit_price
        if style.stop_price is not None:
            order.m_auxPrice = style.stop_price
        order.m_overridePercentageConstraints = True  # override TWS order size constraints

        # place order
        self.connection.placeOrder(self.order_id, contract, order)
        # TODO: wait for returns from orderStatus
        return self.order_id

    def combo_order_amount(self, contract, amount, style=MarketOrder()):
        ''' Place an order

        :param contract: A security object.
        :param amount: The integer amount of shares. Positive means buy, negative means sell.
        :param style:
        :return:
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if amount == 0:
            return -1
        elif amount > 0:
            action = 'BUY'
        else:
            action = 'SELL'

        if isinstance(contract, Contract):
            if len(contract.m_comboLegs) == 0:
                raise TypeError("contract must contains combo legs")
        else:
            raise TypeError("contract must be a contract object")

        # request next valid order ID from IB host; this request will update self.order_id
        self.connection.reqIds(-1)  # note: input param is always ignored;
        sleep(0.05)

        order = Order()
        order.m_orderId = self.order_id
        order.m_client_id = self.client_id
        order.m_action = action
        order.m_totalQuantity = abs(amount)
        order.m_orderType = style.order_type
        if style.limit_price is not None:
            order.m_lmtPrice = style.limit_price
        if style.stop_price is not None:
            order.m_auxPrice = style.stop_price

        order.m_overridePercentageConstraints = True  # override TWS order size constraints
        '''
        # Advanced configuration. Not tested yet.
        if style.is_combo_order:
            if style.non_guaranteed:
                tag = TagValue()
                tag.m_tag = "NonGuaranteed"
                tag.m_value = "1"
                order.m_smartComboRoutingParams = [tag]
        '''
        self.connection.placeOrder(self.order_id, contract, order)
        return self.order_id

    def order_value(self, contract, value, style):
        ''' Reserve for future implementation

        :param contract:
        :param value:
        :param style:
        :return:
        '''
        pass

    def order_target(self, contract, amount, style):
        ''' Places an order to adjust a position to a target number of shares.

        :param contract:
        :param value:
        :param style:
        :return:
        '''
        pass

    def order_target_value(self, contract, amount, style):
        ''' Places an order to adjust a position to a target value.

        :param contract:
        :param value:
        :param style:
        :return:
        '''
        pass

    def modify_order(self, order_id, contract, amount, style=MarketOrder()):
        ''' Change amount or order type (including limited price for limtied orders)
            for a existing order specified by order_id
        
        :param order_id: a existing order's order_id
        :param contract: A IB Contract object. supposed to be the same with the order-to-be-modified.
        :param amount: The integer amount of shares. Positive means buy, negative means sell.
        :param style: market order or limited order
        :return: the existing order's order_id (same as the input)
        '''

        if amount == 0:
            return -1
        elif amount > 0:
            action = 'BUY'
        else:
            action = 'SELL'

        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if not isinstance(contract, Contract):
            raise TypeError("contract must be a contract object")

        order = Order()
        order.m_orderId = order_id
        order.m_client_id = self.client_id
        order.m_action = action
        order.m_totalQuantity = abs(amount)
        order.m_orderType = style.order_type
        if style.limit_price is not None:
            order.m_lmtPrice = style.limit_price
        if style.stop_price is not None:
            order.m_auxPrice = style.stop_price
        order.m_overridePercentageConstraints = True  # override TWS order size constraints

        # place order
        self.connection.placeOrder(self.order_id, contract, order)
        # TODO: wait for returns from orderStatus
        return self.order_id

    def cancel_order(self, order):
        ''' Attempts to cancel the specified order. Cancel is attempted asynchronously.

        :param order: Can be the order_id as a string or the order object.
        :return: None
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(order, int):
            order_id = order
        elif isinstance(order, Order):
            order_id = order.m_orderId
        else:
            raise TypeError("order must be a order_id (int) or order object")
        self.connection.cancelOrder(order_id)

    def get_open_orders(self):
        ''' Attempts to get all open orders.

        :param
        :return: None
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if 'reqOpenOrders' not in self.ipc_msg_dict:
            request = RequestDetails('reqOpenOrders', '', '')
            response = ResponseDetails()
            self.ipc_msg_dict['reqOpenOrders'] = (request, response)
        else:
            response = self.ipc_msg_dict['reqOpenOrders'][1]

        # self.connection.reqOpenOrders()
        # self.reqAutoOpenOrders(True)
        self.connection.reqAllOpenOrders()

        max_wait_time = 3.
        self.get_order_event.wait(max_wait_time)
        if self.get_order_event.is_set():
            # snapshot = copy(response.tick_snapshot)
            # self.ipc_msg_dict.pop(self.tickerId)
            self.get_order_event.clear()
        else:
            # self.ipc_msg_dict.pop(self.tickerId)
            raise RuntimeError('get_open_orders is timeout.')

        return

    #
    # Account Info Methods
    #
    def enable_account_info_update(self):
        ''' Turn on auto account update, meaning IB socket host will push account info to IB socket client.
                updateAccountTime()
                updateAccountValue()
                updatePortfolio()
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        # TODO: check self.IB_acct_id before using it
        # request IB host (e.g. TWS) push account info to IB client (socket client)
        self.connection.reqAccountUpdates(True, self.context.account.account_id)
        return

    def disable_account_info_update(self):
        ''' Turn off auto account update, meaning IB socket host will stop pushing account info
         to IB socket client.
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        # TODO: check self.IB_acct_id before using it
        # stop IB host (e.g. TWS) to push account info to IB client (socket client)
        self.connection.reqAccountUpdates(False, self.context.account.account_id)
        return

    #
    # Fundamental Data Methods
    #
    def get_financial_statements(self, symbol, max_wait_time=20):
        ''' Get a company's financial statements

        :param:
            symbol: stock symbol string, e.g. 'IBM'; or a IB contract object
        :return:
            a string of financial statements
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(symbol, Contract):
            contract = symbol
        elif isinstance(symbol, str):
            contract = new_stock_contract(symbol)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        __id = self.__get_new_request_id()

        request = RequestDetails('reqFundamentalData', 'ReportsFinStatements', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        self.connection.reqFundamentalData(__id, contract, 'ReportsFinStatements')

        response.event.wait(max_wait_time)
        raw_xml = None
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                # covert from xml to dest. format
                raw_xml = copy(response.fundamental_data)
            else:
                pass  # raise RuntimeError('get_financial_statements: reqFundamentalData got error. Security=%s Reason:%s' % (symbol, response.error_msg))
        else:
            # Timeout
            pass  # ('get_financial_statements: reqFundamentalData is timeout. Security=%s' % symbol)

        status = response.status
        self.ipc_msg_dict.pop(__id)
        return status, raw_xml

    def get_company_ownership(self, symbol, max_wait_time=60.0 * 5):
        ''' Get a company's ownership report

        :param:
            symbol: stock symbol string, e.g. 'IBM'
            max_wait_time: max number of seconds to wait before raise timeout
        :return:
            a string of ownership report
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(symbol, Contract):
            contract = symbol
        elif isinstance(symbol, str):
            # For US stock only
            contract = new_stock_contract(symbol)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        __id = self.__get_new_request_id()

        request = RequestDetails('reqFundamentalData', 'ReportsOwnership', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        self.connection.reqFundamentalData(__id, contract, 'ReportsOwnership')

        response.event.wait(max_wait_time)
        report = None
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                # covert from xml to dest. format
                report = parse_ownership_report(response.fundamental_data)
            else:
                pass  # ('get_company_ownership: reqFundamentalData got error. Security=%s Reason:%s' % (symbol, response.error_msg))
        else:
            pass  # ('get_company_ownership: reqFundamentalData is timeout. Security=%s' % symbol)

        status = response.status
        self.ipc_msg_dict.pop(__id)
        return status, report

    def get_analyst_estimates(self, symbol, max_wait_time=20):
        ''' Get analyst estimates report for a company

        :param:
            symbol: stock symbol string, e.g. 'IBM'; or a IB contract object
        :return:
            a string of financial statements
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(symbol, Contract):
            contract = symbol
        elif isinstance(symbol, str):
            contract = new_stock_contract(symbol)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        __id = self.__get_new_request_id()

        request = RequestDetails('reqFundamentalData', 'RESC-Analyst Estimates', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        self.connection.reqFundamentalData(__id, contract, 'RESC')

        response.event.wait(max_wait_time)
        report = None
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                # covert from xml to dest. format
                report = parse_analyst_estimates(response.fundamental_data)
            else:
                pass  # ('get_analyst_estimates: reqFundamentalData got error. Security=%s Reason:%s' % (symbol, response.error_msg))
        else:
            pass  # ('get_analyst_estimates: reqFundamentalData is timeout. Security=%s' % symbol)

        status = response.status
        self.ipc_msg_dict.pop(__id)
        return status, report

    def get_company_overview(self, symbol, max_wait_time=10):
        ''' Get company overview infomration

        :param:
            symbol: stock symbol string, e.g. 'IBM'; or a IB contract object
        :return:
            a string of financial statements
        '''
        # ReportsFinSummary	Financial summary

        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(symbol, Contract):
            contract = symbol
        elif isinstance(symbol, str):
            contract = new_stock_contract(symbol)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        __id = self.__get_new_request_id()

        request = RequestDetails('reqFundamentalData', 'ReportSnapshot-Company overview', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        # ReportSnapshot	Company's financial overview
        self.connection.reqFundamentalData(__id, contract, 'ReportSnapshot')

        response.event.wait(max_wait_time)
        report = None
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                # TODO: covert from xml to dest. format
                report = response.fundamental_data
            else:
                pass  # ('get_analyst_estimates: reqFundamentalData got error. Security=%s Reason:%s' % (symbol, response.error_msg))
        else:
            pass  # ('get_analyst_estimates: reqFundamentalData is timeout. Security=%s' % symbol)

        status = response.status
        self.ipc_msg_dict.pop(__id)
        return status, report

    def get_financial_summary(self, symbol, max_wait_time=10):
        ''' Get company finanical summary information, such as revenue history, net profit, and dividends history.

        :param:
            symbol: stock symbol string, e.g. 'IBM'; or a IB contract object
        :return:
            a string of financial statements
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(symbol, Contract):
            contract = symbol
        elif isinstance(symbol, str):
            contract = new_stock_contract(symbol)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        __id = self.__get_new_request_id()

        request = RequestDetails('reqFundamentalData', 'ReportsFinSummary-Financial summary', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        self.connection.reqFundamentalData(__id, contract, 'ReportsFinSummary')

        response.event.wait(max_wait_time)
        report = None
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                # TODO: covert from xml to dest. format
                report = response.fundamental_data
            else:
                pass
        else:
            pass

        status = response.status
        self.ipc_msg_dict.pop(__id)
        return status, report

    def get_financial_ratios(self, symbol, max_wait_time=5):
        ''' Get analyst estimates report for a company

        :param:
            symbol: stock symbol string, e.g. 'IBM'
        :return:
            a string of financial statements
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(symbol, Contract):
            contract = symbol
        elif isinstance(symbol, str):
            contract = new_stock_contract(symbol)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        __id = self.__get_new_request_id()

        request = RequestDetails('reqFundamentalData', 'RESC-Analyst Estimates', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        # 258 - financial ratios
        '''
            TTMNPMGN=16.1298;NLOW=80.6;TTMPRCFPS=6.26675;TTMGROSMGN=60.76731;TTMCFSHR=15.004
            46;QCURRATIO=1.42071;TTMREV=259842;TTMINVTURN=5.28024;TTMOPMGN=14.22711;TTMPR2RE
            V=1.39703;AEPSNORM=8.55;TTMNIPEREM=144524.1;EPSCHNGYR=8.47727;TTMPRFCFPS=62.4260
            6;TTMRECTURN=19.99938;TTMPTMGN=17.88125;QCSHPS=40.50882;TTMFCF=5815;
            LATESTADATE=2016-12-31;APTMGNPCT=17.88125;AEBTNORM=46463;TTMNIAC=33008;NetDebt_I=152080;
            PRYTDPCTR=-1.55563;TTMEBITD=53326;AFEEPSNTM=0;PR2TANBK=5.01599;EPSTRENDGR=-
            15.53209;QTOTD2EQ=72.60778;TTMFCFSHR=1.50625;QBVPS=110.0867;NPRICE=94.1;YLD5YAVG
            =3.88751;REVTRENDGR=51.11774;TTMEPSXCLX=8.54981;QTANBVPS=18.75999;PRICE2BK=0.854
            78;MKTCAP=363007.5;TTMPAYRAT=31.32574;TTMINTCOV=-99999.99;TTMDIVSHR=2.585;TTMREVCHG=55.81794;
            TTMROAPCT=4.09615;TTMROEPCT=7.73685;
            TTMREVPERE=896006.9;APENORM=11.00585;TTMROIPCT=5.51924;REVCHNGYR=-
            6.66885;CURRENCY=HKD;DIVGRPCT=-8.33887;TTMEPSCHG=-32.80548;PEEXCLXOR=11.00609;QQUICKRATI=1.30087;
            TTMREVPS=67.30638;BETA=0.90979;TTMEBT=46463;ADIV5YAVG=3.1048;ANIACNORM=33008;QLTD2EQ=55.46377;NHIG=103.9
        '''
        report = None
        self.connection.reqMktData(__id, contract, "258", False)
        response.event.wait(max_wait_time)
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                # TODO: convert the format to a table alike
                report = response.tick_str

        return report

    def get_dividends_info(self, symbol, max_wait_time=5):
        ''' Get analyst estimates report for a company

        :param:
            symbol: stock symbol string, e.g. 'IBM'
        :return:
            a string of financial statements
        '''
        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        if isinstance(symbol, Contract):
            contract = symbol
        elif isinstance(symbol, str):
            contract = new_stock_contract(symbol)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        __id = self.__get_new_request_id()
        request = RequestDetails('reqFundamentalData', 'RESC-Analyst Estimates', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        # IB Dividends ("456")
        #
        # This tick type provides four different comma-separated elements:
        # The sum of dividends for the past 12 months (0.83 in the example below).
        # The sum of dividends for the next 12 months (0.92 from the example below).
        # The next dividend date (20130219 in the example below).
        # The next single dividend amount (0.23 from the example below).
        # Example: 0.83,0.92,20130219,0.23
        self.connection.reqMktData(__id, contract, "456", False)
        result = None
        response.event.wait(max_wait_time)
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                # TODO: convert the format
                result = set(response.tick_str.split(','))

        self.ipc_msg_dict.pop(__id)

        return result

    def get_contract_details(self, contract, max_wait_time=5):
        """ Get contract details for a specified contract
        Args:
            contract: a legal IBPY Contract object or a string for U.S. stock only
        Returns:
            status: a reference to the tick data dictionary which will be updated with latest quote.
            contract_details: a contractDetails instance
        """
        if isinstance(contract, Contract):
            pass
        elif isinstance(contract, str):
            contract = new_stock_contract(contract)
        else:
            raise TypeError("contract must be a contract object or string (for U.S. stocks only).")

        if not self.connected:
            raise RuntimeError('IB client is not connected to TWS')

        __id = self.__get_new_request_id()
        request = RequestDetails('reqContractDetails', '', contract)
        response = ResponseDetails()
        self.ipc_msg_dict[__id] = (request, response)

        # False - indicating request live quotes instead of a snapshot
        self.connection.reqContractDetails(__id, contract)

        response.event.wait(max_wait_time)
        contract_details = None
        if response.event.is_set():
            if response.status == ResponseDetails.STATUS_FINISHED:
                if len(response.contract_list) > 0:
                    contract_details = copy(response.contract_list[0])
            else:
                pass
        else:
            pass

        status = response.status
        self.ipc_msg_dict.pop(__id)

        return status, contract_details

    def get_full_contract(self, contract):
        """ Subscribe tick data for a specified contract
        Args:
            contract: a legal IBPY Contract object or a string for U.S. stock only
        Returns:
            tickerId:  the ID of this request. this ID could be used to cancel request later.
            tick_data: a reference to the tick data dictionary which will be updated with latest quote.
        """

        status, contract_details = self.get_contract_details(contract)
        new_contract = copy(contract_details.m_summary)

        return status, new_contract
Пример #6
0
                                         False, False, None, None, None, None,
                                         None, None)
        tws.placeOrder(int(i), contract_info, order_info)
        time.sleep(0.2)

    loops = 1
    # exitidlist = generateNumber(loops)
    #
    # while exitidlist[0] == buyidlist[0]:
    #     exitidlist = generateNumber(loops)
    #
    # for i in exitidlist:
    #     order_info = create.create_order(acc, "LMT", 10000, exit_signal, 10.000, False, False, None)
    #     tws.placeOrder(int(i), contract_info, order_info)

    return sellidlist, buyidlist


conn()
id_list = [[0], [0]]
curr = 'NOK.SEK'
contract = create.create_contract(curr[0:3], "CASH", "IDEALPRO", curr[4:7], '',
                                  '', '', '')
idlist = orderidfun(acc, contract, type, id_list, 2)
rt_price = ask_bid(contract, 2000)

order_info = create.create_order(acc, "LMT", 10000, "BUY", float(rt_price[0]),
                                 True, 'GTC', None, None, None, None, None,
                                 None)
tws.placeOrder(int(id_list[1][0]), contract, order_info)
Пример #7
0
    mylist = []
    for i in range(num):
        mylist.append(order_id)
        order_id = order_id + 1
    return mylist


conn()
order_id = generateNumber(2)
contract_info = contract1("AUD", "CASH", "IDEALPRO", "NZD", "", "", "", "")
#order_info = create.create_order(acc, "LMT", 10000, "BUY", 10.000, False, False, None,0,0)
# 22% price #         # 15% price#
order_info = create.create_order(acc, "TRAIL LIMIT", 10000, "SELL", 1.0930,
                                 True, False, None, 1.09270, 0.001, True, 0.0)
#trail perc #
tws.placeOrder(int(order_id[0]), contract_info, order_info)

# order_info = create.create_order(acc, "TRAIL LIMIT", 10000, "SELL", "0.01", True, False, None,0,0,0.02)
# tws.placeOrder(int(order_id[1]), contract_info, order_info)

conn()
order_id = generateNumber(2)
# 22% price #         # 15% price#
order_info = create.create_order(acc, "LMT", 10000, "SELL", 1.0930, True,
                                 False, None, "", "", True, "")
tws.placeOrder(int(order_id[0]), contract_info, order_info)  #trail perc #

order_info = create.create_order(acc, "TRAIL LIMIT", 10000, "SELL", 1.0930,
                                 True, False, None, 1.09270, 0.001, True, 0.0)
#trail perc #
tws.placeOrder(int(order_id[0]), contract_info, order_info)
Пример #8
0
	data = obtain_hist_data(tws, callback)


	short_SMA, long_SMA = SMA(data, 5, 10)
	print("short_SMA {}, long_SMA {}".format(short_SMA, long_SMA))

	# trading decision
	# ideally we need a check to see if we already have a position. 
	# Else we keep sending a buy 
	if short_SMA > long_SMA:
		pos = check_existing_pos()
		print(pos)
		if not pos:
			print("[INFO] order placing...")
			tws.reqIds(1)
			order_id = callback.next_ValidId + 1
			# placing order
			order_info = create.create_order(accountName, "MKT", 250, "BUY")
			tws.placeOrder(order_id, contract_Details, order_info)
			time.sleep(2)
			order_status_update = pd.DataFrame(callback.order_Status,
				columns = ['orderId', 'status', 'filled', 'remaining', 'avgFillPrice',
				'permId', 'parentId', 'lastFillPrice', 'clientId', 'whyHeld'])
			# if the order is filled, it should be picked up by the 
			# check_existing_pos function. The place order should not
			# be fired.

# disconnnet
tws.eDisconnect()

Пример #9
0
class Bot(object):

    def __init__(self, host, port, strategies, instruments, logger):

        self.msgs = queue.Queue()
        self.book_builder = BookBuilder()

        # strategies
        self.instruments = instruments
        self.contracts = dict()
        self.strategies = []
        for strategy in strategies:
            strat = Recoil2(strategy['watch_threshold'],
                            strategy['watch_duration'],
                            strategy['slowdown_threshold'],
                            strategy['slowdown_duration'])
            self.strategies.append(strat)

        # operations
        self.host = host
        self.port = port
        self.connection = EClientSocket(Connector(self.instruments, self.msgs))
        self.next_id = None
        self.log = logger

    def connect(self):
        template = 'Attempting to connect host: {} port: {}...'
        self.log.operation(template.format(self.host, self.port))
        self.connection.eConnect(self.host, self.port, 0)
        self.log.operation('Connected.')

    def disconnect(self):
        self.log.operation('Disconnecting...')
        self.connection.eDisconnect()
        self.log.operation('Disconnected.')

    def request_data(self):
        for ticker_id, instrument in self.instruments.items():
            contract = Contract()
            contract.m_symbol = instrument['symbol']
            contract.m_currency = instrument['currency']
            contract.m_secType = instrument['secType']
            contract.m_exchange = instrument['exchange']
            self.contracts[instrument['symbol']] = contract
            self.connection.reqMktData(ticker_id, contract, '', False)

    def run(self):
        while True:
            msg = self.msgs.get()
            self.log.raw(msg)

            if msg['type'] == 'nextValidId':
                self.log.order({'msg': 'new order ID', 'orderId': msg['orderId']})
                self.next_id = msg['orderId']
                continue

            tick = self.book_builder.process_raw_tick(msg)

            if not tick:
                continue

            self.log.data(tick)

            for strategy in self.strategies:
                signal = strategy.handle_tick(tick)

                if not signal:
                    continue

                self.log.order(signal)
                order = strategy.place_order(signal)

                if not order:
                    continue

                c = self.contracts[signal['symbol']]
                self.log.order({'symbol': signal['symbol'],
                                'qty': order.m_totalQuantity,
                                'type': order.m_orderType,
                                'goodTill': order.m_goodTillDate,
                                'px': order.m_lmtPrice,
                                'action': order.m_action})
                self.connection.placeOrder(id=self.next_id, contract=c,
                                           order=order)
                self.next_id += 1
Пример #10
0
class IBClient(object):
    fields = {'trades': 'TRADES',
              'midpoint': 'MIDPOINT',
              'bid': 'BID',
              'ask': 'ASK',
              'bid_ask': 'BID_ASK',
              'hist_vol': 'HISTORICAL_VOLATILITY',
              'imp_vol': 'OPTION_IMPLIED_VOLATILITY'}

    def __init__(self, name=None, call_msg=True, host=None, port=None, client_id=None):
        self.name = name
        self.host = host
        self.port = port
        self.client_id = client_id
        self.ref_nums = [0]
        self.wrapper = SyncWrapper()
        self.connection = EClientSocket(self.wrapper)
        self.account = self.wrapper.account
        self.contracts = self.wrapper.contracts
        self.executions_ = self.wrapper.executions
        self.order_messages = self.wrapper.order_messages

        if self.host is None:
            self.host = 'localhost'
        if self.port is None:
            self.port = 7496
        if call_msg is False:
            self.wrapper.suppress = True
        if self.client_id is None:
            self.client_id = 0

        # listen to execution
        #self.wrapper.register(self.method, events='execution')
        self.__connect__ = self.connection.eConnect(self.host, self.port, self.client_id)
        self.__gen_order_id__(1)
        sleep(.2)


    def request_reference_id(self, integer=False):
        if not integer:
            ref_id = uuid.uuid4().hex
            if ref_id in self.ref_nums:
                return self.request_reference()
            else:
                self.ref_nums.append(ref_id)
                return ref_id
        else:
            ref_id = '{0:09d}'.format(np.random.randint(0, 999999999))
            if ref_id > max([x for x in self.ref_nums if type(x) is int]):
                return int(ref_id)
            else:
                return self.request_reference(integer=True)

    def __gen_order_id__(self, num):
        self.connection.reqIds(num)
        return self.wrapper.order_id


    def method(self, sender, event, msg=None):
        print "[{0}] got event {1} with message {2}".format(self.name, event, msg)

    def __track_orders__(self):
        self.connection.reqAutoOpenOrders(1)

    def managed_accounts(self):
        if self.account.child_accounts:
            return self.account.child_accounts
        else:
            self.connection.reqManagedAccts()
            sleep(1)
            if self.account.child_accounts:
                return self.account.child_accounts
            return ['REQUEST FAILED']

    def account_updates(self, acct):
        #get a unique id
        reference = self.request_reference_id()

        #append a new packet container to account
        self.account.append_request(reference, AccountPacket(acct), PortfolioPacket(acct))
        self.wrapper.ref_id = reference
        self.connection.reqAccountUpdates(1, acct)
        sleep(1)
        return reference

    def place_order(self, contract, order):
        self.wrapper.order_id += 100
        ref = self.wrapper.order_id
        self.connection.placeOrder(ref, contract, order)
        sleep(.2)
        return ref

    def cancel_order(self, id):
        self.connection.cancelOrder(id)

    def get_executions(self, efilter=None):
        if not efilter:
            efilter = ExecutionFilter()
        ref = self.request_reference_id(integer=True)
        self.connection.reqExecutions(reqId=ref, filter=efilter)
        sleep(3)  # Todo: This is a ridiculous bottleneck
        return ref

    def get_contract(self, contract):
        ref = self.request_reference_id(integer=True)
        self.connection.reqContractDetails(ref, contract)
        sleep(1)
        return ref

    def portfolio(self, account):
        ref = self.account_updates(account)
        return self.account[ref]['portfolio'].messages

    def account_details(self, account):
        ref = self.account_updates(account)
        return self.account[ref]['account'].messages

    def executions(self, efilter=None):
        ref = self.get_executions(efilter)
        return self.executions_[ref]

    def order_status(self, order_id):
        sleep(.2)
        return [msg for msg in self.order_messages if msg['orderId'] == order_id]

    def disconnect(self):
        self.connection.eDisconnect()
Пример #11
0
class IBClient(object):
    fields = {
        'trades': 'TRADES',
        'midpoint': 'MIDPOINT',
        'bid': 'BID',
        'ask': 'ASK',
        'bid_ask': 'BID_ASK',
        'hist_vol': 'HISTORICAL_VOLATILITY',
        'imp_vol': 'OPTION_IMPLIED_VOLATILITY'
    }

    def __init__(self,
                 name=None,
                 call_msg=True,
                 host=None,
                 port=None,
                 client_id=None):
        self.name = name
        self.host = host
        self.port = port
        self.client_id = client_id
        self.ref_nums = [0]
        self.wrapper = SyncWrapper()
        self.connection = EClientSocket(self.wrapper)
        self.account = self.wrapper.account
        self.contracts = self.wrapper.contracts
        self.executions_ = self.wrapper.executions
        self.order_messages = self.wrapper.order_messages

        if self.host is None:
            self.host = 'localhost'
        if self.port is None:
            self.port = 7496
        if call_msg is False:
            self.wrapper.suppress = True
        if self.client_id is None:
            self.client_id = 0

        # listen to execution
        #self.wrapper.register(self.method, events='execution')
        self.__connect__ = self.connection.eConnect(self.host, self.port,
                                                    self.client_id)
        self.__gen_order_id__(1)
        sleep(.2)

    def request_reference_id(self, integer=False):
        if not integer:
            ref_id = uuid.uuid4().hex
            if ref_id in self.ref_nums:
                return self.request_reference()
            else:
                self.ref_nums.append(ref_id)
                return ref_id
        else:
            ref_id = '{0:09d}'.format(np.random.randint(0, 999999999))
            if ref_id > max([x for x in self.ref_nums if type(x) is int]):
                return int(ref_id)
            else:
                return self.request_reference(integer=True)

    def __gen_order_id__(self, num):
        self.connection.reqIds(num)
        return self.wrapper.order_id

    def method(self, sender, event, msg=None):
        print "[{0}] got event {1} with message {2}".format(
            self.name, event, msg)

    def __track_orders__(self):
        self.connection.reqAutoOpenOrders(1)

    def managed_accounts(self):
        if self.account.child_accounts:
            return self.account.child_accounts
        else:
            self.connection.reqManagedAccts()
            sleep(1)
            if self.account.child_accounts:
                return self.account.child_accounts
            return ['REQUEST FAILED']

    def account_updates(self, acct):
        #get a unique id
        reference = self.request_reference_id()

        #append a new packet container to account
        self.account.append_request(reference, AccountPacket(acct),
                                    PortfolioPacket(acct))
        self.wrapper.ref_id = reference
        self.connection.reqAccountUpdates(1, acct)
        sleep(1)
        return reference

    def place_order(self, contract, order):
        self.wrapper.order_id += 100
        ref = self.wrapper.order_id
        self.connection.placeOrder(ref, contract, order)
        sleep(.2)
        return ref

    def cancel_order(self, id):
        self.connection.cancelOrder(id)

    def get_executions(self, efilter=None):
        if not efilter:
            efilter = ExecutionFilter()
        ref = self.request_reference_id(integer=True)
        self.connection.reqExecutions(reqId=ref, filter=efilter)
        sleep(3)  # Todo: This is a ridiculous bottleneck
        return ref

    def get_contract(self, contract):
        ref = self.request_reference_id(integer=True)
        self.connection.reqContractDetails(ref, contract)
        sleep(1)
        return ref

    def portfolio(self, account):
        ref = self.account_updates(account)
        return self.account[ref]['portfolio'].messages

    def account_details(self, account):
        ref = self.account_updates(account)
        return self.account[ref]['account'].messages

    def executions(self, efilter=None):
        ref = self.get_executions(efilter)
        return self.executions_[ref]

    def order_status(self, order_id):
        sleep(.2)
        return [
            msg for msg in self.order_messages if msg['orderId'] == order_id
        ]

    def disconnect(self):
        self.connection.eDisconnect()
Пример #12
0
    #                      --->   orderStatus**
    # reqAutoOpenOrders    --->   openOrder*
    #                      --->   orderStatus**
    # reqIds               --->   nextValidId           self.next_ValidId
    #                      --->   deltaNeutralValidation
    # exerciseOptions   
    # reqGlobalCancel
    ###################################################################################'''
    print "Testing Orders Group \n"
    # Example 1 - placing order to buy stock
    tws.reqIds(1)   # Need to request next valid order Id
    time.sleep(2)   # wait for response from server
    order_id = callback.next_ValidId
    contract_info1 = create.create_contract('GOOG', 'STK', 'SMART', 'USD')
    order_info1 = create.create_order(accountName, 'MKT', 100, 'BUY')
    tws.placeOrder(order_id, contract_info1, order_info1)
    
    # Example 2 - placing order to buy FX
    tws.reqIds(1)
    time.sleep(1)
    order_id = callback.next_ValidId
    contract_info2 = create.create_contract('EUR', 'CASH', 'IDEALPRO', 'USD')
    order_info2 = create.create_order(accountName, 'MKT', 100000, 'BUY')
    tws.placeOrder(order_id, contract_info2, order_info2)    

    #tws.cancelOrder(order_id)   # Cancel example 2 order
    #tws.reqOpenOrders()         
    #tws.reqAllOpenOrders()
    #tws.reqAutoOpenOrders(1)    # clientId had to be 0 for this to work
    tws.reqGlobalCancel()
    
Пример #13
0
class IbApp(object):
    """IB链接器"""
    def __init__(self, host, port, client_id, req_dict, order_dict, tick_dict):
        """
        TODO: 不应该维护一个巨大的类,可以考虑使用混合模式来管理这个类
        :host:地址
        :port:接口
        :client_id:这个可以随便写一个,int
        :req_id:请求id
        :redis:redis实例
        """
        self.host = host
        self.port = port
        self.client_id = client_id
        self.warpper = IbTestWrapper(req_dict, order_dict, tick_dict)
        self.connection = EClientSocket(self.warpper)
        self.req_id = 0
        self.order_id = 0
        self.req_dict = req_dict
        self.order_dict = order_dict
        self.tick_dict = tick_dict

    def econnect(self):
        """docstring for connect"""
        # 连接TWS
        self.connection.eConnect(self.host, self.port, self.client_id)

    def subscribe(self, m_symbol, currency, m_sec_type, m_exchange,
                  m_local_symbol):
        """
        :return: 返回req_id和合约代码信息返回,好做好映射,
        """
        contract = Contract()
        contract.m_symbol = m_symbol  # 底层资产的代码 PS:CL
        contract.m_currency = currency  # 币种 PS:USD
        contract.m_secType = m_sec_type  # 证券类型 PS:FUT
        contract.m_exchange = m_exchange  # 交易所NYMEX
        contract.m_localSymbol = m_local_symbol  #合约代码
        self.req_id += 1
        self.connection.reqMktData(self.req_id, contract, '', False)  # 订阅
        self.tick_dict[self.req_id] = {}  # 初始化Tick的数据

        #cache_symbol
        cache_symbol = m_local_symbol if ' ' not in m_local_symbol else m_local_symbol.replace(
            ' ', '_')

        # 将订阅合约信息保存在字典中
        self.req_dict[self.req_id] = {
            'symbol': m_symbol,
            'currency': currency,
            'sec_type': m_sec_type,
            'exchange': m_exchange,
            'local_symbol': cache_symbol
        }

    def send_order(self, order_dict):
        """发单"""
        # 发单ID
        self.order_id += 1
        contract = self._make_opt_contract(order_dict)
        order = self._make_opt_order(self.order_id, self.client_id, order_dict)
        self.connection.placeOrder(self.order_id, contract, order)
        self.connection.reqIds()
        self.order_dict[self.order_id] = order_dict
        return self.order_id

    def cancle_order(self, order_id):
        """撤单"""
        self.connection.cancelOrder(order_id)

    def run(self):
        """运行"""
        while True:
            pass

    def _make_opt_contract(self, order_dict):
        """docstring for make_opt_contract"""
        contract = Contract()
        contract.m_localSymbol = order_dict['m_local_symbol']
        contract.m_secType = order_dict['m_sec_type']
        contract.m_right = order_dict['m_right']
        contract.m_expiry = order_dict['m_expiry']
        contract.m_strike = order_dict['m_strike']
        contract.m_exchange = order_dict['m_exchange']
        contract.m_currency = order_dict['currency']
        return contract

    def _make_opt_order(self, order_id, client_id, order_dict):
        """docstring for _make_opt_contract"""
        order = Order()
        order.m_orderId = order_id
        order.m_clientId = client_id
        order.m_action = order_dict['m_action']
        order.m_lmtPrice = order_dict['price']
        order.m_totalQuantity = order_dict['volume']
        order.m_orderType = order_dict['m_order_type']
        return order
Пример #14
0
class orderRunnerBeta:
    def __init__(self, datadecoder):
        self.accountName = "asd781820"
        self.callback = IBWrapper()
        self.tws = EClientSocket(self.callback)
        self.host = ""
        self.port = 4002
        self.clientId = 8
        self.tws.eConnect(self.host, self.port, self.clientId)
        self.dd = datadecoder
        self.create = contract()
        self.callback.initiate_variables()
        self.callback.initiate_variables()
        self.tws.reqAccountSummary(8, 'All', 'TotalCashValue')
        self.filedf = datadecoder.usabledf
        self.datadecoder = datadecoder
        contract_Details = self.create.create_contract('EUR', 'CASH',
                                                       'IDEALPRO', 'USD')
        tickerId = 10000
        self.tws.reqRealTimeBars(tickerId, contract_Details, 5, "MIDPOINT", 0)
        self.tickerId = 9010
        self.df = pd.read_csv('df.csv')
        self.RbinDict = bqe.makeRDf(self.df)
        self.column_index_value_dict, self.binDict = bqe.makeDf(self.df)

    def create_trailing_order(self, action, quantity, trailingPercent=0.006):
        order = Order()
        order.m_orderType = "TRAIL"
        order.m_totalQuantity = quantity
        order.m_trailingPercent = trailingPercent
        order.m_action = action
        return order

    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
        return order

    def buy(self, contract_Details, limit, stop):

        self.tws.reqIds(-1)
        time.sleep(0.5)
        oid = self.callback.next_ValidId
        parent = Order()
        parent.orderId = oid
        parent.m_action = "BUY"
        parent.m_orderType = "MKT"
        parent.m_totalQuantity = 300000
        parent.m_transmit = False
        print('|==========执行触发=================|')
        print('|执行时期:%s|' % datetime.now())
        print('|操作: BUY                        |')
        print('|执行前总额:%s' % self.callback.account_Summary[-1][3])
        print('|===================================|')
        self.tws.reqIds(-1)
        takeProfit = Order()
        takeProfit.orderId = parent.orderId + 1
        takeProfit.m_action = "SELL"
        takeProfit.m_orderType = "LMT"
        takeProfit.m_totalQuantity = 300000
        takeProfit.m_lmtPrice = limit
        takeProfit.m_parentId = oid
        takeProfit.m_transmit = False

        stopLoss = Order()
        stopLoss.orderId = parent.orderId + 2
        stopLoss.m_action = "SELL"
        stopLoss.m_orderType = "STP"
        #Stop trigger price
        stopLoss.m_auxPrice = stop
        stopLoss.m_totalQuantity = 300000
        stopLoss.m_parentId = oid
        stopLoss.m_transmit = True

        bracketOrder = [parent, takeProfit, stopLoss]

        for o in bracketOrder:
            self.tws.placeOrder(o.orderId, contract_Details, o)
            self.tws.reqIds(-1)
        time.sleep(1)
        time.sleep(2)

    def sell(self, contract_Details, limit, stop):
        self.tws.reqIds(-1)
        time.sleep(0.5)
        oid = self.callback.next_ValidId
        parent = Order()
        parent.orderId = oid
        parent.m_action = "SELL"
        parent.m_orderType = "MKT"
        parent.m_totalQuantity = 300000
        parent.m_transmit = False
        print('|==========执行触发=================|')
        print('|执行时期:%s|' % datetime.now())
        print('|操作: BUY                        |')
        print('|执行前总额:%s' % self.callback.account_Summary[-1][3])
        print('|===================================|')
        self.tws.reqIds(-1)
        takeProfit = Order()
        takeProfit.orderId = parent.orderId + 1
        takeProfit.m_action = "BUY"
        takeProfit.m_orderType = "LMT"
        takeProfit.m_totalQuantity = 300000
        takeProfit.m_lmtPrice = limit
        takeProfit.m_parentId = oid
        takeProfit.m_transmit = False

        stopLoss = Order()
        stopLoss.orderId = parent.orderId + 2
        stopLoss.m_action = "BUY"
        stopLoss.m_orderType = "STP"
        #Stop trigger price
        stopLoss.m_auxPrice = stop
        stopLoss.m_totalQuantity = 300000
        stopLoss.m_parentId = oid
        stopLoss.m_transmit = True

        bracketOrder = [parent, takeProfit, stopLoss]

        for o in bracketOrder:
            self.tws.placeOrder(o.orderId, contract_Details, o)
            self.tws.reqIds(-1)
        time.sleep(1)
        time.sleep(2)

    def job(self):
        contract_Details = self.create.create_contract('EUR', 'CASH',
                                                       'IDEALPRO', 'USD')
        #self.tws.reqCurrentTime()
        #time.sleep(1)
        #ts = self.callback.current_Time
        #data_endtime = datetime.utcfromtimestamp(ts).strftime('%Y%m%d  %H:%M:%S')

        self.tws.reqHistoricalData(tickerId=self.tickerId,
                                   contract=contract_Details,
                                   endDateTime='',
                                   durationStr="1 D",
                                   barSizeSetting="1 min",
                                   whatToShow="BID",
                                   useRTH=0,
                                   formatDate=1)

        time.sleep(2)

        data = pd.DataFrame(self.callback.historical_Data,
                            columns=[
                                "reqId", "date", "open", "high", "low",
                                "close", "volume", "count", "WAP", "hasGaps"
                            ])[-500:-1]
        self.dd.findMatch(data)
        print(data)
        print(datetime.now())

        for b in self.dd.reversedBucket:
            print('|=============================================|')
            print('|检测到基因:%s|' % b)
            print('|=============================================|')
            if (self.filedf.index.contains(b)):
                stra = bqe.get_sharpe_stra(b)

                if (stra > 0):
                    threading.Thread(target=self.buy,
                                     args=[contract_Details,
                                           stra + 1]).start()
                elif (stra < 0):
                    threading.Thread(target=self.sell,
                                     args=[contract_Details,
                                           abs(stra - 1)]).start()

        self.tws.reqIds(-1)
        print('|===================================|')
        print('|总额:%s               |' % self.callback.account_Summary[-1][3])
        print('|===================================|')

    def run(self):
        print('|===========================================|')
        print('|=======欢迎使用beta版本,祝您好运==========|')
        print('|====新特性:1。止损定单 2。智能订单执行====|')
        print('|===========================================|')
        print('|===========================================|')
        self.tickerId = 9010

        while (1):
            now = datetime.now()
            if (now.second == 5):
                contract_Details = self.create.create_contract(
                    'EUR', 'CASH', 'IDEALPRO', 'USD')
                #self.tws.reqCurrentTime()
                #time.sleep(1)
                #ts = self.callback.current_Time
                #data_endtime = datetime.utcfromtimestamp(ts).strftime('%Y%m%d  %H:%M:%S')

                self.tws.reqHistoricalData(tickerId=self.tickerId,
                                           contract=contract_Details,
                                           endDateTime='',
                                           durationStr="1 D",
                                           barSizeSetting="1 min",
                                           whatToShow="BID",
                                           useRTH=0,
                                           formatDate=1)

                time.sleep(2)

                data = pd.DataFrame(self.callback.historical_Data,
                                    columns=[
                                        "reqId", "date", "open", "high", "low",
                                        "close", "volume", "count", "WAP",
                                        "hasGaps"
                                    ])[-500:-1]
                self.dd.findMatch(data)

                last_close = data.iloc[-1].close
                for b in self.dd.reversedBucket:
                    if (self.filedf.index.contains(b)):
                        print('usable gene: %s' % b)
                        limit, stop, action = bqe.get_monte_carlo_stra(
                            ast.literal_eval(b), self.column_index_value_dict,
                            self.binDict, self.df, self.RbinDict)

                        if (action > 0):
                            limit_price = last_close + limit
                            stop_price = last_close - stop
                            threading.Thread(target=self.buy,
                                             args=[
                                                 contract_Details, limit_price,
                                                 stop_price
                                             ]).start()

                        elif (action < 0):
                            limit_price = last_close - limit
                            stop_price = last_close + stop
                            threading.Thread(
                                target=self.sell,
                                args=[contract_Details, limit, stop]).start()

                self.tws.reqIds(-1)
                print('|===================================|')
                print('|总额:%s               |' %
                      self.callback.account_Summary[-1][3])
                print('|===================================|')

    def dc(self):
        self.tws.eDisconnect()
Пример #15
0
class TWS_gateway(threading.Thread):

    # config
    config = None
    # redis connection
    rs = None

    # channel clients' requests to IB/TWS
    cli_request_handler = None

    # manage conID / contracts mapping
    contract_subscription_mgr = None

    connection = None

    # handler to process incoming IB/TWS messages and echo back to clients
    tws_event_handler = None

    # monitor IB connection / heart beat
    ibh = None
    tlock = None
    ib_conn_status = None
    ib_order_transmit = False

    def __init__(self, host, port, clientId, kafka_host, kafka_port, config):
        super(TWS_gateway, self).__init__()
        self.config = config
        self.host = host
        self.port = port
        self.clientId = clientId
        self.ib_order_transmit = config.get("tws_gateway", "tws_gateway.order_transmit").strip('"').strip("'") if \
                                        config.get("tws_gateway", "tws_gateway.order_transmit").strip('"').strip("'") <> None\
                                        else False

        logging.info('starting up TWS_gateway...')
        logging.info('Order straight through (no-touch) flag = %s' %
                     ('True' if self.ib_order_transmit == True else 'False'))

        logging.info('connecting to Redis server...')
        self.initialize_redis(config)

        logging.info('starting up TWS_event_handler...')
        self.tws_event_handler = TWS_event_handler(kafka_host, kafka_port)

        logging.info('starting up IB EClientSocket...')
        self.connection = EClientSocket(self.tws_event_handler)

        logging.info('starting up client request handler - kafkaConsumer...')
        self.cli_request_handler = KafkaConsumer( *[(v,0) for v in list(TWS_Protocol.topicMethods) + list(TWS_Protocol.gatewayMethods) ], \
                                   metadata_broker_list=['%s:%s' % (kafka_host, kafka_port)],\
                                   group_id = 'epc.tws_gateway',\
                                   auto_commit_enable=True,\
                                   auto_commit_interval_ms=30 * 1000,\
                                   auto_offset_reset='largest') # discard old ones

        self.reset_message_offset()

        if not self.eConnect():
            logging.error(
                'TWS_gateway: unable to establish connection to IB %s:%d' %
                (self.host, self.port))
            sys.exit(-1)
        else:
            # start heart beat monitor
            logging.info('starting up IB heart beat monitor...')
            self.tlock = Lock()
            self.ibh = IbHeartBeat(config)
            self.ibh.register_listener([self.on_ib_conn_broken])
            self.ibh.run()

        logging.info('starting up subscription manager...')
        self.initialize_subscription_mgr()

    def initialize_subscription_mgr(self):

        self.contract_subscription_mgr = SubscriptionManager(self)
        self.contract_subscription_mgr.register_persistence_callback(
            self.persist_subscriptions)
        key = self.config.get(
            "tws_gateway",
            "subscription_manager.subscriptions.redis_key").strip('"').strip(
                "'")
        if self.rs.get(key):
            #contracts = map(lambda x: ContractHelper.kvstring2contract(x), json.loads(self.rs.get(key)))

            def is_outstanding(c):

                today = time.strftime('%Y%m%d')
                if c.m_expiry < today:
                    logging.info(
                        'initialize_subscription_mgr: ignoring expired contract %s%s%s'
                        % (c.m_expiry, c.m_strike, c.m_right))
                    return False
                return True

            contracts = filter(
                lambda x: is_outstanding(x),
                map(lambda x: ContractHelper.kvstring2object(x, Contract),
                    json.loads(self.rs.get(key))))

            self.contract_subscription_mgr.load_subscription(contracts)

    def persist_subscriptions(self, contracts):

        key = self.config.get(
            "tws_gateway",
            "subscription_manager.subscriptions.redis_key").strip('"').strip(
                "'")
        #cs = json.dumps(map(lambda x: ContractHelper.contract2kvstring(x) if x <> None else None, contracts))
        cs = json.dumps(
            map(
                lambda x: ContractHelper.object2kvstring(x)
                if x <> None else None, contracts))
        logging.debug(
            'Tws_gateway: updating subscription table to redis store %s' % cs)
        self.rs.set(key, cs)

    def initialize_redis(self, config):
        r_host = config.get("redis", "redis.server").strip('"').strip("'")
        r_port = config.get("redis", "redis.port")
        r_db = config.get("redis", "redis.db")

        self.rs = redis.Redis(r_host, r_port, r_db)
        try:
            self.rs.client_list()
        except redis.ConnectionError:
            logging.error(
                'TWS_gateway: unable to connect to redis server using these settings: %s port:%d db:%d'
                % (r_host, r_port, r_db))
            logging.error('aborting...')
            sys.exit(-1)

    def reset_message_offset(self):
        topic_offsets = map(
            lambda topic: (topic,
                           self.cli_request_handler.get_partition_offsets(
                               topic, 0, -1, 999)),
            TWS_Protocol.topicMethods + TWS_Protocol.gatewayMethods)
        topic_offsets = filter(
            lambda x: x <> None,
            map(lambda x: (x[0], x[1][1], x[1][0])
                if len(x[1]) > 1 else None, topic_offsets))
        logging.info('TWS_gateway set topic offset to the latest point\n%s' %
                     (''.join('%s,%s,%s\n' % (x[0], x[1], x[2])
                              for x in topic_offsets)))

        # the set_topic_partitions method clears out all previous settings when executed
        # therefore it's not possible to call the function multiple times:
        # self.consumer.set_topic_partitions(('gw_subscriptions', 0, 114,)
        # self.consumer.set_topic_partitions(('tickPrice', 0, 27270,))
        # as the second call will wipe out whatever was done previously

        self.cli_request_handler.set_topic_partitions(*topic_offsets)

    def run(self):

        for message in self.cli_request_handler:

            logging.info("%s:%d:%d: key=%s value=%s" %
                         (message.topic, message.partition, message.offset,
                          message.key, message.value))

            #             print ("TWS_gateway: received client request %s:%d:%d: key=%s value=%s" % (message.topic, message.partition,
            #                                          message.offset, message.key,
            #                                          message.value))

            getattr(self, message.topic, None)(message.value)
            #self.cli_request_handler.task_done(message)

    def on_ib_conn_broken(self, msg):
        logging.error('TWS_gateway: detected broken IB connection!')
        self.ib_conn_status = 'ERROR'
        self.tlock.acquire()  # this function may get called multiple times
        try:  # block until another party finishes executing
            if self.ib_conn_status == 'OK':  # check status
                return  # if already fixed up while waiting, return

            self.eDisconnect()
            self.eConnect()
            while not self.connection.isConnected():
                logging.error('TWS_gateway: attempt to reconnect...')
                self.eConnect()
                sleep(2)

            # we arrived here because the connection has been restored
            # resubscribe tickers again!
            logging.info(
                'TWS_gateway: IB connection restored...resubscribe contracts')
            self.contract_subscription_mgr.force_resubscription()

        finally:
            self.tlock.release()

    def eConnect(self):
        logging.info('TWS_gateway - eConnect. Connecting to %s:%s App Id: %s' %
                     (self.host, self.port, self.clientId))
        self.connection.eConnect(self.host, self.port, self.clientId)
        return self.connection.isConnected()

    def reqAccountUpdates(self, value=None):
        logging.info('TWS_gateway - reqAccountUpdates value=%s' % value)
        self.connection.reqAccountUpdates(1, '')

    def reqAccountSummary(self, value):
        logging.info('TWS_gateway - reqAccountSummary value=%s' % value)

        vals = map(
            lambda x: x.encode('ascii') if isinstance(x, unicode) else x,
            json.loads(value))
        self.connection.reqAccountSummary(vals[0], vals[1], vals[2])

    def reqOpenOrders(self, value=None):
        self.connection.reqOpenOrders()

    def reqPositions(self, value=None):
        self.connection.reqPositions()

    def reqExecutions(self, value):
        try:
            filt = ExecutionFilter(
            ) if value == '' else ExecutionFilterHelper.kvstring2object(
                value, ExecutionFilter)
            self.connection.reqExecutions(0, filt)
        except:
            logging.error(traceback.format_exc())

    def reqIds(self, value=None):
        self.connection.reqIds(1)

    def reqNewsBulletins(self):
        self.connection.reqNewsBulletins(1)

    def cancelNewsBulletins(self):
        self.connection.cancelNewsBulletins()

    def setServerLogLevel(self):
        self.connection.setServerLogLevel(3)

    def reqAutoOpenOrders(self):
        self.connection.reqAutoOpenOrders(1)

    def reqAllOpenOrders(self):
        self.connection.reqAllOpenOrders()

    def reqManagedAccts(self):
        self.connection.reqManagedAccts()

    def requestFA(self):
        self.connection.requestFA(1)

    def reqMktData(self, sm_contract):
        logging.info('TWS Gateway received reqMktData request: %s' %
                     sm_contract)
        try:
            #self.contract_subscription_mgr.reqMktData(ContractHelper.kvstring2contract(sm_contract))
            self.contract_subscription_mgr.reqMktData(
                ContractHelper.kvstring2object(sm_contract, Contract))
        except:
            pass

    def reqHistoricalData(self):
        contract = Contract()
        contract.m_symbol = 'QQQQ'
        contract.m_secType = 'STK'
        contract.m_exchange = 'SMART'
        endtime = strftime('%Y%m%d %H:%M:%S')
        self.connection.reqHistoricalData(tickerId=1,
                                          contract=contract,
                                          endDateTime=endtime,
                                          durationStr='1 D',
                                          barSizeSetting='1 min',
                                          whatToShow='TRADES',
                                          useRTH=0,
                                          formatDate=1)

    def placeOrder(self, value=None):
        logging.info('TWS_gateway - placeOrder value=%s' % value)
        try:
            vals = json.loads(value)
        except ValueError:
            logging.error('TWS_gateway - placeOrder Exception %s' %
                          traceback.format_exc())
            return

#        c = ContractHelper.kvstring2contract(vals[1])
        o = OrderHelper.kvstring2object(vals[2], Order)
        o.__dict__['transmit'] = self.ib_order_transmit
        #         print c.__dict__
        #         print o.__dict__
        #         print '---------------------'

        #self.connection.placeOrder(vals[0], ContractHelper.kvstring2contract(vals[1]), OrderHelper.kvstring2object(vals[2], Order))
        self.connection.placeOrder(
            vals[0], ContractHelper.kvstring2object(vals[1], Contract),
            OrderHelper.kvstring2object(vals[2], Order))
#        self.connection.placeOrder(orderId, contract, newOptOrder)

    def eDisconnect(self, value=None):
        sleep(2)
        self.connection.eDisconnect()


####################################################################3
#   Gateway commands

    def gw_req_subscriptions(self, value=None):

        #subm = map(lambda i: ContractHelper.contract2kvstring(self.contract_subscription_mgr.handle[i]), range(len(self.contract_subscription_mgr.handle)))
        #subm = map(lambda i: ContractHelper.object2kvstring(self.contract_subscription_mgr.handle[i]), range(len(self.contract_subscription_mgr.handle)))
        subm = map(
            lambda i: (i,
                       ContractHelper.object2kvstring(
                           self.contract_subscription_mgr.handle[i])),
            range(len(self.contract_subscription_mgr.handle)))

        print subm
        if subm:
            self.tws_event_handler.broadcast_event('gw_subscriptions',
                                                   {'subscriptions': subm},
                                                   source='GW')