def spx_bar_history(update_bars=True):
        file_name = 'sp500_5min_bars'
        df_hist = read_feather(UpdateSP500Data.DATA_BASE_PATH / file_name)
        # Download latest
        if update_bars:
            ib = IB()
            ib.connect('127.0.0.1', port=4001, clientId=40)
            contract = Index('SPX', 'CBOE', 'USD')
            bars = ib.reqHistoricalData(
                contract,
                endDateTime='',
                durationStr='1 M',
                barSizeSetting='5 mins',
                whatToShow='TRADES',
                useRTH=True,
                formatDate=1)

            ib.disconnect()
            df = util.df(bars)
            df = df.set_index('date')
            full_hist = df.combine_first(df_hist)
            write_feather(full_hist, UpdateSP500Data.DATA_BASE_PATH / file_name)
        else:
            full_hist = df_hist.copy()
        return full_hist
Beispiel #2
0
class IbGateway:
    """Interactive Brokers functions to fetch data"""
    def __init__(self, host, port, clientId=0):
        self.ib_gateway = IB()
        self.ib_gateway.connect(host, port, clientId=clientId)

    def fundamental_data(self, contract):
        """Load fundamental data from Interactive Brokers"""
        ib_contract = Contract(**contract)
        fundamental_data = self.ib_gateway.reqFundamentalData(
            ib_contract, reportType="ReportsFinStatements")
        return xmltodict.parse(fundamental_data)

    def flush(self, tablename):
        """Remove all data from the table"""

    def ipmort_data(self, tablename, data):
        """Write data into the table"""

    def ping(self):
        """Pings Interactive Brokers gateway"""
        return self.ib_gateway.isConnected()

    def disconnect(self):
        """Disconnect from Interactive Brokers"""
        self.ib_gateway.disconnect()
def get_valid_spy_contract(idx) -> OptionContract:
    from ib_insync import IB, Stock

    ib = IB()
    ib.connect(clientId=idx + 1)
    ib_stk_con = Stock(symbol="SPY", exchange="SMART", currency="USD")
    ib_details = ib.reqContractDetails(ib_stk_con)[0]
    ib.reqMarketDataType(4)
    tick = ib.reqMktData(contract=ib_stk_con, snapshot=True)
    while np.isnan(tick.ask):
        ib.sleep()
    ask = tick.ask
    ib_con_id = ib_details.contract.conId
    ib_chains = ib.reqSecDefOptParams(
        underlyingSymbol="SPY",
        futFopExchange="",
        underlyingSecType="STK",
        underlyingConId=ib_con_id,
    )
    ib_chain = ib_chains[0]
    ib_chain.strikes.sort(key=lambda s: abs(s - ask))
    strike = ib_chain.strikes[0]
    expiration_str = ib_chain.expirations[idx]
    expiration_date = datetime.strptime(expiration_str, "%Y%m%d")
    spy_contract = OptionContract(
        symbol="SPY",
        strike=strike,
        right=Right.CALL,
        multiplier=int(ib_chain.multiplier),
        last_trade_date=expiration_date,
    )
    ib.disconnect()

    return spy_contract
Beispiel #4
0
def main(ib: IB):
    logger.getLogger().info("Connecting...")
    ib.disconnect()
    ib.waitOnUpdate(timeout=0.5)   #added to handle is client already in use https://github.com/erdewit/ib_insync/issues/76
    randomClientID = random.randint(1,250)
    log.info("random client ID: {CI}".format(CI=randomClientID))
    ib.connect(config.HOST, config.PORT, clientId=randomClientID,timeout=0)
    #ib.connect(config.HOST, config.PORT, clientId=config.CLIENTID,timeout=0)
    ib.reqMarketDataType(config.DATATYPE.value)
#    try:
#        logger.getLogger().info("Connecting...")
#        ib.connect(config.HOST, config.PORT, clientId=config.CLIENTID,timeout=0)
#        #ib.connect(config.HOST, config.PORT, clientId=config.CLIENTID,timeout=0)
#        ib.reqMarketDataType(config.DATATYPE.value)
#    except NameError:    # got this block from https://groups.io/g/insync/message/4045
#            #self.num_disconnects += 1
#            print(datetime.datetime.now(), 'Connection error exception', self.num_disconnects)
#            #self.ib.cancelHistoricalData(bars)
#            log.info('Sleeping for 10sec...')
#            ib.disconnect
#            self.ib.sleep(10)
#            ib.connect(config.HOST, config.PORT, clientId=config.CLIENTID,timeout=0)
#    except OSError:
#        log.info("main try except OS errror > Connection Failed.")
#        sys_exit()

    app = App(ib)
    app.run()
Beispiel #5
0
async def main(options):
    ib = IB()
    ib.disconnectedEvent += onDisconnected
    await ib.connectAsync(options.ib_host, options.ib_port)
    server = Server([IbBridgeServer(ib)])
    with graceful_exit([server]):
        await server.start(options.http_host, options.http_port)
        print(f"Serving on {options.http_host}:{options.http_port}")
        await server.wait_closed()
        ib.disconnectedEvent -= onDisconnected
        ib.disconnect()
Beispiel #6
0
def ping():
    def timeout_handler(signum, frame):
        signal.alarm(0)
        raise TimeoutError('IB gateway timed out, please check your account & password')
    signal.signal(signal.SIGALRM, timeout_handler)
    signal.alarm(120)

    ib = IB()
    while not ib.isConnected():
        try:
            IB.sleep(1)
            ib.connect('localhost', 4001, clientId=1)
        except (ConnectionRefusedError, OSError) as e:
            if type(e) is TimeoutError:
                raise e
            logging.warning('Still waiting gateway connection..({})'.format(e))
    
    ib.disconnect()
Beispiel #7
0
class Window(qt.QWidget):
    def __init__(self, host, port, clientId):
        qt.QWidget.__init__(self)
        self.edit = qt.QLineEdit('', self)
        self.edit.editingFinished.connect(self.add)
        self.table = TickerTable()
        self.connectButton = qt.QPushButton('Connect')
        self.connectButton.clicked.connect(self.onConnectButtonClicked)
        layout = qt.QVBoxLayout(self)
        layout.addWidget(self.edit)
        layout.addWidget(self.table)
        layout.addWidget(self.connectButton)

        self.connectInfo = (host, port, clientId)
        self.ib = IB()
        self.ib.pendingTickersEvent += self.table.onPendingTickers

    def add(self, text=''):
        text = text or self.edit.text()
        if text:
            contract = eval(text)
            if (contract and self.ib.qualifyContracts(contract)
                    and contract not in self.table):
                ticker = self.ib.reqMktData(contract, '', False, False, None)
                self.table.addTicker(ticker)
            self.edit.setText(text)

    def onConnectButtonClicked(self, _):
        if self.ib.isConnected():
            self.ib.disconnect()
            self.table.clearTickers()
            self.connectButton.setText('Connect')
        else:
            self.ib.connect(*self.connectInfo)
            self.ib.reqMarketDataType(2)
            self.connectButton.setText('Disonnect')
            for symbol in ('EURUSD', 'USDJPY', 'EURGBP', 'USDCAD', 'EURCHF',
                           'AUDUSD', 'NZDUSD'):
                self.add(f"Forex('{symbol}')")
            self.add("Stock('TSLA', 'SMART', 'USD')")

    def closeEvent(self, ev):
        asyncio.get_event_loop().stop()
Beispiel #8
0
class Window(QWidget):
    def __init__(self, host, port, clientId):
        QWidget.__init__(self)
        self.edit = QLineEdit('', self)
        self.edit.editingFinished.connect(self.add)
        self.connectButton = QPushButton('Connect')
        self.connectButton.clicked.connect(self.onConnectButtonClicked)
        layout = QVBoxLayout(self)
        layout.addWidget(self.edit)
        layout.addWidget(self.connectButton)
        self.graph = TickerGraph(self, width=5, height=4)
        self.graph.move(0, 0)
        layout.addWidget(self.graph)
        self.connectInfo = (host, port, clientId)
        self.ib = IB()

    def add(self, text=''):
        text = text  #or self.edit.text()
        if text:
            contract = eval(text)
            if (contract and self.ib.qualifyContracts(contract)):
                data = self.ib.reqHistoricalData(contract,
                                                 endDateTime='',
                                                 durationStr='30 D',
                                                 barSizeSetting='4 hours',
                                                 whatToShow='MIDPOINT',
                                                 useRTH=True)
                df = util.df(data)
                print(df["close"])
                self.graph.plot(df["close"])
            self.edit.setText(text)

    def onConnectButtonClicked(self, _):
        if self.ib.isConnected():
            self.ib.disconnect()
            self.connectButton.setText('Connect')
        else:
            self.ib.connect(*self.connectInfo)
            self.connectButton.setText('Disconnect')
            self.add(f"Forex('" + str(self.edit.text()) + "')")

    def closeEvent(self, ev):
        asyncio.get_event_loop().stop()
Beispiel #9
0
class BrokerConnection(metaclass=Singleton):
    def __init__(self):
        self.ib = IB()

    def connect(self, host, port, client_id, callback=None):
        self.ib.connect(host, port, clientId=client_id)
        if callback:
            self.ib.connectedEvent += callback

    def disconnect(self):
        self.ib.disconnect()

    def isConnected(self):
        return self.ib.isConnected()

    def positions(self):
        return [
            pos for pos in self.ib.positions() if pos.contract.secType == 'OPT'
        ]

    def reqMatchingSymbols(self, text_to_search):
        '''
        Function IBApi::EClient::reqMatchingSymbols is available to search for
        stock contracts. The input can be either the first few letters of the
        ticker symbol, or for longer strings, a character sequence matching a
        word in the security name.
        https://interactivebrokers.github.io/tws-api/matching_symbols.html
        '''
        return self.ib.reqMatchingSymbols(text_to_search)

    def getOptionChainContracts(self, contract):
        chain = self.ib.reqSecDefOptParams(contract.symbol, contract.exchange,
                                           contract.secType, contract.conId)
        qChain = self.ib.qualifyContracts(chain)
        #return util.df(qChain)
        return qChain
Beispiel #10
0
def ping():
    def timeout_handler(signum, frame):
        signal.alarm(0)
        raise TimeoutError(
            'IB gateway timed out, please check your account & password')

    signal.signal(signal.SIGALRM, timeout_handler)
    signal.alarm(120)

    ib = IB()
    pingClientId = int(os.environ['IB_GATEWAY_PING_CLIENT_ID'])
    maxRetryCount = int(os.environ['ibAccMaxRetryCount'])
    retryCount = 0
    while not ib.isConnected():
        try:
            IB.sleep(1)
            ib.connect('localhost', 4001, clientId=pingClientId)
        except (ConnectionRefusedError, OSError) as e:
            retryCount += 1
            if retryCount >= 30:
                raise ValueError("Invalid ib account")
            logging.warning('Still waiting gateway connection..({})'.format(e))

    ib.disconnect()
Beispiel #11
0
class trade_ES():
    def __init__(self):

        self.ib = IB()
        self.ib.connect('127.0.0.1',
                        7497,
                        clientId=np.random.randint(10, 1000))
        self.tickers_ret = {}
        self.endDateTime = ''
        self.No_days = '43200 S'
        self.interval = '30 secs'
        self.tickers_signal = "Hold"
        self.ES = Future(symbol='ES',
                         lastTradeDateOrContractMonth='20200619',
                         exchange='GLOBEX',
                         currency='USD')
        self.ib.qualifyContracts(self.ES)
        self.ES_df = self.ib.reqHistoricalData(contract=self.ES,
                                               endDateTime=self.endDateTime,
                                               durationStr=self.No_days,
                                               barSizeSetting=self.interval,
                                               whatToShow='TRADES',
                                               useRTH=False,
                                               keepUpToDate=True)
        self.tickers_ret = []
        self.options_ret = []
        self.option = {'call': FuturesOption, 'put': FuturesOption}
        self.options_history = {}
        self.trade_options = {'call': [], 'put': []}
        self.price = 0
        self.i = -1
        self.ES_df.updateEvent += self.make_clean_df
        self.Buy = True
        self.Sell = False
        self.ib.positionEvent += self.order_verify
        self.waitTimeInSeconds = 220
        self.tradeTime = 0
        self.mySemaphore = asyncio.Semaphore(1)

    def run(self):

        self.make_clean_df(self.ES_df)

    def next_exp_weekday(self):
        weekdays = {2: [6, 0], 4: [0, 1, 2], 0: [3, 4]}
        today = datetime.date.today().weekday()
        for exp, day in weekdays.items():
            if today in day:
                return exp

    def next_weekday(self, d, weekday):

        days_ahead = weekday - d.weekday()
        if days_ahead <= 0:  # Target day already happened this week
            days_ahead += 7
        date_to_return = d + datetime.timedelta(
            days_ahead)  # 0 = Monday, 1=Tuself.ESday, 2=Wednself.ESday...
        return date_to_return.strftime('%Y%m%d')

    def get_strikes_and_expiration(self):

        expiration = self.next_weekday(datetime.date.today(),
                                       self.next_exp_weekday())
        chains = self.ib.reqSecDefOptParams(underlyingSymbol='ES',
                                            futFopExchange='GLOBEX',
                                            underlyingSecType='FUT',
                                            underlyingConId=self.ES.conId)
        chain = util.df(chains)
        strikes = chain[chain['expirations'].astype(str).str.contains(
            expiration)].loc[:, 'strikes'].values[0]
        [ESValue] = self.ib.reqTickers(self.ES)
        ES_price = ESValue.marketPrice()
        strikes = [
            strike for strike in strikes
            if strike % 5 == 0 and ES_price - 10 < strike < ES_price + 10
        ]
        return strikes, expiration

    def get_contract(self, right, net_liquidation):
        strikes, expiration = self.get_strikes_and_expiration()
        for strike in strikes:
            contract = FuturesOption(symbol='ES',
                                     lastTradeDateOrContractMonth=expiration,
                                     strike=strike,
                                     right=right,
                                     exchange='GLOBEX')
            self.ib.qualifyContracts(contract)
            self.price = self.ib.reqMktData(contract, "", False, False)
            if float(self.price.last) * 50 >= net_liquidation:
                continue
            else:
                return contract

    def make_clean_df(self, ES_df, hashbar=None):

        ES_df = util.df(ES_df)
        ES_df['RSI'] = ta.RSI(ES_df['close'])
        ES_df['macd'], ES_df['macdsignal'], ES_df['macdhist'] = ta.MACD(
            ES_df['close'], fastperiod=12, slowperiod=26, signalperiod=9)
        ES_df['MA_9'] = ta.MA(ES_df['close'], timeperiod=9)
        ES_df['MA_21'] = ta.MA(ES_df['close'], timeperiod=21)
        ES_df['MA_200'] = ta.MA(ES_df['close'], timeperiod=200)
        ES_df['EMA_9'] = ta.EMA(ES_df['close'], timeperiod=9)
        ES_df['EMA_21'] = ta.EMA(ES_df['close'], timeperiod=21)
        ES_df['EMA_200'] = ta.EMA(ES_df['close'], timeperiod=200)
        ES_df['ATR'] = ta.ATR(ES_df['high'], ES_df['low'], ES_df['close'])
        ES_df['roll_max_cp'] = ES_df['high'].rolling(20).max()
        ES_df['roll_min_cp'] = ES_df['low'].rolling(20).min()
        ES_df['roll_max_vol'] = ES_df['volume'].rolling(20).max()
        ES_df.dropna(inplace=True)
        self.loop_function(ES_df)

    def placeOrder(self, contract, order):

        trade = self.ib.placeOrder(contract, order)
        tradeTime = datetime.datetime.now()
        return ([trade, contract, tradeTime])

    def sell(self, contract, position):
        self.ib.qualifyContracts(contract)
        if position.position > 0:
            order = 'Sell'
        else:
            order = 'Buy'

        marketorder = MarketOrder(order, abs(position.position))
        marketTrade, contract, tradeTime = self.placeOrder(
            contract, marketorder)
        while self.ib.position.position != 0:
            self.ib.sleep(1)
        self.mySemaphore.release()

    async def buy(self, contract):
        await self.semaphore.acquire()
        self.ib.qualifyContracts(contract)
        marketorder = MarketOrder('Buy', 1)
        marketTrade = self.ib.placeOrder(contract, marketorder)

    def order_verify(self, order):
        if order.position == 0.0 or order.position < 0:
            self.Buy = True
            self.Sell = False
        elif order.position > 0:
            self.Buy = False
            self.Sell = True

        else:
            self.Buy = False
            self.Sell = False
        print(f'Buy= {self.Buy}, sell = {self.Sell}')

    def loop_function(self, ES_df):

        df = ES_df[[
            'high', 'low', 'volume', 'close', 'RSI', 'ATR', 'roll_max_cp',
            'roll_min_cp', 'roll_max_vol', 'EMA_9', 'EMA_21', 'macd',
            'macdsignal'
        ]]

        if self.tickers_signal == "Hold":
            print('Hold')
            if df["high"].iloc[self.i] >= df["roll_max_cp"].iloc[self.i] and \
                    df["volume"].iloc[self.i] > df["roll_max_vol"].iloc[self.i - 1] and df['RSI'].iloc[self.i] > 30 \
                    and df['macd'].iloc[self.i] > df['macdsignal'].iloc[self.i] :
                self.tickers_signal = "Buy"
                return


            elif df["low"].iloc[self.i] <= df["roll_min_cp"].iloc[self.i] and \
                    df["volume"].iloc[self.i] > df["roll_max_vol"].iloc[self.i - 1] and df['RSI'].iloc[self.i] < 70 \
                    and df['macd'].iloc[self.i] < df['macdsignal'].iloc[self.i]:
                self.tickers_signal = "Sell"
                return

            else:
                self.tickers_signal = "Hold"
                return

        elif self.tickers_signal == "Buy":
            print('BUY SIGNAL')
            if df["close"].iloc[self.i] > df["close"].iloc[self.i - 1] - (
                    0.75 * df["ATR"].iloc[self.i - 1]) and len(
                        self.ib.positions()) != 0:
                print(
                    f'{df["close"].iloc[self.i]} > {df["close"].iloc[self.i - 1] - (0.75 * df["ATR"].iloc[self.i - 1])}'
                )
                print('first buy condition')
                positions = self.ib.positions()
                for position in positions:
                    if position.contract.right == 'C':
                        self.sell(position.contract, position)
                        self.tickers_signal = "Hold"
                        return



            elif df["low"].iloc[self.i] <= df["roll_min_cp"].iloc[self.i] and \
                    df["volume"].iloc[self.i] > df["roll_max_vol"].iloc[self.i - 1] and df['RSI'].iloc[self.i] < 70 \
                    and df['macd'].iloc[self.i] < df['macdsignal'].iloc[self.i] and len(self.ib.positions())!=0:
                self.tickers_signal = "Sell"
                print('sell')
                positions = self.ib.positions()
                for position in positions:
                    if position.contract.right == 'C':
                        self.sell(position.contract, position)
                        self.tickers_signal == "Sell"
                        return

            else:
                if len(self.ib.positions()) == 0:
                    self.option['call'] = self.get_contract(
                        right="C", net_liquidation=2000)
                    self.buy(self.option['call'])
                    self.tickers_signal = "Hold"
                else:
                    self.tickers_signal = "Hold"

        elif self.tickers_signal == "Sell":
            print('SELL SIGNAL')
            if df["close"].iloc[self.i] < df["close"].iloc[self.i - 1] + (
                    0.75 * df["ATR"].iloc[self.i - 1]) and len(
                        self.ib.positions()) != 0:
                print('first sell condition')
                print(
                    f'{df["close"].iloc[self.i]} < {df["close"].iloc[self.i - 1] - (0.75 * df["ATR"].iloc[self.i - 1])}'
                )
                print('sell')
                positions = self.ib.positions()
                for position in positions:
                    if position.contract.right == 'P':
                        self.sell(position.contract, position)
                        self.tickers_signal = "Hold"
                        return



            elif df["high"].iloc[self.i] >= df["roll_max_cp"].iloc[self.i] and \
                    df["volume"].iloc[self.i] > df["roll_max_vol"].iloc[self.i - 1] and df['RSI'].iloc[self.i] > 30 \
                    and df['macd'].iloc[self.i] > df['macdsignal'].iloc[self.i] and len(self.ib.positions())!=0:
                self.tickers_signal = "Buy"
                print('sell')
                positions = self.ib.positions()
                for position in positions:
                    if position.contract.right == 'P':
                        self.sell(position.contract, position)
                        self.tickers_signal == "Buy"
                        return

            else:
                if len(self.ib.positions()) == 0:
                    self.option['put'] = self.get_contract(
                        right="P", net_liquidation=2000)
                    self.buy(self.option['put'])
                    self.tickers_signal = "Hold"
                else:
                    self.tickers_signal = "Hold"

    def checkError(self, errCode, errString):
        print('Error Callback', errCode, errString)
        if errCode == 2104:
            print('re-connect after 5 secs')
            self.ib.sleep(5)
            self.ib.disconnect()
            self.ib.connect('127.0.0.1',
                            7497,
                            clientId=np.random.randint(10, 1000))
            self.make_clean_df(self.ES)
    def init_ticker(self):
        self.ticker = self.ticker_in.text().upper()
        self.ticker_in.setText(self.ticker)
        # self.spot = Ydata_feed.get_latest(self.ticker)
        # self.spot_in.setText(str(self.spot['close']))
        # if spot == None:
        print(self.ticker)
        self.spot = data_feed.get_data(
            self.ticker,
            'STK',
            'SMART',
            'USD',
            duration="1 D",
            enddate=datetime.today().strftime("%Y%m%d %H:%M:%S %Z"),
            barsize='1 day')
        sleep(5)
        self.spot_in.setText(str(self.spot['close'][0]))

        self.div_in.setText(str(0))
        # self.div_in.setText(str(Ydata_feed.get_div_yield(ticker)))

        exps(self.ticker)
        with open(tmp_file, newline='') as f:
            reader = csv.reader(f)
            self.exp_list = (datetime.strptime(i, "%Y%m%d")
                             for i in list(reader)[0])

            self.formatted_exp_list = list(
                (datetime.strftime(i, "%m-%d-%Y") for i in self.exp_list))
            print(list(self.formatted_exp_list),
                  len(list(self.formatted_exp_list)))

        d0 = datetime.today()  #.strftime('%Y%m%d')

        dds = []
        x = 0
        for iii in self.formatted_exp_list:
            d1 = datetime.strptime(iii, '%m-%d-%Y')  #.strftime('%Y%m%d')

            delta = d1 - d0
            dd = delta.days
            dds.append(str(dd))

            self.formatted_exp_list[x] = str(
                self.formatted_exp_list[x]) + " [" + str(dd) + "] "
            x += 1

        print(dds, len(dds))

        print(self.formatted_exp_list)

        self.comboBox_2.addItems(self.formatted_exp_list)
        for row in self.row_dic:
            # print(row,self.row_dic[row])
            self.row_dic[row]['exp'].addItems(self.formatted_exp_list)

        if self.fill_pos == None:
            self.fill_pos = QPushButton('Fill Positions', self)
            self.horizontalLayout.addWidget(self.fill_pos)
            self.fill_pos.clicked.connect(self.fill_positions)

        ib = IB().connect('127.0.0.1', port, clientId=20)
        ib.disconnect()
        ib.waitOnUpdate(timeout=0.1)
        print('disconnected')
        print(ib.isConnected())
class Window(qt.QWidget):

    def __init__(self, host, port, clientId):
        qt.QWidget.__init__(self)
        
        self.vxxbLabel = qt.QLabel('VXXB')
        self.vxxbButton = qt.QPushButton('VXXB')
        self.tltLabel = qt.QLabel('TLT')
        self.tltButton = qt.QPushButton('TLT')
        self.gldLabel = qt.QLabel('GLD')
        self.gldButton = qt.QPushButton('GLD')
        self.vxxbButton.clicked.connect(self.onVXXBButtonClicked)
        self.gldButton.clicked.connect(self.onGLDButtonClicked)
        self.tltButton.clicked.connect(self.onTLTButtonClicked)
        self.pricedic = {}
        
#        self.edit = qt.QLineEdit('', self)
#        self.edit.editingFinished.connect(self.add)
        self.table = TickerTable()
        self.connectButton = qt.QPushButton('Connect')
        self.connectButton.clicked.connect(self.onConnectButtonClicked)
        
        
        layout = qt.QGridLayout(self)#qt.QVBoxLayout(self)
        

        layout.addWidget(self.vxxbLabel,0,0,1,2)
        layout.addWidget(self.vxxbButton,1,0,1,2)
        layout.addWidget(self.tltLabel,0,2,1,2)
        layout.addWidget(self.tltButton,1,2,1,2)
        layout.addWidget(self.gldLabel,0,4,1,2)
        layout.addWidget(self.gldButton,1,4,1,2)        
        
        
#        layout.addWidget(self.edit)
        layout.addWidget(self.table,2,0,6,6)
        layout.addWidget(self.connectButton,9,2,1,2)
        
        

        self.connectInfo = (host, port, clientId)
        self.ib = IB()
        self.ib.pendingTickersEvent += self.table.onPendingTickers
        self.ib.pendingTickersEvent += self.onPendingTickersForLabels

    def add(self, contract):
        if (contract and self.ib.qualifyContracts(contract)
                and contract not in self.table):
            ticker = self.ib.reqMktData(contract, '', False, False, None)
            self.table.addTicker(ticker)

    def onConnectButtonClicked(self, _):
        if self.ib.isConnected():
            self.ib.disconnect()
            self.table.clearTickers()
            self.connectButton.setText('Connect')
        else:
            self.ib.connect(*self.connectInfo)
            self.connectButton.setText('Disonnect')
            
            self.vxxb = Stock('VXXB',exchange='SMART')
            self.ib.qualifyContracts(self.vxxb)
            self.table.vxxbticker = self.ib.reqMktData(self.vxxb, '', False, False, None)
            
            self.tlt = Stock('TLT',exchange='ARCA')
            self.ib.qualifyContracts(self.tlt)
            self.table.tltticker = self.ib.reqMktData(self.tlt, '', False, False, None)
            
            self.gld = Stock('GLD',exchange='ARCA')
            self.ib.qualifyContracts(self.gld)
            self.table.gldticker = self.ib.reqMktData(self.gld, '', False, False, None)
            
    def closeEvent(self, ev):
        asyncio.get_event_loop().stop()

    def onPendingTickersForLabels(self, tickers):
        for ticker in tickers:
            if type(getattr(ticker,'contract'))==Stock:  
                if ticker.contract.symbol=='VXXB':
                    self.vxxbprice = ticker.marketPrice()
                    self.vxxbLabel.setText('{0:0.2f}'.format(self.vxxbprice))
                    self.table.vxxbprice = self.vxxbprice
                    self.pricedic['VXXB'] = self.vxxbprice
#                    print('vxxb:'+str(ticker.marketPrice()))
                elif ticker.contract.symbol=='GLD':
                    self.gldprice = ticker.marketPrice()
                    self.gldLabel.setText('{0:0.2f}'.format(self.gldprice))
                    self.table.gldprice=self.gldprice
                    self.pricedic['GLD'] = self.gldprice
#                    print('gld:'+str(ticker.marketPrice()))
                else:
                    self.tltprice = ticker.marketPrice()
                    self.tltLabel.setText('{0:0.2f}'.format(self.tltprice))
                    self.table.tltprice=self.tltprice
                    self.pricedic['TLT'] = self.tltprice
#                    print('tlt:'+str(ticker.marketPrice()))
                    
                    
    def prepareOptionContract(self,stockcontract):        
        
        contractPrice = self.pricedic[stockcontract.symbol]
        chains = self.ib.reqSecDefOptParams(stockcontract.symbol, '', stockcontract.secType,stockcontract.conId)
        chain = next(c for c in chains if c.exchange == 'SMART')
#        print(chain)
        strikes = sorted([strike for strike in chain.strikes
        if contractPrice - 2 < strike < contractPrice + 2])
        expirations = sorted(exp for exp in chain.expirations)[:2]

        contracts = [Option(stockcontract.symbol, expiration, strike, 'P','SMART')
                    for expiration in expirations
                    for strike in strikes]
#        print(contracts)
        self.ib.qualifyContracts(*contracts)
        for ac in contracts:
            self.add(contract=ac)           
            
            
    def onVXXBButtonClicked(self, _):
        if self.ib.isConnected():
            self.table.clearTickers()
            self.prepareOptionContract(self.vxxb)
            self.table.symbolofticker = 'VXXB'
            
    def onGLDButtonClicked(self, _):
        if self.ib.isConnected():
            self.table.clearTickers()
            self.prepareOptionContract(self.gld)
            self.table.symbolofticker = 'GLD'
            
    def onTLTButtonClicked(self, _):
        print('TLT')
        if self.ib.isConnected():
            self.table.clearTickers()
            self.prepareOptionContract(self.tlt)
            self.table.symbolofticker = 'TLT'
Beispiel #14
0
class IBStore(with_metaclass(MetaSingleton, object)):
    '''Singleton class wrapping an ibpy ibConnection instance.

    The parameters can also be specified in the classes which use this store,
    like ``IBData`` and ``IBBroker``

    Params:

      - ``host`` (default:``127.0.0.1``): where IB TWS or IB Gateway are
        actually running. And although this will usually be the localhost, it
        must not be

      - ``port`` (default: ``7496``): port to connect to. The demo system uses
        ``7497``

      - ``clientId`` (default: ``None``): which clientId to use to connect to
        TWS.

        ``None``: generates a random id between 1 and 65535
        An ``integer``: will be passed as the value to use.

      - ``notifyall`` (default: ``False``)

        If ``False`` only ``error`` messages will be sent to the
        ``notify_store`` methods of ``Cerebro`` and ``Strategy``.

        If ``True``, each and every message received from TWS will be notified

      - ``_debug`` (default: ``False``)

        Print all messages received from TWS to standard output

      - ``reconnect`` (default: ``3``)

        Number of attempts to try to reconnect after the 1st connection attempt
        fails

        Set it to a ``-1`` value to keep on reconnecting forever

      - ``timeout`` (default: ``3.0``)

        Time in seconds between reconnection attemps

      - ``timeoffset`` (default: ``True``)

        If True, the time obtained from ``reqCurrentTime`` (IB Server time)
        will be used to calculate the offset to localtime and this offset will
        be used for the price notifications (tickPrice events, for example for
        CASH markets) to modify the locally calculated timestamp.

        The time offset will propagate to other parts of the ``backtrader``
        ecosystem like the **resampling** to align resampling timestamps using
        the calculated offset.

      - ``timerefresh`` (default: ``60.0``)

        Time in seconds: how often the time offset has to be refreshed

      - ``indcash`` (default: ``True``)

        Manage IND codes as if they were cash for price retrieval
    '''

    # Set a base for the data requests (historical/realtime) to distinguish the
    # id in the error notifications from orders, where the basis (usually
    # starting at 1) is set by TWS
    REQIDBASE = 0x01000000

    BrokerCls = None #getattr(sys.modules["cerebro.strategies." +classname.split('.')[0]], classname.split('.')[1])IBBroker  #None  # broker class will autoregister
    DataCls = None  # data class will auto register

    params = (
        ('host', '127.0.0.1'),
        ('port', 7496),
        ('clientId', None),  # None generates a random clientid 1 -> 2^16
        ('notifyall', False), # NOT IMPLEMENTED
        ('_debug', False),
        ('reconnect', 3),  # -1 forever, 0 No, > 0 number of retries
        ('timeout', 3.0),  # timeout between reconnections
        ('timeoffset', True),  # Use offset to server for timestamps if needed
        ('timerefresh', 60.0),  # How often to refresh the timeoffset
        ('indcash', True),  # Treat IND codes as CASH elements
        ('readonly', False),  # Set to True when IB API is in read-only mode
        ('account', ''),  # Main account to receive updates for
     
    )

    @classmethod
    def getdata(cls, *args, **kwargs):
        '''Returns ``DataCls`` with args, kwargs'''
        return cls.DataCls(*args, **kwargs)

    @classmethod
    def getbroker(cls, *args, **kwargs):
        '''Returns broker with *args, **kwargs from registered ``BrokerCls``'''
        return cls.BrokerCls(*args, **kwargs)

    def __init__(self):
        super(IBStore, self).__init__()

        self._env = None  # reference to cerebro for general notifications
        self.broker = None  # broker instance
        self.datas = list()  # datas that have registered over start
        # self.ccount = 0  # requests to start (from cerebro or datas)

        # self._lock_tmoffset = threading.Lock()
        # self.tmoffset = timedelta()  # to control time difference with server

        # # Structures to hold datas requests
        # self.qs = collections.OrderedDict()  # key: tickerId -> queues
        # self.ts = collections.OrderedDict()  # key: queue -> tickerId
        self.iscash = dict()  # tickerIds from cash products (for ex: EUR.JPY)

        self.acc_cash = AutoDict()  # current total cash per account
        self.acc_value = AutoDict()  # current total value per account
        self.acc_upds = AutoDict()  # current account valueinfos per account

        self.positions = collections.defaultdict(Position)  # actual positions

        self.orderid = None  # next possible orderid (will be itertools.count)

        self.managed_accounts = list()  # received via managedAccounts
        self.notifs = queue.Queue()  # store notifications for cerebro
        self.orders = collections.OrderedDict()  # orders by order ided

        self.opending = collections.defaultdict(list)  # pending transmission
        self.brackets = dict()  # confirmed brackets
        
        self.last_tick = None

        # Use the provided clientId or a random one
        if self.p.clientId is None:
            self.clientId = random.randint(1, pow(2, 16) - 1)
        else:
            self.clientId = self.p.clientId

        if self.p.timeout is None:
            self.timeout = 2
        else:
            self.timeout = self.p.timeout

        if self.p.readonly is None:
            self.readonly = False
        else:
            self.readonly = self.p.readonly

        if self.p.account is None:
            self.account = ""
        else:
            self.account = self.p.account
                    
        if self.p._debug:
            util.logToConsole(level=logging.DEBUG)
        
        util.patchAsyncio()
        util.startLoop()
        
        self.ib = IB()
        
        self.ib.connect(
                    host=self.p.host, port=self.p.port, 
                    clientId=self.clientId,
                    timeout=self.timeout,
                    readonly=self.readonly,
                    account=self.account,
                    )
        
        # This utility key function transforms a barsize into a:
        #   (Timeframe, Compression) tuple which can be sorted
        def keyfn(x):
            n, t = x.split()
            tf, comp = self._sizes[t]
            return (tf, int(n) * comp)

        # This utility key function transforms a duration into a:
        #   (Timeframe, Compression) tuple which can be sorted
        def key2fn(x):
            n, d = x.split()
            tf = self._dur2tf[d]
            return (tf, int(n))

        # Generate a table of reverse durations
        self.revdur = collections.defaultdict(list)
        # The table (dict) is a ONE to MANY relation of
        #   duration -> barsizes
        # Here it is reversed to get a ONE to MANY relation of
        #   barsize -> durations
        for duration, barsizes in self._durations.items():
            for barsize in barsizes:
                self.revdur[keyfn(barsize)].append(duration)

        # Once managed, sort the durations according to real duration and not
        # to the text form using the utility key above
        for barsize in self.revdur:
            self.revdur[barsize].sort(key=key2fn)

    def start(self, data=None, broker=None):
        #self.reconnect(fromstart=True)  # reconnect should be an invariant

        # Datas require some processing to kickstart data reception
        if data is not None:
            self._env = data._env
            # For datas simulate a queue with None to kickstart co
            self.datas.append(data)

            # if connection fails, get a fakeation that will force the
            # datas to try to reconnect or else bail out
            return self.getTickerQueue(start=True)

        elif broker is not None:
            self.broker = broker

    def stop(self):
        try:
            self.ib.disconnect()  # disconnect should be an invariant
        except AttributeError:
            pass    # conn may have never been connected and lack "disconnect"

    def get_notifications(self):
        '''Return the pending "store" notifications'''
        # The background thread could keep on adding notifications. The None
        # mark allows to identify which is the last notification to deliver
        self.notifs.put(None)  # put a mark
        notifs = list()
        while True:
            notif = self.notifs.get()
            if notif is None:  # mark is reached
                break
            notifs.append(notif)

        return notifs

    def managedAccounts(self):
        # 1st message in the stream
        self.managed_accounts = self.ib.managedAccounts()

        # Request time to avoid synchronization issues
        self.reqCurrentTime()

    def currentTime(self,msg):
        if not self.p.timeoffset:  # only if requested ... apply timeoffset
            return
        curtime = datetime.fromtimestamp(float(msg.time))
        with self._lock_tmoffset:
            self.tmoffset = curtime - datetime.now()

        threading.Timer(self.p.timerefresh, self.reqCurrentTime).start()

    def timeoffset(self):
        with self._lock_tmoffset:
            return self.tmoffset

    def reqCurrentTime(self):
        self.ib.reqCurrentTime()

    def nextOrderId(self):
        # Get the next ticker using a new request value from TWS
        self.orderid = self.ib.client.getReqId()
        return self.orderid

    def getTickerQueue(self, start=False):
        '''Creates ticker/Queue for data delivery to a data feed'''
        q = queue.Queue()
        if start:
            q.put(None)
            return q
            
        return q
    
    def getContractDetails(self, contract, maxcount=None):
        #cds = list()
        cds = self.ib.reqContractDetails(contract)
 
        #cds.append(cd)

        if not cds or (maxcount and len(cds) > maxcount):
            err = 'Ambiguous contract: none/multiple answers received'
            self.notifs.put((err, cds, {}))
            return None

        return cds

    def reqHistoricalDataEx(self, contract, enddate, begindate,
                            timeframe, compression,
                            what=None, useRTH=False, tz='', 
                            sessionend=None,
                            #tickerId=None
                            ):
        '''
        Extension of the raw reqHistoricalData proxy, which takes two dates
        rather than a duration, barsize and date

        It uses the IB published valid duration/barsizes to make a mapping and
        spread a historical request over several historical requests if needed
        '''
        # Keep a copy for error reporting purposes
        kwargs = locals().copy()
        kwargs.pop('self', None)  # remove self, no need to report it

        if timeframe < TimeFrame.Seconds:
            # Ticks are not supported
            return self.getTickerQueue(start=True)

        if enddate is None:
            enddate = datetime.now()

        if begindate is None:
            duration = self.getmaxduration(timeframe, compression)
            if duration is None:
                err = ('No duration for historical data request for '
                       'timeframe/compresison')
                self.notifs.put((err, (), kwargs))
                return self.getTickerQueue(start=True)
            barsize = self.tfcomp_to_size(timeframe, compression)
            if barsize is None:
                err = ('No supported barsize for historical data request for '
                       'timeframe/compresison')
                self.notifs.put((err, (), kwargs))
                return self.getTickerQueue(start=True)

            return self.reqHistoricalData(contract=contract, enddate=enddate,
                                          duration=duration, barsize=barsize,
                                          what=what, useRTH=useRTH, tz=tz,
                                          sessionend=sessionend)

        # Check if the requested timeframe/compression is supported by IB
        durations = self.getdurations(timeframe, compression)
        # if not durations:  # return a queue and put a None in it
        #     return self.getTickerQueue(start=True)

        # Get or reuse a queue
        # if tickerId is None:
        #     tickerId, q = self.getTickerQueue()
        # else:
        #     tickerId, q = self.reuseQueue(tickerId)  # reuse q for old tickerId

        # Get the best possible duration to reduce number of requests
        duration = None
        # for dur in durations:
        #     intdate = self.dt_plus_duration(begindate, dur)
        #     if intdate >= enddate:
        #         intdate = enddate
        #         duration = dur  # begin -> end fits in single request
        #         break
        intdate = begindate

        if duration is None:  # no duration large enough to fit the request
            duration = durations[-1]

            # Store the calculated data
            # self.histexreq[tickerId] = dict(
            #     contract=contract, enddate=enddate, begindate=intdate,
            #     timeframe=timeframe, compression=compression,
            #     what=what, useRTH=useRTH, tz=tz, sessionend=sessionend)

        barsize = self.tfcomp_to_size(timeframe, compression)

        if contract.secType in ['CASH', 'CFD']:
            #self.iscash[tickerId] = 1  # msg.field code
            if not what:
                what = 'BID'  # default for cash unless otherwise specified

        elif contract.secType in ['IND'] and self.p.indcash:
            #self.iscash[tickerId] = 4  # msg.field code
            pass

        what = what or 'TRADES'
        
        q = self.getTickerQueue()

        histdata = self.ib.reqHistoricalData(
                                contract,
                                intdate.strftime('%Y%m%d %H:%M:%S') + ' GMT',
                                duration,
                                barsize,
                                what,
                                useRTH,
                                2) # dateformat 1 for string, 2 for unix time in seconds
        for msg in histdata:
            q.put(msg)
        
        return q

    def reqHistoricalData(self, contract, enddate, duration, barsize,
                          what=None, useRTH=False, tz='', sessionend=None):
        '''Proxy to reqHistorical Data'''

        # get a ticker/queue for identification/data delivery
        q = self.getTickerQueue()

        if contract.secType in ['CASH', 'CFD']:
            #self.iscash[tickerId] = True
            if not what:
                what = 'BID'  # TRADES doesn't work
            elif what == 'ASK':
                #self.iscash[tickerId] = 2
                pass
        else:
            what = what or 'TRADES'

        # split barsize "x time", look in sizes for (tf, comp) get tf
        #tframe = self._sizes[barsize.split()[1]][0]
        # self.histfmt[tickerId] = tframe >= TimeFrame.Days
        # self.histsend[tickerId] = sessionend
        # self.histtz[tickerId] = tz

        histdata = self.ib.reqHistoricalData(
                            contract,
                            enddate.strftime('%Y%m%d %H:%M:%S') + ' GMT',
                            duration,
                            barsize,
                            what,
                            useRTH,
                            2) # dateformat 1 for string, 2 for unix time in seconds
        for msg in histdata:
            q.put(msg)

        return q

    def reqRealTimeBars(self, contract, useRTH=False, duration=5):
        '''Creates a request for (5 seconds) Real Time Bars

        Params:
          - contract: a ib.ext.Contract.Contract intance
          - useRTH: (default: False) passed to TWS
          - duration: (default: 5) passed to TWS

        Returns:
          - a Queue the client can wait on to receive a RTVolume instance
        '''
        # get a ticker/queue for identification/data delivery
        q = self.getTickerQueue()

        rtb = self.ib.reqRealTimeBars(contract, duration, 
                                      'MIDPOINT', useRTH=useRTH)
        self.ib.sleep(duration)
        for bar in rtb:
            q.put(bar)
        return q

    def reqMktData(self, contract, what=None):
        '''Creates a MarketData subscription

        Params:
          - contract: a ib.ext.Contract.Contract intance

        Returns:
          - a Queue the client can wait on to receive a RTVolume instance
        '''
        # get a ticker/queue for identification/data delivery
        q = self.getTickerQueue()
        ticks = '233'  # request RTVOLUME tick delivered over tickString

        if contract.secType in ['CASH', 'CFD']:
            #self.iscash[tickerId] = True
            ticks = ''  # cash markets do not get RTVOLUME
            if what == 'ASK':
                #self.iscash[tickerId] = 2
                pass

        # q.put(None)  # to kickstart backfilling
        # Can request 233 also for cash ... nothing will arrive
        
        md = MktData()
        q_ticks = queue.Queue()
        
        util.run(md.update_ticks(self.ib, contract, ticks, q_ticks))
                  
        while not q_ticks.empty():
            ticker = q_ticks.get()
            for tick in ticker.ticks:
                # https://interactivebrokers.github.io/tws-api/tick_types.html
                if tick != self.last_tick: #last price
                    #print(str(tick.time) +" >> " + str(tick.price))
                    self.last_tick = tick
                    q.put(tick)

        return q

    # The _durations are meant to calculate the needed historical data to
    # perform backfilling at the start of a connetion or a connection is lost.
    # Using a timedelta as a key allows to quickly find out which bar size
    # bar size (values in the tuples int the dict) can be used.

    _durations = dict([
        # 60 seconds - 1 min
        ('60 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min')),

        # 120 seconds - 2 mins
        ('120 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins')),

        # 180 seconds - 3 mins
        ('180 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins')),

        # 300 seconds - 5 mins
        ('300 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins')),

        # 600 seconds - 10 mins
        ('600 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins')),

        # 900 seconds - 15 mins
        ('900 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins')),

        # 1200 seconds - 20 mins
        ('1200 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins')),

        # 1800 seconds - 30 mins
        ('1800 S',
         ('1 secs', '5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins')),

        # 3600 seconds - 1 hour
        ('3600 S',
         ('5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour')),

        # 7200 seconds - 2 hours
        ('7200 S',
         ('5 secs', '10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour', '2 hours')),

        # 10800 seconds - 3 hours
        ('10800 S',
         ('10 secs', '15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour', '2 hours', '3 hours')),

        # 14400 seconds - 4 hours
        ('14400 S',
         ('15 secs', '30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour', '2 hours', '3 hours', '4 hours')),

        # 28800 seconds - 8 hours
        ('28800 S',
         ('30 secs',
          '1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour', '2 hours', '3 hours', '4 hours', '8 hours')),

        # 1 days
        ('1 D',
         ('1 min', '2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour', '2 hours', '3 hours', '4 hours', '8 hours',
          '1 day')),

        # 2 days
        ('2 D',
         ('2 mins', '3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour', '2 hours', '3 hours', '4 hours', '8 hours',
          '1 day')),

        # 1 weeks
        ('1 W',
         ('3 mins', '5 mins', '10 mins', '15 mins',
          '20 mins', '30 mins',
          '1 hour', '2 hours', '3 hours', '4 hours', '8 hours',
          '1 day', '1 W')),

        # 2 weeks
        ('2 W',
         ('15 mins', '20 mins', '30 mins',
          '1 hour', '2 hours', '3 hours', '4 hours', '8 hours',
          '1 day', '1 W')),

        # 1 months
        ('1 M',
         ('30 mins',
          '1 hour', '2 hours', '3 hours', '4 hours', '8 hours',
          '1 day', '1 W', '1 M')),

        # 2+ months
        ('2 M', ('1 day', '1 W', '1 M')),
        ('3 M', ('1 day', '1 W', '1 M')),
        ('4 M', ('1 day', '1 W', '1 M')),
        ('5 M', ('1 day', '1 W', '1 M')),
        ('6 M', ('1 day', '1 W', '1 M')),
        ('7 M', ('1 day', '1 W', '1 M')),
        ('8 M', ('1 day', '1 W', '1 M')),
        ('9 M', ('1 day', '1 W', '1 M')),
        ('10 M', ('1 day', '1 W', '1 M')),
        ('11 M', ('1 day', '1 W', '1 M')),

        # 1+ years
        ('1 Y',  ('1 day', '1 W', '1 M')),
    ])

    # Sizes allow for quick translation from bar sizes above to actual
    # timeframes to make a comparison with the actual data
    _sizes = {
        'secs': (TimeFrame.Seconds, 1),
        'min': (TimeFrame.Minutes, 1),
        'mins': (TimeFrame.Minutes, 1),
        'hour': (TimeFrame.Minutes, 60),
        'hours': (TimeFrame.Minutes, 60),
        'day': (TimeFrame.Days, 1),
        'W': (TimeFrame.Weeks, 1),
        'M': (TimeFrame.Months, 1),
    }

    _dur2tf = {
        'S': TimeFrame.Seconds,
        'D': TimeFrame.Days,
        'W': TimeFrame.Weeks,
        'M': TimeFrame.Months,
        'Y': TimeFrame.Years,
    }

    def getdurations(self,  timeframe, compression):
        key = (timeframe, compression)
        if key not in self.revdur:
            return []

        return self.revdur[key]

    def getmaxduration(self, timeframe, compression):
        key = (timeframe, compression)
        try:
            return self.revdur[key][-1]
        except (KeyError, IndexError):
            pass

        return None

    def tfcomp_to_size(self, timeframe, compression):
        if timeframe == TimeFrame.Months:
            return '{} M'.format(compression)

        if timeframe == TimeFrame.Weeks:
            return '{} W'.format(compression)

        if timeframe == TimeFrame.Days:
            if not compression % 7:
                return '{} W'.format(compression // 7)

            return '{} day'.format(compression)

        if timeframe == TimeFrame.Minutes:
            if not compression % 60:
                hours = compression // 60
                return ('{} hour'.format(hours)) + ('s' * (hours > 1))

            return ('{} min'.format(compression)) + ('s' * (compression > 1))

        if timeframe == TimeFrame.Seconds:
            return '{} secs'.format(compression)

        # Microseconds or ticks
        return None

    def dt_plus_duration(self, dt, duration):
        size, dim = duration.split()
        size = int(size)
        if dim == 'S':
            return dt + timedelta(seconds=size)

        if dim == 'D':
            return dt + timedelta(days=size)

        if dim == 'W':
            return dt + timedelta(days=size * 7)

        if dim == 'M':
            month = dt.month - 1 + size  # -1 to make it 0 based, readd below
            years, month = divmod(month, 12)
            return dt.replace(year=dt.year + years, month=month + 1)

        if dim == 'Y':
            return dt.replace(year=dt.year + size)

        return dt  # could do nothing with it ... return it intact


    # def histduration(self, dt1, dt2):
    #     # Given two dates calculates the smallest possible duration according
    #     # to the table from the Historical Data API limitations provided by IB
    #     #
    #     # Seconds: 'x S' (x: [60, 120, 180, 300, 600, 900, 1200, 1800, 3600,
    #     #                     7200, 10800, 14400, 28800])
    #     # Days: 'x D' (x: [1, 2]
    #     # Weeks: 'x W' (x: [1, 2])
    #     # Months: 'x M' (x: [1, 11])
    #     # Years: 'x Y' (x: [1])

    #     td = dt2 - dt1  # get a timedelta for calculations

    #     # First: array of secs
    #     tsecs = td.total_seconds()
    #     secs = [60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 7200, 10800,
    #             14400, 28800]

    #     idxsec = bisect.bisect_left(secs, tsecs)
    #     if idxsec < len(secs):
    #         return '{} S'.format(secs[idxsec])

    #     tdextra = bool(td.seconds or td.microseconds)  # over days/weeks

    #     # Next: 1 or 2 days
    #     days = td.days + tdextra
    #     if td.days <= 2:
    #         return '{} D'.format(days)

    #     # Next: 1 or 2 weeks
    #     weeks, d = divmod(td.days, 7)
    #     weeks += bool(d or tdextra)
    #     if weeks <= 2:
    #         return '{} W'.format(weeks)

    #     # Get references to dt components
    #     y2, m2, d2 = dt2.year, dt2.month, dt2.day
    #     y1, m1, d1 = dt1.year, dt1.month, dt2.day

    #     H2, M2, S2, US2 = dt2.hour, dt2.minute, dt2.second, dt2.microsecond
    #     H1, M1, S1, US1 = dt1.hour, dt1.minute, dt1.second, dt1.microsecond

    #     # Next: 1 -> 11 months (11 incl)
    #     months = (y2 * 12 + m2) - (y1 * 12 + m1) + (
    #         (d2, H2, M2, S2, US2) > (d1, H1, M1, S1, US1))
    #     if months <= 1:  # months <= 11
    #         return '1 M'  # return '{} M'.format(months)
    #     elif months <= 11:
    #         return '2 M'  # cap at 2 months to keep the table clean

    #     # Next: years
    #     # y = y2 - y1 + (m2, d2, H2, M2, S2, US2) > (m1, d1, H1, M1, S1, US1)
    #     # return '{} Y'.format(y)

    #     return '1 Y'  # to keep the table clean

    def makecontract(self, symbol, sectype, exch, curr,
                     expiry='', strike=0.0, right='', mult=1):
        '''returns a contract from the parameters without check'''

        contract = Contract()

        contract.symbol = symbol
        contract.secType = sectype
        contract.exchange = exch
        if curr:
            contract.currency = curr
        if sectype in ['FUT', 'OPT', 'FOP']:
            contract.lastTradeDateOrContractMonth = expiry
        if sectype in ['OPT', 'FOP']:
            contract.strike = strike
            contract.right = right
        if mult:
            contract.multiplier = mult

        return contract

    def cancelOrder(self, orderid):
        '''Proxy to cancelOrder'''
        self.ib.cancelOrder(orderid)


    def placeOrder(self, orderid, contract, order):
        '''Proxy to placeOrder'''        
        trade = self.ib.placeOrder(contract, order)  
        while not trade.isDone():
            self.ib.waitOnUpdate()
        return trade
        
    def reqTrades(self):
        '''Proxy to Trades'''
        return self.ib.trades()

    def reqPositions(self):
        '''Proxy to reqPositions'''
        return self.ib.reqPositions()
    
    def getposition(self, contract, clone=False):
        # Lock access to the position dicts. This is called from main thread
        # and updates could be happening in the background
        #with self._lock_pos:
        position = self.positions[contract.conId]
        if clone:
            return copy(position)

        return position

    def reqAccountUpdates(self, subscribe=True, account=None):
        '''Proxy to reqAccountUpdates

        If ``account`` is ``None``, wait for the ``managedAccounts`` message to
        set the account codes
        '''
        if account is None:
            #self._event_managed_accounts.wait()
            self.managedAccounts()
            account = self.managed_accounts[0]

        #self.ib.reqAccountUpdates(subscribe, bytes(account))
        self.updateAccountValue()


    def updateAccountValue(self):
        # Lock access to the dicts where values are updated. This happens in a
        # sub-thread and could kick it at anytime
        #with self._lock_accupd:
        #if self.connected():
        ret = self.ib.accountValues()
        
        for msg in ret:
            try:
                value = float(msg.value)   
            except ValueError:
                value = msg.value

            self.acc_upds[msg.account][msg.tag][msg.currency] = value

            if msg.tag == 'NetLiquidation':
                # NetLiquidationByCurrency and currency == 'BASE' is the same
                self.acc_value[msg.account] = value
            elif msg.tag == 'TotalCashBalance' and msg.currency == 'BASE':
                self.acc_cash[msg.account] = value

    def get_acc_values(self, account=None):
        '''Returns all account value infos sent by TWS during regular updates
        Waits for at least 1 successful download

        If ``account`` is ``None`` then a dictionary with accounts as keys will
        be returned containing all accounts

        If account is specified or the system has only 1 account the dictionary
        corresponding to that account is returned
        '''
        # Wait for at least 1 account update download to have been finished
        # before the account infos can be returned to the calling client
        # if self.connected():
        #     self._event_accdownload.wait()
        # Lock access to acc_cash to avoid an event intefering
        #with self._updacclock:
        if account is None:
            # wait for the managedAccount Messages
            # if self.connected():
            #     self._event_managed_accounts.wait()

            if not self.managed_accounts:
                return self.acc_upds.copy()

            elif len(self.managed_accounts) > 1:
                return self.acc_upds.copy()

            # Only 1 account, fall through to return only 1
            account = self.managed_accounts[0]

        try:
            return self.acc_upds[account].copy()
        except KeyError:
            pass

        return self.acc_upds.copy()

    def get_acc_value(self, account=None):
        '''Returns the net liquidation value sent by TWS during regular updates
        Waits for at least 1 successful download

        If ``account`` is ``None`` then a dictionary with accounts as keys will
        be returned containing all accounts

        If account is specified or the system has only 1 account the dictionary
        corresponding to that account is returned
        '''
        # Wait for at least 1 account update download to have been finished
        # before the value can be returned to the calling client
        # if self.connected():
        #     self._event_accdownload.wait()
        # Lock access to acc_cash to avoid an event intefering
        #with self._lock_accupd:
        if account is None:
            # wait for the managedAccount Messages
            # if self.connected():
            #     self._event_managed_accounts.wait()

            if not self.managed_accounts:
                return float()

            elif len(self.managed_accounts) > 1:
                return sum(self.acc_value.values())

            # Only 1 account, fall through to return only 1
            account = self.managed_accounts[0]

        try:
            return self.acc_value[account]
        except KeyError:
            pass

        return float()

    def get_acc_cash(self, account=None):
        '''Returns the total cash value sent by TWS during regular updates
        Waits for at least 1 successful download

        If ``account`` is ``None`` then a dictionary with accounts as keys will
        be returned containing all accounts

        If account is specified or the system has only 1 account the dictionary
        corresponding to that account is returned
        '''
        # Wait for at least 1 account update download to have been finished
        # before the cash can be returned to the calling client'
        # if self.connected():
        #     self._event_accdownload.wait()
            # result = [v for v in self.ib.accountValues() \
            #           if v.tag == 'TotalCashBalance' and v.currency == 'BASE']
        # Lock access to acc_cash to avoid an event intefering
            
        #with self._lock_accupd:
        if account is None:
            #wait for the managedAccount Messages
            # if self.connected():
            #     self._event_managed_accounts.wait()

            if not self.managed_accounts:
                return float()

            elif len(self.managed_accounts) > 1:
                return sum(self.acc_cash.values())

            # Only 1 account, fall through to return only 1
            account = self.managed_accounts[0]

        try:
            return self.acc_cash[account]
        except KeyError:
            pass
Beispiel #15
0
import logging

from ib_insync import IB

from config.config import Config
from incre.crawl import Crawl
from incre.cal import Cal

if __name__ == '__main__':
    # 记录 IB 接口及其他错误信息
    logging.basicConfig(filename='logs/incre/error.log', level=logging.ERROR)

    ib = IB()
    ib.connect(Config.ib_host, Config.ib_port, Config.ib_client_id)

    # 增量爬取数据
    c = Crawl(ib)
    c.crawl_codes_data()  # 爬取 stock 数据
    c.crawl_index_data()  # 爬取 HSI 数据

    ib.disconnect()

    # 增量计算数据
    ca = Cal()
    ca.main()
Beispiel #16
0
def runProg(args):
    """run program"""

    util.patchAsyncio()

    # log to a file
    utils.logToFile(f'ttestTradingHours.log', level=logging.INFO)
    # utils.logToConsole()

    apschedulerLogger = logging.getLogger('apscheduler')
    apschedulerLogger.setLevel(logging.INFO)
    tradingLogger = logging.getLogger('trading')
    tradingLogger.setLevel(logging.INFO)

    pd.set_option('display.width', 200)

    # flags
    useWatchdog = False
    useScheduler = True

    # local timezone
    tzlocal = dateutil.tz.tzlocal()

    # load the config file
    configFile = args.configFile
    config = ConfigParser(interpolation=ExtendedInterpolation(),
                          defaults=os.environ)
    config.read(configFile)

    # load data from configFile
    host = config.get('InteractiveBrokers', 'host')
    port = config.getint('InteractiveBrokers', 'port')
    clientId = config.getint('InteractiveBrokers', 'clientId')
    DBType = config.get('DataBase', 'DBType')
    DBFileName = config.get('DataBase', 'DBFileName')

    # for production mode: watchdog
    if useWatchdog:
        # start watchdog
        # ibc = IBC(963, gateway=True, tradingMode='paper',ibcIni='/home/bn/IBController/configPaper.ini')
        ibcIni = config.get('InteractiveBrokers', 'ibcIni')
        tradingMode = config.get('InteractiveBrokers', 'tradingMode')
        ibc = IBC(970, gateway=True, tradingMode=tradingMode, ibcIni=ibcIni)
        ib = IB()
        watchdogApp = Watchdog(ibc,
                               ib=ib,
                               appStartupTime=15,
                               host=host,
                               port=port,
                               clientId=clientId)
        watchdogApp.start()
    else:
        # faster way for now
        ib = IB()
        try:
            ib.connect(host=host, port=port, clientId=clientId)
        except:
            import random
            clientId = clientId + random.randint(1, 100000)
            ib.connect(host=host, port=port, clientId=clientId)
            pass

        class myWatchdog(object):
            def __init__(self):
                self.ib = ib
                pass

            pass

        watchdogApp = myWatchdog()
        pass
    pass

    # create database class
    mydb = database.tradingDB(DBType=DBType, DBFileName=DBFileName)
    # load existing database
    mydb.instantiateExistingTablesAndClasses(ib=ib)
    # set log level of sqlalchemy
    mydb._loggerSQLAlchemy.setLevel(logging.WARNING)

    # set the list of qualified contracts
    # get a list of qualified contracts that correspond to each row in mydb.MarketDataInfoTableDataFrame
    __qcs__ = list(mydb.MarketDataInfoTableDataFrame.qualifiedContract.values)
    # qcs = __qcs__[0:2]
    # qcs = operator.itemgetter(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12)(__qcs__)
    # qcs = operator.itemgetter(0, 13, 1, 11, 7)(__qcs__)
    # qcs = operator.itemgetter(0, 12, 13, 2, 10, 3)(__qcs__)
    # qcs = operator.itemgetter(0, 1, 10)(__qcs__)
    qcs = __qcs__
    if isinstance(qcs, Contract):
        qcs = [qcs]
        pass
    if isinstance(qcs, tuple):
        qcs = list(qcs)
        pass

    if None in qcs:
        print('problem with connecting to IB. Now exiting')
        sys.exit()

    # define the container class
    cc = containerClass.ContainerClass()

    # add config
    cc.config = config

    # set watchdogapp
    cc.watchdogApp = watchdogApp

    # set database
    cc.mydb = mydb
    cc.qcs = qcs

    # register callbacks with ib
    cc.registerCallbacks(useWatchdog=useWatchdog)

    # define a scheduler
    useScheduler = True
    if useScheduler:
        scheduler = AsyncIOScheduler()
        cc.scheduler = scheduler
        cc.scheduler.start()
        pass

    for qc in qcs:
        print(qc)
        cds = watchdogApp.ib.reqContractDetails(qc)
        cd = cds[0]
        tHP = marketDataIB.TradingHourParser(cd)
        print(tHP.timeZoneId)
        for line in tHP.tradingHours.split(';'):
            print(line)
            break
            pass
        hoursParsed = tHP.parseToDF()
        print(hoursParsed.head(6))
        # for index, row in hoursParsed.iterrows():
        #     print(row)
        #     break
        #     pass

    # # general setting for the density of data for historical requests
    # configIB = config['InteractiveBrokers']
    # barSizePandasTimeDelta = pd.Timedelta(**eval(configIB.get('densityTimeDelta', '{"minutes":1}')))
    #
    #
    # ##############################################################
    # # request recent historical bars
    # ##############################################################
    # # settings to request the bars (for the qcs that are a member of cc)
    # # the 'short' settings are the default ones to be applied during trading hours
    #
    # durationPandasTimeDelta = pd.Timedelta(**eval(configIB.get('durationTimeDeltaRecentHistoricalDataShort', '{"hours":1}')))
    # timeOutTime = configIB.getint('timeOutTimeShortRequests', 10)
    #
    # recentHistoricalDataSettingsShort = {
    #     'durationPandasTimeDelta': durationPandasTimeDelta,
    #     'barSizePandasTimeDelta': barSizePandasTimeDelta,
    #     'timeOutTime': timeOutTime,
    #     'maximumBarsLengthFactor': 2,
    # }
    #
    # # settings for recent historical bars to be requested during off-trading hours.
    # # due to performance reasons, during the trading hours we want to request
    # # very short bars; during off-trading hours, we can request longer bars
    # # which fill up possible gaps left by the shorter setting.
    #
    # durationPandasTimeDelta = pd.Timedelta(**eval(configIB.get('durationTimeDeltaRecentHistoricalDataLong', '{"days":1}')))
    # timeOutTime = configIB.getint('timeOutTimeMediumRequests', 60)
    #
    # recentHistoricalDataSettingsLong = {
    #     'durationPandasTimeDelta': durationPandasTimeDelta,
    #     'barSizePandasTimeDelta': barSizePandasTimeDelta,
    #     'timeOutTime': timeOutTime,
    #     'maximumBarsLengthFactor': 2,
    # }
    #
    #
    # # set the current settings in the containerClass
    # a = (f'Now updating the settings for the request of recent historical bars')
    # logging.info(a)
    # print(a)
    # # set the settings
    # cc.recentHistoricalDataSettings = recentHistoricalDataSettingsShort
    #
    # # request the bars
    # a = (f'Now requesting initial recent historical bars')
    # logging.info(a)
    # print(a)
    # orderedDictOfBars = cc.requestRecentHistoricalOrderedDictOfBars()
    # cc.orderedDictOfBars = orderedDictOfBars
    #
    #
    # for (tableName, bars) in cc.orderedDictOfBars.items():
    #     nBars = None
    #     if isinstance(bars,objects.BarDataList):
    #         nBars = len(bars)
    #     print(tableName,type(bars),nBars)
    # ##############################################################
    #
    #
    # ##############################################################
    # # request historical bars
    # ##############################################################
    #
    # # add the job requesting historical data to the scheduler
    # # this setting starts at the earliestDateTime given by IB
    #
    # earliestPandasTimeDelta = pd.Timedelta(**eval(configIB.get('earliestTimeDeltaHistoricalData', '{"weeks":4}')))
    # durationPandasTimeDelta = pd.Timedelta(**eval(configIB.get('durationTimeDeltaHistoricalData', '{"days":1}')))
    # timeOutTime = configIB.getint('timeOutTimeLongRequests', 1800)
    # # timeOutTime = configIB.getint('timeOutTimeMediumRequests', 60)
    #
    # if earliestPandasTimeDelta.total_seconds() < 0:
    #     earliestDateTimeUTCNaive = None
    # else:
    #     earliestDateTimeUTCNaive = pd.to_datetime(pd.datetime.utcnow()).floor('1 min') - earliestPandasTimeDelta
    #     pass
    #
    # historicalDataGetterSettings={
    #     'ib': cc.watchdogApp.ib,
    #     'mydb': cc.mydb,
    #     'qcs': cc.qcs,
    #     'durationPandasTimeDelta': durationPandasTimeDelta,
    #     'barSizePandasTimeDelta': barSizePandasTimeDelta,
    #     'earliestDateTime': earliestDateTimeUTCNaive,
    #     'timeOutTime': timeOutTime,
    #     'jitterSpanFraction': 0.02,
    # }
    #
    # jobSettings = {
    #     'job': marketDataIB.asyncioJobGetHistoricalData,
    #     'args': [],
    #     'kwargs': historicalDataGetterSettings,
    #     'jobRootName': None,
    #     'minute': '*',
    #     'second': '0',
    #     'coalesce': True,
    #     'misfire_grace_time': 30,
    #     'trigger': 'cron',
    #     'max_instances': 1,
    # }
    #
    # if useScheduler:
    #     cc.addJobToScheduler(jobSettings=jobSettings)
    #     pass
    # ##############################################################
    #
    #
    # ##############################################################
    # # change the request of recent historical bars to a longer setting during off-trading hours
    # ##############################################################
    # # add a scheduled job that switches from the short to the long settings
    # jobSettings = {
    #     'job': cc.schedulerJobSwitchRequestForRecentHistoricalDataFromOneSettingToOther,
    #     'args': [],
    #     'kwargs': recentHistoricalDataSettingsLong,
    #     'jobRootName': 'schedulerJobSwitchRequestForRecentHistoricalDataFromShortToLong',
    #     'hour': '22',
    #     # 'hour': '*',
    #     'minute': '07',
    #     # 'minute': '*/2',
    #     'second': '00',
    #     # 'second': '5-59/10',
    #     'coalesce': True,
    #     'misfire_grace_time': 30,
    #     'trigger': 'cron',
    #     'max_instances': 1,
    # }
    #
    # if useScheduler:
    #     cc.addJobToScheduler(jobSettings=jobSettings)
    #
    # # add a scheduled job that switches from the long to the short settings
    # jobSettings = {
    #     'job': cc.schedulerJobSwitchRequestForRecentHistoricalDataFromOneSettingToOther,
    #     'args': [],
    #     'kwargs': recentHistoricalDataSettingsShort,
    #     'jobRootName': 'schedulerJobSwitchRequestForRecentHistoricalDataFromLongToShort',
    #     'hour': '04',
    #     # 'hour': '*',
    #     'minute': '13',
    #     # 'minute': '1-59/2',
    #     'second': '00',
    #     # 'second': '*/10',
    #     'coalesce': True,
    #     'misfire_grace_time': 30,
    #     'trigger': 'cron',
    #     'max_instances': 1,
    # }
    #
    # if useScheduler:
    #     cc.addJobToScheduler(jobSettings=jobSettings)
    #
    # ##############################################################

    if 1:
        if useScheduler:
            print('Press Ctrl+{0} to exit'.format('Break' if os.name ==
                                                  'nt' else 'C'))
            # Execution will block here until Ctrl+C (Ctrl+Break on Windows) is pressed.
            try:
                asyncio.get_event_loop().run_forever()
            except (KeyboardInterrupt, SystemExit):
                pass
            pass
        else:
            util.allowCtrlC()
            ib.run()
            pass
        pass

    ib.disconnect()
Beispiel #17
0
def instantiateMyDB(args):
    """instantiate all SQ ORM classes using a config file passed in the arguments"""

    # load the config file
    configFile = args.configFile
    config = ConfigParser(interpolation=ExtendedInterpolation(),
                          defaults=os.environ)
    config.read(configFile)

    # create connection to IB
    ib = IB()
    assert (isinstance(ib, IB))

    ib.errorEvent += myErrorCallback

    # load data from configFile
    a = config.get('MarketData', 'ConIdList')
    conIdList = eval(a)
    host = config.get('InteractiveBrokers', 'host')
    port = config.getint('InteractiveBrokers', 'port')
    clientId = config.getint('InteractiveBrokers', 'clientId')
    DBType = config.get('DataBase', 'DBType')
    DBFileName = config.get('DataBase', 'DBFileName')
    timeOutTime = config.getint('InteractiveBrokers',
                                'timeOutTimeShortRequests')

    # override configFile if clientId is given on the command line
    if args.clientId is not None:
        clientId = args.clientId

    # override configFile if timeOutTime is given on the command line
    if args.timeOutTime is not None:
        timeOutTime = args.TimeOutTime

    # connect to interactive brokers
    try:
        ib.connect(host=host, port=port, clientId=clientId)
    except:
        import random
        clientId = clientId + random.randint(1, 100000)
        ib.connect(host=host, port=port, clientId=clientId)
        pass

    # create database class
    mydb = tradingDB(DBType=DBType, DBFileName=DBFileName)

    # loop over all conIds defined in the config File and create the sqlalchemy ORM classes
    # these tables will appear in the metadata of the DBDeclarativeBase attribute of mydb
    # prepare a dataframe that holds all infos that should be put into the MarketDataInfoTable on disk
    # and the MarketDataInfoTableDataFrame in memory
    nTables = len(conIdList)
    featureList = [
        'conId',
        'qualifiedContract',
        'earliestDateTime',
        'category',
        'kwargs',
        'tableName',
        'tableORM',
    ]
    dfWithInfoAboutTables = pd.DataFrame(None,
                                         index=range(nTables),
                                         columns=featureList)
    dfWithInfoAboutTables.loc[:, 'conId'] = conIdList

    df = dfWithInfoAboutTables
    for indx in df.index:
        conId = df.at[indx, 'conId']

        a = (f'about to qualify contract: conId: {conId}')
        logging.info(a)
        print(a)

        qc = utils.getQualifiedContractFromConId(ib=ib,
                                                 conId=conId,
                                                 timeOutTime=timeOutTime)
        df.at[indx, 'qualifiedContract'] = qc

        # calculate the earliest Date for this contract
        earliestDateTime = utils.getEarliestDateTimeFromIBAsDateTime(
            ib=ib, qualifiedContract=qc, timeOutTime=timeOutTime)
        df.at[indx, 'earliestDateTime'] = earliestDateTime

        # set the category that should be MarketData for the tables to be generated in this loop
        category = mydb.tableCategories.MarketData.value
        df.at[indx, 'category'] = category

        # set the keyword arguments for the call to calculateTableName
        kwargs = {}
        kwargs['category'] = category
        kwargs['earliestDateTime'] = earliestDateTime
        kwargs.update(qc.dict())
        df.at[indx, 'kwargs'] = kwargs

        # calculate the tableName
        tableName = mydb.calculateTableName(**kwargs)
        df.at[indx, 'tableName'] = tableName

        # create the sqlalchemy ORM class; this will write the class to the mydb.DBDeclarativeBase.metadata object
        a = (
            f'creating MarketData Table: conId: {conId}; tableName: {tableName}'
        )
        logging.info(a)
        print(a)
        tableORM = mydb.getTableORMByTablename(tableName=tableName)
        df.at[indx, 'tableORM'] = tableORM

        pass

    # now all the ORM tables should be defined.
    # they are not yet created on disk.
    # also, the MarketDataInfoTable is not populated and the MarketDataInfoTableDataFrame is not populated

    # loop over all conIds defined in the config File and create a row in the Market Data Info Table
    # also, populate the corresponding dataframe

    # create all tables on disk if they do not yet exist
    mydb.createAllTables()

    ssn = mydb.Session()
    for indx, row in dfWithInfoAboutTables.iterrows():
        tableName = row.tableName
        print(f'upserting a row for {tableName} to the MarketDataInfoTable')
        # create a row for each conId in the MDIT table
        # first, instantiate a row in the MarketDataInfoTable
        MDIT = mydb.MarketDataInfoTable(tableName=tableName)
        # set all available column values
        kwargs = row.kwargs
        for k, v in kwargs.items():
            if k in MDIT.__table__.columns:
                setattr(MDIT, k, v)
                pass
            pass
        # upsert this table Row to the table
        d = utils.convertTableRowToDict(MDIT)
        # # only update values that are not none
        # rowOfTableOnDisk = ssn.query(mydb.MarketDataInfoTable).filter(mydb.MarketDataInfoTable.tableName==tableName).first()
        # for k,v in d.items():
        #     if v is None:
        #         a = None
        #         print(k,v)
        #         try:
        #             a = getattr(rowOfTableOnDisk, 'earliestDateTime', None)
        #         except:
        #             pass
        #
        #         d[k] = a
        #         print(a)
        #         pass
        #     pass
        ssn.execute(mydb.upsert(mydb.MarketDataInfoTable, [d]))

    ssn.commit()
    ssn.close()

    mydb.MarketDataInfoTableDataFrame = mydb.createMarketDataInfoTableDataFrameFromMarketDataInfoTable(
        ib=ib, timeOutTime=timeOutTime)

    # disconnect from interactive brokers
    ib.disconnect()

    return (mydb)
class AsyncIBDataProvider(GenericDataProvider):

    logger = logging.getLogger(__name__)

    def __init__(self,
                 verbose: int,
                 host: str,
                 port: int,
                 timeout: int,
                 chunk_size: int,
                 id=0,
                 tz='America/New_York',
                 **kwargs):
        super(AsyncIBDataProvider, self).__init__(self.logger,
                                                  verbose,
                                                  tz,
                                                  chunk_size=chunk_size,
                                                  **kwargs)
        self.port = port
        self.host = host
        self.timeout = timeout
        self.keep_alive = False
        if 'keep_alive' in kwargs:
            self.keep_alive = kwargs['keep_alive']
        self.ib = IB()
        self.id = id

    def disconnect(self):
        self.ib.disconnect()

    def connect(self):
        if self.id == 0:
            id = int(random.uniform(1, 1000))
        else:
            id = self.id
        self.logger.info(
            f"IBAsync: {self.host}:{self.port}, timeout={self.timeout}, id={id}"
        )
        self.ib.connect(self.host,
                        self.port,
                        clientId=id,
                        timeout=self.timeout,
                        readonly=True)

    def _initialize(self):
        if not self.ib.isConnected():
            self.connect()

    def _finish(self):
        if not self.keep_alive:
            self.disconnect()

    async def _get_data_internal_async(self, symbol_data: SymbolData,
                                       **kwargs) -> pd.DataFrame:
        return self._get_data_internal(symbol_data)

    def _get_data_internal(self, symbol_data: SymbolData) -> pd.DataFrame:
        self.logger.info(f"Getting symbol data: {symbol_data}")

        if symbol_data.timeframe == 'day':
            symbol, bars = self._get_daily(symbol_data.start,
                                           symbol_data.symbol, symbol_data.end)
            symbol = symbol_data.symbol.split('-')[0]
            dataframe = self._to_dataframe(bars)

        elif symbol_data.timeframe == '60min':
            now = f"{(datetime.now()):%Y-%m-%d %H:%M}"
            duration = '365 D'
            if symbol_data.start:
                diff = datetime.strptime(
                    now, '%Y-%m-%d %H:%M') - datetime.strptime(
                        symbol_data.start, '%Y-%m-%d %H:%M')
                if diff.days < 365:
                    duration = f"{diff.days} D"
            symbol, bars = self._get_intraday(symbol_data.symbol, now,
                                              duration, '1 hour',
                                              symbol_data.rth_only)
            symbol = symbol_data.symbol.split('-')[0]
            dataframe = self._to_dataframe(bars, tz_fix=True)

        elif symbol_data.timeframe == '5min':
            now = f"{(datetime.now()):%Y-%m-%d %H:%M}"
            duration = '30 D'
            if symbol_data.start:
                diff = datetime.strptime(
                    now, '%Y-%m-%d %H:%M') - datetime.strptime(
                        symbol_data.start, '%Y-%m-%d %H:%M')
                if diff.days < 30:
                    duration = f"{diff.days} D"

            symbol, bars = self._get_intraday(symbol_data.symbol, now,
                                              duration, '5 mins',
                                              symbol_data.rth_only)
            symbol = symbol_data.symbol.split('-')[0]
            dataframe = self._to_dataframe(bars, tz_fix=True)

        elif symbol_data.timeframe == '15min':
            now = f"{(datetime.now()):%Y-%m-%d %H:%M}"
            duration = '60 D'
            if symbol_data.start:
                diff = datetime.strptime(
                    now, '%Y-%m-%d %H:%M') - datetime.strptime(
                        symbol_data.start, '%Y-%m-%d %H:%M')
                if diff.days < 60:
                    duration = f"{diff.days} D"
            symbol, bars = self._get_intraday(symbol_data.symbol, now,
                                              duration, '15 mins',
                                              symbol_data.rth_only)
            symbol = symbol_data.symbol.split('-')[0]
            dataframe = self._to_dataframe(bars, tz_fix=True)

        else:
            raise Exception(f"{symbol_data.timeframe} not implemented!")

        df = dataframe
        if dataframe.empty:
            self.logger.warning(f"Got empty df for {symbol_data}")
        else:
            df = self._post_process(dataframe, symbol, symbol_data.start,
                                    symbol_data.end, symbol_data.timeframe,
                                    symbol_data.transform)

        return df

    @staticmethod
    def exctract_symbol(ticker: str,
                        type: str = 'STK',
                        exchange: str = 'ARCA',
                        currency: str = 'USD',
                        expire='',
                        multiplier='') -> tuple:
        if ticker.count('-') == 4:
            symbol, type, exchange, currency, multiplier = ticker.split('-')
            if type.isdigit():
                expire = type
                type = "FUT"

        elif ticker.count('-') == 3:
            symbol, type, exchange, currency = ticker.split('-')
            if type.isdigit():
                expire = type
                type = "FUT"

        elif ticker.count('-') == 2:
            if ticker.find('CASH') > -1:
                symbol, currency, exchange = ticker.split('-')
                symbol = symbol.replace('.', '')
                type = 'FX'
            else:
                a, b, c = ticker.split('-')
                if b.isdigit():
                    type = 'FUT'
                    symbol = a
                    exchange = c
                    expire = b
                else:
                    symbol = a
                    exchange = b
                    currency = c

        elif ticker.count('-') == 1:
            symbol, exchange = ticker.split('-')
        else:
            symbol = ticker

        return type, symbol, exchange, currency, expire, multiplier

    @staticmethod
    def parse_contract(ticker):
        """
        Backtrader contract specification (https://www.backtrader.com/docu/live/ib/ib.html):

        TICKER # Stock type and SMART exchange

        TICKER-STK # Stock and SMART exchange

        TICKER-STK-EXCHANGE # Stock

        TICKER-STK-EXCHANGE-CURRENCY # Stock

        TICKER-CFD # CFD and SMART exchange

        TICKER-CFD-EXCHANGE # CFD

        TICKER-CDF-EXCHANGE-CURRENCY # Stock

        TICKER-IND-EXCHANGE # Index

        TICKER-IND-EXCHANGE-CURRENCY # Index

        TICKER-YYYYMM-EXCHANGE # Future

        TICKER-YYYYMM-EXCHANGE-CURRENCY # Future

        TICKER-YYYYMM-EXCHANGE-CURRENCY-MULT # Future

        TICKER-FUT-EXCHANGE-CURRENCY-YYYYMM-MULT # Future

        TICKER-YYYYMM-EXCHANGE-CURRENCY-STRIKE-RIGHT # FOP

        TICKER-YYYYMM-EXCHANGE-CURRENCY-STRIKE-RIGHT-MULT # FOP

        TICKER-FOP-EXCHANGE-CURRENCY-YYYYMM-STRIKE-RIGHT # FOP

        TICKER-FOP-EXCHANGE-CURRENCY-YYYYMM-STRIKE-RIGHT-MULT # FOP

        CUR1.CUR2-CASH-IDEALPRO # Forex

        TICKER-YYYYMMDD-EXCHANGE-CURRENCY-STRIKE-RIGHT # OPT

        TICKER-YYYYMMDD-EXCHANGE-CURRENCY-STRIKE-RIGHT-MULT # OPT

        TICKER-OPT-EXCHANGE-CURRENCY-YYYYMMDD-STRIKE-RIGHT # OPT

        TICKER-OPT-EXCHANGE-CURRENCY-YYYYMMDD-STRIKE-RIGHT-MULT # OPT

        :return: 
        """
        contract_type, symbol, exchange, currency, expire, multiplier = \
            AsyncIBDataProvider.exctract_symbol(ticker)

        if contract_type == 'FX':
            return Forex(pair=symbol)
        if contract_type == 'IND':
            return Index(symbol, exchange, currency)
        if contract_type == 'FUT':
            return Future(symbol,
                          expire,
                          exchange,
                          currency=currency,
                          multiplier=multiplier)
        else:
            return Stock(symbol, exchange, currency)

    def _get_intraday(self, ticker: str, to_date: str, duration: str,
                      barsize: str, rth_only: bool) -> (str, [BarData]):
        to_dt = datetime.strptime(f"{to_date}", '%Y-%m-%d %H:%M')
        contract = AsyncIBDataProvider.parse_contract(ticker)
        whatToShow = 'MIDPOINT' if isinstance(contract,
                                              (Forex, CFD,
                                               Commodity)) else 'TRADES'
        bars = self.ib.reqHistoricalData(contract,
                                         endDateTime=to_dt,
                                         durationStr=duration,
                                         barSizeSetting=barsize,
                                         whatToShow=whatToShow,
                                         useRTH=rth_only,
                                         formatDate=2)
        return contract.symbol, bars

    def _get_daily(self, from_date: str, ticker: str,
                   to_date: str) -> (str, [BarData]):
        #TODO: strip HH:MM from start/end dates?
        from_dt = datetime.strptime(from_date, "%Y-%m-%d")
        today = datetime.strptime(to_date, "%Y-%m-%d")
        to_dt = datetime(today.year, today.month, today.day, 23, 59, 59)
        days = (to_dt - from_dt).days
        if days > 365:
            self.logger.warning(f"Historical data is limited to 365 Days. "
                                f"Only requesting for year '{from_dt.year}'")
            days = 365
            to_dt = datetime(from_dt.year, 12, 31, 23, 59, 59)
        if to_dt > datetime.today():
            to_dt = None

        contract = AsyncIBDataProvider.parse_contract(ticker)
        whatToShow = 'MIDPOINT' if isinstance(contract,
                                              (Forex, CFD,
                                               Commodity)) else 'TRADES'
        # bars = self.ib.reqDailyBars(contract, 2016)
        bars = self.ib.reqHistoricalData(contract,
                                         endDateTime=to_dt,
                                         durationStr=F"{days} D",
                                         barSizeSetting='1 day',
                                         whatToShow=whatToShow,
                                         useRTH=True,
                                         formatDate=1)
        return contract.symbol, bars

    def _to_dataframe(self, bars, tz_fix=False):
        if tz_fix:
            data = [{
                'Date':
                pd.to_datetime(
                    b.date.astimezone(self.tz).replace(tzinfo=None)),
                'Open':
                b.open,
                'High':
                b.high,
                'Low':
                b.low,
                'Close':
                b.close,
                'Volume':
                b.volume
            } for b in bars]
        else:
            data = [{
                'Date': pd.to_datetime(b.date),
                'Open': b.open,
                'High': b.high,
                'Low': b.low,
                'Close': b.close,
                'Volume': b.volume
            } for b in bars]

        if len(data) > 0:
            return pd.DataFrame(data).set_index('Date')
        else:
            return pd.DataFrame()

    def add_quotes(self, data, ticker):
        return data
Beispiel #19
0
class IBDataService:

    ip = "127.0.0.1"
    port = 4002  # 4001 for real trading

    def __init__(self):
        self.uid = random.randint(1000, 10000)
        print(f"init - UID: {str(self.uid)}")
        self.ib = IB()
        self.connect()

    def connect(self, *args):
        print(f"connectToIB - UID: {str(self.uid)}")

        if self.ib.isConnected() is False:
            print("CONNECTING ...")
            self.ib.connect("127.0.0.1", 4002, clientId=self.uid)
            print("CONNECTED")

    def disconnect(self, *args):
        print(f"connectToIB - UID: {str(self.uid)}")

        if self.ib.isConnected():
            print("DISCONNECTING ...")
            self.ib.disconnect()
            print("DISCONNECTED ...")

    def getContractDetail(self, contract):
        print(f"getContractDetail - UID: {str(self.uid)}")
        data = self.ib.reqContractDetails(contract)

        # print(data)

        if len(data) > 0:
            return data[0]
        else:
            return None

    def getFuturesContractDetail(self, contract):
        print(f"getFuturesContractDetail - UID: {str(self.uid)}")
        data = self.ib.reqContractDetails(contract)
        if len(data) > 0:
            return data
        else:
            return None

    def getHistoricalData(self,
                          contract,
                          endDate="",
                          duration="1 Y",
                          barSize="1 day",
                          price="MIDPOINT"):
        print(f"getHistoricalData - UID: {str(self.uid)}")
        data = self.ib.reqHistoricalData(contract, endDate, duration, barSize,
                                         price, 1, 1, False, [])
        return data

    async def startRealtimeData(self, contract, method):
        print(f"startRealtimeData - UID: {str(self.uid)}")

        self.ib.reqMktData(contract, "233", False, False)

        ticker = self.ib.reqTickByTickData(contract, TickDataType.LAST.value)
        ticker.updateEvent += method

        print(f"ENDS - startRealtimeData - UID: {str(self.uid)}")

    def stopRealtimeData(self, contract):
        print(f"stopRealtimeData - UID: {str(self.uid)}")

        self.ib.cancelMktData(contract)
        self.ib.cancelTickByTickData(contract, TickDataType.LAST.value)

        print(f"ENDS - stopRealtimeData - UID: {str(self.uid)}")
Beispiel #20
0
class Basem:
    ''' 导入分钟级别股票信息类
    '''
    def __init__(self):
        self.log   = log(__name__, 'logs/basem.log')
        self.db    = Basedb()
        self.empty = []
        self.total = 0
        self.i     = 0

        self.ib = IB()
        self.ib.connect(Config.ib_host, Config.ib_port, Config.ib_client_id)

    def __del__(self):
        self.ib.disconnect()

    def deal_data(self, future, symbol):
        ''' 回调函数,处理接口返回的股票数据
        '''
        self.i += 1
        print('(%d/%d) 正在导入 %s HK' % (self.i, self.total, symbol), flush=True)

        data = future.result()
        if not data:
            self.empty.append((symbol,))
            return

        open_sql    = 'insert into `open_5m` (`code`, `code_type`, `date`, `value`) values '
        high_sql    = 'insert into `high_5m` (`code`, `code_type`, `date`, `value`) values '
        low_sql     = 'insert into `low_5m` (`code`, `code_type`, `date`, `value`) values '
        close_sql   = 'insert into `close_5m` (`code`, `code_type`, `date`, `value`) values '
        volume_sql  = 'insert into `volume_5m` (`code`, `code_type`, `date`, `value`) values '
        average_sql = 'insert into `average_5m` (`code`, `code_type`, `date`, `value`) values '

        for bar_data in data:
            date       = bar_data.date
            open_price = bar_data.open
            high       = bar_data.high
            low        = bar_data.low
            close      = bar_data.close
            average    = bar_data.average

            # volume 有不存在的情况, 16:00 收市,交易量不存在
            try:
                volume = bar_data.volume
            except AttributeError:
                volume = 0

            open_sql    += "('{code}', '{code_type}', '{date}', {value:.4f}),".format(code=symbol, code_type='hk', date=date, value=open_price)
            high_sql    += "('{code}', '{code_type}', '{date}', {value:.4f}),".format(code=symbol, code_type='hk', date=date, value=high)
            low_sql     += "('{code}', '{code_type}', '{date}', {value:.4f}),".format(code=symbol, code_type='hk', date=date, value=low)
            close_sql   += "('{code}', '{code_type}', '{date}', {value:.4f}),".format(code=symbol, code_type='hk', date=date, value=close)
            volume_sql  += "('{code}', '{code_type}', '{date}', {value}),".format(code=symbol, code_type='hk', date=date, value=volume)
            average_sql += "('{code}', '{code_type}', '{date}', {value:.4f}),".format(code=symbol, code_type='hk', date=date, value=average)

        open_rows    = self.db.query(open_sql.rstrip(','))
        high_rows    = self.db.query(high_sql.rstrip(','))
        low_rows     = self.db.query(low_sql.rstrip(','))
        close_rows   = self.db.query(close_sql.rstrip(','))
        volume_rows  = self.db.query(volume_sql.rstrip(','))
        average_rows = self.db.query(average_sql.rstrip(','))

        if open_rows.rowcount == 0:
            raise RuntimeError('open_sql 语句执行失败:%s' % open_sql)
        elif high_rows.rowcount == 0:
            raise RuntimeError('high_sql 语句执行失败:%s' % high_sql)
        elif low_rows.rowcount == 0:
            raise RuntimeError('low_sql 语句执行失败:%s' % low_sql)
        elif close_rows.rowcount == 0:
            raise RuntimeError('close_sql 语句执行失败:%s' % close_sql)
        elif volume_rows.rowcount == 0:
            raise RuntimeError('volume_sql 语句执行失败:%s' % volume_sql)
        elif average_rows.rowcount == 0:
            raise RuntimeError('average_sql 语句执行失败:%s' % average_sql)
        else:
            pass

    def crawl_data(self, codes):
        ''' 爬取 IB 接口股票的交易信息
        '''
        futures = []
        i = 0
        for code in codes:
            i += 1
            symbol, _ = code
            stock  = Stock(symbol, Config.hk_exchange, Config.hk_currency)
            future = self.ib.reqHistoricalDataAsync(stock, endDateTime='', durationStr='900 S',
                                                    barSizeSetting='5 mins', whatToShow='TRADES', useRTH=True)
            self.ib.sleep(0.02)
            future.add_done_callback(functools.partial(self.deal_data, symbol=symbol))
            futures.append(future)

        return futures

    def get_codes_data(self, codes=None):
        ''' 爬取股票信息
        1个月的5分钟交易信息
        '''
        t1 = time.time()

        # codes => None 则从数据库获取股票列表
        # 否则,使用传递进来的codes list,目的是再次爬取那些空数据的股票
        # 以确保股票数据为空而不会遗漏有数据的股
        # 因为有时连接超时,接口会返回空列表,但此股是有数据的
        if codes is None:
            codes = self.db.get_codes()
            if not codes.rowcount:
                raise RuntimeError('获取股票失败,stock 表返回空.')

        codes      = list(codes)
        self.total = len(codes)
        self.i     = 0

        futures = self.crawl_data(codes)
        self.ib.run(*futures)

        # 爬取完成,记录爬取的endDateTime时间,供下次增量爬取使用
        end_date_time = '2017-12-31 23:59:59'
        res           = self.db.set_record(end_date_time)
        if not res.rowcount:
            raise RuntimeError('记录一个月5分钟的end_date_time失败.')

        t2 = time.time()
        t3 = t2 - t1
        print('HK 股票交易信息全部导入完成,耗时:%.2fs' % t3)
        self.log.info('导入股票信息完成,数据为空的股票有:{}'.format(self.empty))

    def get_hsi_data(self):
        ''' 获取 HSI 一个月5分钟的信息
        '''
        symbol   = 'HSI'
        exchange = 'HKFE'
        currency = 'HKD'
        index    = Index(symbol, exchange, currency)

        data = self.ib.reqHistoricalData(index, endDateTime='20180119 15:00:00', durationStr='900 S',
                                         barSizeSetting='5 mins', whatToShow='TRADES', useRTH=True)
        if not data:
            raise RuntimeError('HSI 数据接口返回空.')

        sql = 'insert into `hsi_5m` (`date`, `open`, `high`, `low`, `close`) values '
        for bar_data in data:
            date       = bar_data.date
            open_price = bar_data.open
            high       = bar_data.high
            low        = bar_data.low
            close      = bar_data.close

            sql += "('{date}', {open:.4f}, {high:.4f}, {low:.4f}, {close:.4f}),".format(date=date, open=open_price, high=high, low=low, close=close)
        res = self.db.query(sql.rstrip(','))

        if res.rowcount == 0:
            raise RuntimeError('SQL 语句执行异常, 插入数据库失败:%s' % sql)
        else:
            print('HSI Index 1个月5分钟数据导入完成.', flush=True)
Beispiel #21
0
def main(symbol):
    # util.logToConsole(logging.DEBUG)
    util.logToFile('log.txt')

    s = symbol.upper()
    click.echo("Options for {} Loading: ".format(s), nl=False)

    ib = IB()
    ib.connect('127.0.0.1', 7497, clientId=3, readonly=True)

    contract = Stock(s, 'SMART', 'USD')
    ib.qualifyContracts(contract)

    click.echo('Chains ', nl=False)
    chains = ib.reqSecDefOptParams(contract.symbol, '', contract.secType,
                                   contract.conId)
    chain = next(c for c in chains if c.exchange == 'SMART')

    click.echo('Price '.format(s), nl=False)
    ib.reqMarketDataType(1)
    [ticker] = ib.reqTickers(contract)
    value = ticker.marketPrice()

    strikes = [
        strike for strike in chain.strikes
        if value * 0.90 < strike < value * 1.0
    ]
    expirations = sorted(exp for exp in chain.expirations)[:2]
    rights = ['P', 'C']

    click.echo("Option Contracts {}@{} ".format(s, value), nl=False)
    contracts = [
        Option(s, expiration, strike, right, 'SMART', tradingClass=s)
        for right in rights for expiration in expirations for strike in strikes
    ]
    click.echo('Validate ', nl=False)
    contracts = ib.qualifyContracts(*contracts)
    click.echo(len(contracts), nl=False)

    ib.reqMarketDataType(4)
    click.echo(' Ticker')
    tickers = ib.reqTickers(*contracts)
    options = []
    for t in tickers:
        # click.echo(t)
        # calc = ib.calculateOptionPrice(
        #       t.contract, volatility=0.14, underPrice=value)
        # print(calc)
        options.append(OptionData(t))

    df = util.df(options, [
        'symbol', 'lastTradeDateOrContractMonth', 'strike', 'right',
        'marketPrice', 'optionYield', 'timeToExpiration', 'spread', 'bid',
        'ask', 'impliedVol', 'delta', 'gamma', 'vega'
    ])
    click.echo(df)

    currentWeekPut = df[(df['right'] == 'P') &
                        (df['lastTradeDateOrContractMonth'] == expirations[0])]

    click.echo(currentWeekPut.loc[(abs(abs(currentWeekPut.delta) -
                                       0.2)).sort_values().index].head(2))

    ib.disconnect()
Beispiel #22
0
class Window(qt.QWidget):
    def __init__(self, host, port, clientId):
        qt.QWidget.__init__(self)
        self.setWindowTitle("Giulio's App")
        self.canvas = MplCanvas()
        # self.edit = qt.QLineEdit('', self)
        # self.edit.editingFinished.connect(self.add)
        self.table = HistoricalTable()
        self.MAList = []
        self.MADict = {}

        self.connectButton = qt.QPushButton('Connect')
        self.connectButton.setStyleSheet(
            "border: 1px solid black; background: white")
        self.connectButton.resize(100, 32)
        self.connectButton.setGeometry(200, 150, 100, 40)
        self.connectButton.clicked.connect(self.onConnectButtonClicked)
        self.displayButton = qt.QPushButton('Display values')
        self.displayButton.setStyleSheet(
            "border: 1px solid black; background: white")
        self.displayButton.resize(100, 32)
        self.displayButton.clicked.connect(self.onDisplayButtonClicked)
        self.cancelAllButton = qt.QPushButton('CancelAll')
        self.cancelAllButton.setStyleSheet(
            "border: 1px solid black; background: white")
        self.cancelAllButton.resize(100, 32)
        self.cancelAllButton.setGeometry(200, 150, 100, 40)
        self.cancelAllButton.clicked.connect(self.onCancelAllButtonClicked)

        layout = qt.QVBoxLayout(self)
        # layout.addWidget(self.edit)
        layout.addWidget(self.table)
        #layout.addWidget(self.canvas)
        layout.addWidget(self.connectButton)
        layout.addWidget(self.cancelAllButton)
        # layout.addStretch(1)
        # self.fig = plt.figure()
        # self.ax = self.fig.add_subplot(1, 1, 1)
        self.xs = []
        self.ys = []
        # layout.addWidget(self.fig)
        self.connectInfo = (host, port, clientId)
        self.ib = IB()
        self.headers = [
            'symbol', 'bidSize', 'bid', 'ask', 'askSize', 'last', 'lastSize',
            'close'
        ]
        self.id = 1
        self.firstSignal = True
        self.isConnectionBroken = False
        self.firstma50 = 0
        self.firstma200 = 0
        self.availableCash = 0
        self.ib.orderStatusEvent += self.order_status_cb
        self.ib.execDetailsEvent += self.exec_details_cb
        self.ib.errorEvent += self.error_cb
        self.ib.accountSummaryEvent += self.accountSummary
        self.ib.pendingTickersEvent += self.onPendingTickers

        # self.ib.pendingTickersEvent += self.table.onPendingTickers

    async def accountSummaryAsync(self, account: str = '') -> \
            List[AccountValue]:
        if not self.wrapper.acctSummary:
            # loaded on demand since it takes ca. 250 ms
            await self.reqAccountSummaryAsync()
        if account:
            return [
                v for v in self.wrapper.acctSummary.values()
                if v.account == account
            ]
        else:
            return list(self.wrapper.acctSummary.values())

    def accountSummary(self, account: str = '') -> List[AccountValue]:
        if (account.tag == 'BuyingPower'):
            logging.info('account buying power - ' + account.value)
            accVal: float = 0.0
            accVal = account.value
            self.availableCash = float(accVal)
            self.availableCash = round(self.availableCash, 2)
            logging.info('available cash - ' + str(self.availableCash))
        logging.info("account summary:: " + str(account.account) + " " +
                     account.tag + " " + account.value)

        return []  #self._run(self.accountSummaryAsync(account))

    def error_cb(self, reqId, errorCode, errorString, contract):
        logging.error("error: " + str(reqId) + " , " + str(errorCode) + " , " +
                      str(errorString))
        logging.error("string - " + str(errorString))
        """if(errorCode == 1100):
            logging.error("Connectivity between IB and TWS has been lost")
            self.isConnectionBroken = True
        if (errorCode == 1300):
            logging.error("socket connection dropped")
            self.isConnectionBroken = True
        if(errorCode == 2105):
            logging.error("HMDS data farm connection is broken")
        if ((errorCode == 2104 or errorCode == 2106) and self.isConnectionBroken == True):
            logging.info("HMDS data farm connection has been restored")
            self.reqData()"""

    def reqGlobalCancel(self):
        """
        Cancel all active trades including those placed by other
        clients or TWS/IB gateway.
        """
        self.ib.reqGlobalCancel()
        logging.info('reqGlobalCancel')

    def order_status_cb(self, trade):
        logging.info("order status for " + str(trade.order.orderId))
        logging.info("Status filled and remaining - " +
                     trade.orderStatus.status + " " +
                     str(trade.orderStatus.filled) + " " +
                     str(trade.orderStatus.remaining))

    def exec_details_cb(self, trade, fill):
        logging.info("exec details for " + fill.contract.symbol +
                     " with orderid " + str(fill.execution.orderId))
        if (fill.execution.side == "Sell"):
            self.availableCash += fill.execution.price

    def onPendingTickers(self, tickers):
        for ticker in tickers:
            logging.info("ticker - " + str(ticker.contract.conId) + " " +
                         str(ticker.contract.secType) + " " +
                         ticker.contract.symbol + " " +
                         ticker.contract.currency)
            for col, header in enumerate(self.headers):
                if col == 0:
                    continue
                val = getattr(ticker, header)
                symbol = ticker.contract.symbol + (ticker.contract.currency
                                                   if ticker.contract.secType
                                                   == 'CASH' else '')
                ma = self.MADict[symbol]
                logging.info("Values - " + str(ticker.contract.secType) + " " +
                             str(ticker.contract.conId) + " " + symbol + " " +
                             str(header) + " " + str(col) + " val- " +
                             str(val))
                if (str(header) == 'bid'):
                    ma.bid = val
                if (str(header) == 'ask'):
                    ma.ask = val

    def onBarUpdate(self, bars, hasNewBar):
        self.xs.append(dt.datetime.now().strftime('%H:%M:%S.%f'))
        # logging.debug("bar update " + str(hasNewBar) + " for " + str(bars.reqId))
        logging.info(bars[-1])
        symbol = bars.contract.symbol + (
            bars.contract.currency if bars.contract.secType == 'CASH' else '')
        ma = self.MADict[symbol]
        logging.info("update for " + ma.symbol)
        df = util.df(bars)
        # logging.debug(df)
        ma.setMAs(df)
        ma50 = ta.MA(df['close'], 50)
        ma200 = ta.MA(df['close'], 200)
        self.ys.append(ma50)

        self.xs = self.xs[-50:]
        self.ys = self.ys[-50:]

        # self.ax.clear()
        # self.ax.plot(self.xs, self.ys)
        plt.xticks(rotation=45, ha='right')
        plt.subplots_adjust(bottom=0.30)
        plt.title('50MA')
        plt.ylabel('MA')
        """logging.debug("ma50")
        logging.debug(ma50)
        logging.debug("ma200")
        logging.debug(ma200)
        logging.debug("last items")
        logging.debug(ma50.tail(1).item())
        logging.debug(ma200.tail(1).item())"""
        orderList = ma.checkGCDC()
        if (orderList is not None):
            orderQuantity = 0
            for order in orderList:
                if (order.orderType == "LMT"):
                    if (order.action == "Buy"):
                        order.totalQuantity = 1000  #(self.availableCash/ma.bid) * .01
                        self.availableCash -= (order.totalQuantity *
                                               order.trailStopPrice)
                        logging.info("Placing buy order for " + ma.symbol +
                                     " " + str(ma.bid) + " with orderId " +
                                     str(order.orderId))
                    else:
                        order.totalQuantity = 1000  #(self.availableCash/ma.ask) * .01
                        logging.info("Placing sell order for " + ma.symbol +
                                     " at " + str(ma.ask) + " with orderId " +
                                     str(order.orderId))
                    orderQuantity = order.totalQuantity
                else:
                    if (order.orderType == "TRAIL"):
                        order.totalQuantity = orderQuantity
                        if (order.action == "Buy"):
                            #order.totalQuantity = (self.availableCash / ma.bid) * .01
                            self.availableCash -= (order.totalQuantity *
                                                   order.trailStopPrice)
                            logging.info("Placing buy order for " + ma.symbol +
                                         " " + str(ma.bid) + " with orderId " +
                                         str(order.orderId))
                        else:
                            #order.totalQuantity = (self.availableCash / ma.ask) * .01
                            logging.info("Placing sell order for " +
                                         ma.symbol + " at " + str(ma.ask) +
                                         " with orderId " + str(order.orderId))

                        logging.info("Placing " + order.action +
                                     " order for " + ma.symbol + " at " +
                                     str(order.trailStopPrice) + " " +
                                     str(ma.ask) + " with orderId " +
                                     str(order.orderId) + " " +
                                     str(trade.order.orderId))
                trade = self.ib.placeOrder(bars.contract, order)

        if (ma.isOrderActive == False and ma.GCCheck == True):
            logging.info("order is not active and gccheck is true")
        self.MADict[symbol] = ma
        """if (ma.firstSignal == True):
            ma.firstma50 = round(ma50.tail(1).item(), 6)
            ma.firstma200 = round(ma200.tail(1).item(), 6)
            ma.firstSignal = False
            if (ma.firstma50 < ma.firstma200):
                logging.info("checking golden cross for " + ma.symbol + " : mas - " + str(ma.firstma50) + " " + str(ma.firstma200))
            else:
                logging.info("checking death cross for " + ma.symbol + " : mas - " + str(ma.firstma50) + " " + str(ma.firstma200))
                ma.GCCheck = False
                self.MADict[symbol] = ma
        else:
            prevma50 = ma.getMa50()
            prevma200 = ma.getMa200()
            currma50 = round(ma50.tail(1).item(), 6)
            currma200 = round(ma200.tail(1).item(), 6)
            if(ma.isOrderActive == False):
                if(ma.GCCheck == True):
                    logging.info("golden cross check for " + ma.symbol)
                    logging.info("prev mas - " + str(prevma50) + " " + str(prevma200))
                    logging.info("curr mas - " + str(currma50) + " " + str(currma200))
                    logging.info("curr bid and ask vals - " + str(ma.bid) + " " + str(ma.ask))
                    if((prevma50 <= prevma200) and (currma50 > currma200)):
                        logging.info(("golden cross occured for " + ma.symbol))
                        ma.GCCheck = False
                        if(ma.isOrderActive == False):
                            ma.isOrderActive = True
                            order = TrailOrder("Buy", 1000, ma.ask, 20)
                            trade = self.ib.placeOrder(bars.contract, order)
                            logging.info("Placing buy order for " + ma.symbol + " at " + str(order.trailStopPrice) + " " + str(ma.ask) + " with orderId " + str(order.orderId) + " " + str(trade.order.orderId))
                        self.MADict[symbol] = ma

                else:
                    logging.info("death cross check for " + ma.symbol)
                    logging.info("prev mas - " + str(prevma50) + " " + str(prevma200))
                    logging.info("curr mas - " + str(currma50) + " " + str(currma200))
                    if ((prevma50 >= prevma200) and (currma50 < currma200)):
                        logging.info(("death cross occured for " + ma.symbol))
                        ma.GCCheck = True
                        if (ma.isOrderActive == False):
                            ma.isOrderActive = True
                            order = TrailOrder("Sell", 1000, ma.bid, 20)
                            trade = self.ib.placeOrder(bars.contract, order)
                            logging.info("Placing sell order for " + ma.symbol + " at " + str(ma.bid) + " with orderId " + str(trade.order.orderId))
                        self.MADict[symbol] = ma """

        ma.setMa50(round(ma50.tail(1).item(), 6))
        ma.setMa200(round(ma200.tail(1).item(), 6))
        self.MADict[symbol] = ma

        logging.debug("MAs for " + str(bars.contract.secType) + " " +
                      str(bars.contract.symbol) + " " +
                      bars.contract.currency + " , reqid: " + str(bars.reqId) +
                      " " + str(ma50.values[-1]) + " " +
                      str(ma200.values[-1]) + " : " +
                      str(ma50.tail(1).item()) + " " +
                      str(ma200.tail(1).item()))
        self.table.updateData(bars.reqId, round(ma50.tail(1).item(), 6),
                              round(ma200.tail(1).item(), 6))
        # logging.debug(ma50.values[-1])
        # plt.close()
        # plot = util.barplot(bars)
        # clear_output(wait=True)
        # display(plot)

    def add_historical(self, text=''):
        logging.debug("text - " + text)
        logger.debug("logging")
        text = text or self.edit.text()
        if text:
            logging.debug('eval text ')  # + eval(text))
            contract = eval(text)
            logging.debug("requesting historical and mkt data for " + text)
            bars = self.ib.reqHistoricalData(contract,
                                             endDateTime='',
                                             durationStr='2000 S',
                                             barSizeSetting='10 secs',
                                             whatToShow='MIDPOINT',
                                             useRTH=True,
                                             formatDate=1,
                                             keepUpToDate=True)
            ticker = self.ib.reqMktData(contract, '', False, False, None)
            logging.info(bars[-1])
            logging.debug("sectype " + str(bars.reqId) + " " +
                          str(bars.contract.conId) + " " +
                          bars.contract.secType + " " + bars.contract.symbol +
                          " " + bars.contract.currency)
            self.table.addHistoricalData(bars.reqId, contract)
            df = util.df(bars)
            # with pd.option_context('display.max_rows', None, 'display.max_columns',
            #                       None):  # more options can be specified also
            #    logging.debug(df)
            close = pd.DataFrame(df, columns=['close'])
            logging.debug("close ")
            logging.debug(close)
            # df['pandas_SMA_3'] = df.iloc[:, 1].rolling(window=3).mean()
            # df.head()

            #ma50 = ta.MA(df['close'], 50)
            #ma200 = ta.MA(df['close'], 200)
            symbol = bars.contract.symbol + (bars.contract.currency
                                             if bars.contract.secType == 'CASH'
                                             else '')
            logging.info("symbol - " + symbol)
            ma = MovingAverages(
                self.ib, symbol, bars.reqId
            )  #, round(ma50.tail(1).item(), 6), round(ma200.tail(1).item(), 6))
            ma.setMAs(df)
            self.MAList.append(ma)
            self.MADict[symbol] = ma
            """logging.debug("ma50")
            logging.debug(ma50)
            logging.debug("ma200")
            logging.debug(ma200)
            logging.debug("initial ma vals for " + symbol)
            logging.debug(ma50.tail(1).item())
            logging.debug(ma200.tail(1).item())"""
            self.table.updateData(bars.reqId, round(ma.ma50.tail(1).item(), 6),
                                  round(ma.ma200.tail(1).item(), 6))
            # sma = pd.SMA(df['close'].values, timeperiod=4)
            """portfolio = self.ib.portfolio()#.wrapper.portfolio.cash = 10000
            logging.debug("portfolio")
            logging.debug(portfolio)
            positions = self.ib.positions()
            logging.debug("positions")
            for x in range(len(positions)):
                logging.debug(positions[x].contract.symbol)
                logging.debug(positions[x].position)"""
            # logging.debug(positions)
            bars.updateEvent += self.onBarUpdate
            logging.debug("reqid is " + str(bars.reqId) + " for " +
                          bars.contract.symbol + " " + bars.contract.currency +
                          " , sectype - " + bars.contract.secType)

    def onDisplayButtonClicked(self, _):
        logging.debug("MA values")
        for ma in self.MAList:
            logging.debug("symbol - " + " " + ma.symbol)
            logging.debug(
                str(ma.firstma50) + " " + str(ma.firstma200) + " " +
                str(ma.firstSignal) + " " + str(ma.ma50) + " " + str(ma.ma200))
        for x in self.MADict:
            logging.debug(x)
        for x in self.MADict.values():
            logging.debug("dict values - " + str(x.firstSignal) + " " +
                          x.symbol + " " + str(x.firstma50) + " " +
                          str(x.firstma200) + " " + str(x.ma50) + " " +
                          str(x.ma200))

    def onConnectButtonClicked(self, _):
        logging.debug("isconnected: " + str(self.ib.isConnected()))
        if self.ib.isConnected():
            self.ib.disconnect()
            logging.debug("clearing data")
            self.table.clearData()
            self.connectButton.setText('Connect')
            logging.debug("done")
        else:
            logging.debug("trying to connect")
            # ib = IB()
            # ib.connect('127.0.0.1', 7497, clientId=3)
            self.ib.connect('127.0.0.1', 7497,
                            clientId=2)  # *self.connectInfo)
            logging.debug("connected - ")  # + self.ib.isConnected())
            # self.ib.reqMarketDataType(2)
            self.connectButton.setText('Disconnect')
            self.ib.reqAccountSummary()
            self.reqData()

    def onCancelAllButtonClicked(self):
        logging.info("Cancelling all open orders")
        #self.ib.connect('127.0.0.1', 7497, clientId=2)  # *self.connectInfo)
        self.reqGlobalCancel()

    def reqData(self):
        #self.reqGlobalCancel()
        """for symbol in ('EURUSD', 'USDJPY', 'EURGBP', 'USDCAD',
                       'EURCHF', 'AUDUSD', 'NZDUSD'):
            logging.debug("requesting for " + symbol)
            self.add_historical(f"Forex('{symbol}')")"""
        #self.add_historical("Stock('TSLA', 'SMART', 'USD')")
        #self.add_historical("Stock('IBM', 'SMART', 'USD')")
        #self.add_historical("Stock('MSFT', 'SMART', 'USD')")
        self.add_historical("Stock('FB', 'SMART', 'USD')")

    def closeEvent(self, ev):
        logging.debug("closing")
        asyncio.get_event_loop().stop()
Beispiel #23
0
class request(IB):
    def __init__(self, symbol, temp, client):
        self.symbol = symbol
        self.temp = temp
        instruments = pd.read_csv('instruments.csv').set_index('symbol')
        self.params = instruments.loc[self.symbol]
        self.market = str(self.params.market)
        self.exchange = str(self.params.exchange)
        self.tick_size = float(self.params.tick_size)
        self.digits = int(self.params.digits)
        self.leverage = int(self.params.leverage)
        self.client = client
        self.current_date()
        self._sundays_activation()
        self.ib = IB()
        print(self.ib.connect('127.0.0.1', 7497, self.client))
        self.connected = self.ib.isConnected()  #######
        self.get_contract()
        self.interrumption = False
        #self.data = self.download_data(tempo=temp, duration='1 D')
        #self.ib.reqMktData(self.contract, '', False, False); self.ticker = self.ib.ticker(self.contract)  #########
        #self.ticker = self.ib.reqTickByTickData(self.contract, 'Last', 0)
        self.bars = self.ib.reqRealTimeBars(self.contract, 5, 'MIDPOINT',
                                            False)
        self.operable = True

    def operable_schedule(self):
        if self.weekday == 4 and pd.to_datetime(
                self.hour).time() > pd.to_datetime('18:00:00').time():
            print('%s %s | Today is Friday and Market has Closed!' %
                  (self.date, self.hour))
            self.operable = False
        elif self.weekday == 5:
            print('%s %s | Today is Saturday and market is not Opened' %
                  (self.date, self.hour))
            self.operable = False
        else:
            self.operable = True

    def current_date(self):
        self.date = datetime.now().strftime('%Y-%m-%d')
        self.weekday = datetime.now().weekday()
        self.hour = datetime.now().strftime('%H:%M:%S')

    def _sundays_activation(self):
        hour = '18:00:05'
        if self.weekday == 6:
            if pd.to_datetime(self.hour).time() < pd.to_datetime(hour).time():
                print('Today is Sunday. Bot activation is at 18:00:00')
                while True:
                    self.current_date()
                    if pd.to_datetime(
                            self.hour).time() >= pd.to_datetime(hour).time():
                        print('Activation Done')
                        self.send_telegram_message(
                            '%s %s | Bot Activation Done' %
                            (self.date, self.hour))
                        break

    def continuous_check_message(self, message):
        if datetime.now().minute == 0 and datetime.now().second == 0:
            self.send_telegram_message(message, type='info')

    def reconnection(self):
        if self.hour == '23:44:30' or self.hour == '16:59:30':
            self.interrumption = True
            self.ib.disconnect()
            self.connected = self.ib.isConnected()
            print('%s %s | Ib disconnection' % (self.date, self.hour))
            print('Connected: %s' % self.connected)
        if self.hour == '23:46:00' or self.hour == '18:00:05':
            self.interrumption = False
            print('%s %s | Reconnecting...' % (self.date, self.hour))
            while not self.connected:
                try:
                    self.ib.connect('127.0.0.1', 7497, self.client)
                    self.connected = self.ib.isConnected()
                    if self.connected:
                        print('%s %s | Connection reestablished!' %
                              (self.date, self.hour))
                        print('Requesting Market Data...')
                        self.bars = self.ib.reqRealTimeBars(
                            self.contract, 5, 'MIDPOINT', False)
                        print('Last Close of %s: %.2f' %
                              (self.symbol, self.bars[-1].close))
                        print('%s Data has been Updated!' % self.symbol)
                except:
                    print(
                        '%s %s | Connection Failed! Trying to reconnect in 10 seconds...'
                        % (self.date, self.hour))
                    self.ib.sleep(10)
            print('%s %s | %s Data has been Updated!' %
                  (self.date, self.hour, self.symbol))

    def _local_symbol_selection(self):
        '''Selects local symbol according to symbol and current date'''
        current_date = datetime.now().date()
        # csv file selection according to symbol
        if self.symbol in ['ES', 'RTY', 'NQ', 'MES', 'MNQ', 'M2K']:
            contract_dates = pd.read_csv(
                'D:/Archivos/futuro/Algorithmics/Codes/My_Bots/Hermes/contract_dates/indexes_globex.txt',
                parse_dates=True)
        elif self.symbol in ['YM', 'MYM', 'DAX']:
            contract_dates = pd.read_csv(
                'D:/Archivos/futuro/Algorithmics/Codes/My_Bots/Hermes/contract_dates/indexes_ecbot_dtb.txt',
                parse_dates=True)
        elif self.symbol in ['QO', 'MGC']:
            contract_dates = pd.read_csv(
                'D:/Archivos/futuro/Algorithmics/Codes/My_Bots/Hermes/contract_dates/QO_MGC.txt',
                parse_dates=True)
        elif self.symbol in ['CL', 'QM']:
            contract_dates = pd.read_csv(
                'D:/Archivos/futuro/Algorithmics/Codes/My_Bots/Hermes/contract_dates/CL_QM.txt',
                parse_dates=True)
        else:
            contract_dates = pd.read_csv(
                'D:/Archivos/futuro/Algorithmics/Codes/My_Bots/Hermes/contract_dates/%s.txt'
                % symbol,
                parse_dates=True)

        # Current contract selection according to current date
        for i in range(len(contract_dates)):
            initial_date = pd.to_datetime(
                contract_dates.iloc[i].initial_date).date()
            final_date = pd.to_datetime(
                contract_dates.iloc[i].final_date).date()
            if initial_date <= current_date <= final_date:
                current_contract = contract_dates.iloc[i].contract
                break

        # local symbol selection
        local = current_contract
        if self.symbol in [
                'ES', 'RTY', 'NQ', 'MES', 'MNQ', 'M2K', 'QO', 'CL', 'MGC', 'QM'
        ]:
            local = '%s%s' % (self.symbol, current_contract)
        if self.symbol in ['YM', 'ZS']:
            local = '%s   %s' % (self.symbol, current_contract)
        if self.symbol == 'MYM':
            local = '%s  %s' % (self.symbol, current_contract)
        if self.symbol == 'DAX': local = 'FDAX %s' % current_contract

        return local

    def get_contract(self):
        if self.market == 'futures':
            local = self._local_symbol_selection()
            self.contract = Future(symbol=self.symbol,
                                   exchange=self.exchange,
                                   localSymbol=local)
            print(
                self.ib.reqContractDetails(
                    self.contract)[0].contract.lastTradeDateOrContractMonth)
            '''expiration = self.ib.reqContractDetails(Future(self.symbol,self.exchange))[0].contract.lastTradeDateOrContractMonth
            self.contract = Future(symbol=self.symbol, exchange=self.exchange, lastTradeDateOrContractMonth=expiration)'''
        elif self.market == 'forex':
            self.contract = Forex(self.symbol)
        elif self.market == 'stocks':
            self.contract = Stock(symbol=self.symbol,
                                  exchange=self.exchange,
                                  currency='USD')

    def download_data(self, tempo, duration):
        pr = (lambda market: 'MIDPOINT'
              if market == 'forex' else 'TRADES')(self.market)
        historical = self.ib.reqHistoricalData(self.contract,
                                               endDateTime='',
                                               durationStr=duration,
                                               barSizeSetting=tempo,
                                               whatToShow=pr,
                                               useRTH=False,
                                               keepUpToDate=False)
        return historical

    def send_telegram_message(self, message, type='trades'):
        bot_token = '1204313430:AAGonra1LaFhyI1gCVOHsz8yAohJUeFgplo'
        bot_chatID = '-499850995' if type == 'trades' else '-252750334'
        url = 'https://api.telegram.org/bot%s/sendMessage?chat_id=%s&text=%s' % (
            bot_token, bot_chatID, message)

        requests.get(url)
Beispiel #24
0
class ArbitrageOnSymbol():
    def __init__(self, args):
        super(ArbitrageOnSymbol, self).__init__()
        print('ArbitrageOnSymbol__init__: ', args[0], args[1], args[2])
        # time.sleep(1)
        self.symbol = args[0]
        self.exchange = args[1]
        self.clientId = args[2]
        self.ib_server = args[3]
        self.ib_port = args[4]
        self.file_path = args[5]
        #
        self.is_refresh_source = False
        self.is_refresh = False
        #
        self.Storage = self.file_path + '/Storage_' + self.symbol
        self.Storage_ = self.file_path + '/Storage__' + self.symbol
        #self.data = self.get_data()
        #
        self.start_time = time.perf_counter()
        self.amount_of_arbitrages = 0
        self.test_counter = 0
        #asyncio.set_event_loop(asyncio.new_event_loop())

        loop = asyncio.get_event_loop_policy().new_event_loop()
        asyncio.set_event_loop(loop)
        self.ib_ = IB()
        self.data = None
        print('End ArbitrageOnSymbol__init__: ', args[0], args[1], args[2])

    # pull data and store locally
    def fetch_possible_contract(self, right='C'):
        print('fetch_possible_contract------ 1')
        print(right, ' ', self.symbol)
        o = Option(symbol=self.symbol, right=right, exchange=self.exchange)
        # print('fetch_possible_contract 1: ', self.symbol, ' ', right)
        o_cd = self.ib_.reqContractDetails(o)
        # print('fetch_possible_contract 2: ', self.symbol, ' ', right)
        cs = [j.contract for j in o_cd]
        print('fetch_possible_contract------ 2')
        print('Done: ', right, ' ', self.symbol)
        print('fetch_possible_contract------ 3')
        return cs

    def fetch_possible_contracts(self):
        # loop = asyncio.get_event_loop()

        #loop = asyncio.get_event_loop_policy().new_event_loop()
        #asyncio.set_event_loop(loop)

        try:
            print('fetch_possible_contracts 1')
            self.ib_.connect(self.ib_server,
                             self.ib_port,
                             clientId=self.clientId)
            print('fetch_possible_contracts 2')
            print(self.ib_)
            #####
            print('fetch_possible_contracts 3')
            c = self.fetch_possible_contract('C')
            p = self.fetch_possible_contract('P')
            print('fetch_possible_contracts 4')

            possible_contracts = {'C': c, 'P': p}
            if os.path.exists(self.Storage):
                os.remove(self.Storage)
            with open(self.Storage, 'wb') as f:
                pickle.dump(possible_contracts, f)
            print('fetch_possible_contracts 5')

            return possible_contracts
            #####
        except KeyboardInterrupt:
            pass
        finally:
            print("ib_.disconnect")
            # self.ib_.disconnect()
            print("Closing Loop")
            #loop.close()

    # fetching the data
    def get_possible_contracts(self):
        print('get_possible_contracts 1')
        with open(self.Storage, 'rb') as f:
            return pickle.load(f)

    def convert_data(self):
        if os.path.exists(self.Storage_):
            os.remove(self.Storage_)
        data = {}
        data_ = self.get_possible_contracts(
        )  # for every right (C or P) we have list of contract
        print('convert_data - 1')
        data['C'] = self.get_data_('C', data_['C'])
        data['P'] = self.get_data_('P', data_['P'])
        with open(self.Storage_, 'wb') as f:
            pickle.dump(data, f)
        print('convert_data - 2')
        return data

    # Create three dictionaries
    # cs = strikes for each contract period
    # cc_c = contracts for each contract period
    # bf = possible butterfly
    def get_data_(self, right, data):
        print('---------------------')
        print('-----get_data_--------', right)
        print('---------------------')
        cs = {}  # strikes for each contract period
        cs0 = {}  # strikes for each contract period
        for i in data:
            h = i.lastTradeDateOrContractMonth
            if h not in cs:
                cs[h] = {
                    'strikes': {
                        str(i.strike): {
                            'event': None,
                            'bid': 0,
                            'bidSize': 0,
                            'ask': 0,
                            'askSize': 0,
                            'close': 0,
                            'price': 0,
                            'undPrice': 0,
                            'contract': i
                        }
                    },
                    'strategies': []
                }
                cs0[h] = [i.strike]
            else:
                cs[h]['strikes'][str(i.strike)] = {
                    'event': None,
                    'bid': 0,
                    'bidSize': 0,
                    'ask': 0,
                    'askSize': 0,
                    'close': 0,
                    'price': 0,
                    'undPrice': 0,
                    'contract': i
                }
                cs0[h].append(i.strike)
        for h in cs0:
            cs0[h] = sorted(cs0[h])
            oo = cs0[h]
            pp = []
            for v in range(1, len(oo)):
                pp.append(float(oo[v]) - float(oo[v - 1]))
            dd1 = []
            for pi in pp:
                if pi not in dd1:
                    dd1.append(pi)
            dd1 = sorted(dd1)
            df = int(max(oo) / min(dd1))
            dd = []
            for d1 in dd1:
                for f in range(1, df):
                    dk = d1 * f
                    if dk not in dd:
                        dd.append(dk)
            for d in dd:
                for v in range(1, len(oo)):
                    if ((oo[v] + d) in oo) and ((oo[v] - d) in oo):
                        k = ((oo[v] - d), oo[v], (oo[v] + d))
                        cs[h]['strategies'].append(k)
        print('End ---------------------')
        print('-----get_data_--------', right)
        print('End ---------------------')
        return cs

    # end fetching the data

    # run the algo trading
    def run(self):
        print("run 1: Process for {}".format(self.symbol))
        self.data = self.get_data()
        print("run 2: Process for {}".format(self.symbol))
        #loop = asyncio.get_event_loop()

        #loop = asyncio.get_event_loop_policy().new_event_loop()
        #asyncio.set_event_loop(loop)
        loop = asyncio.get_event_loop()
        print(loop)
        print("run 3: Process for {}".format(self.symbol))
        while True:
            print("run 1 While Loop", ' ', self.symbol)
            try:
                print("run 2 While Loop", ' ', self.symbol)
                self.ib_.connect(self.ib_server,
                                 self.ib_port,
                                 clientId=self.clientId)
                print("run 3 While Loop", ' ', self.symbol)
                print(self.ib_)

                #####
                # kk = '20190802'
                # self.objects_.append(ArbitrageOnContract('C', kk, self.data['C'][kk], loop, self))
                #####
                loop.create_task(self.main())
                loop.run_forever()
            except KeyboardInterrupt:
                pass
            finally:
                print("finally Closing Loop", ' ', self.symbol)
                self.ib_.disconnect()
        loop.close()

    async def main(self):
        print('main 1 ', self.symbol)
        for contracts_right in self.data:
            # print('main ', contracts_right)
            for contract_date in self.data[contracts_right]:
                await asyncio.sleep(0)
                contracts_data = self.data[contracts_right][contract_date]
                print(contract_date)
                s = asyncio.ensure_future(
                    self.running(contracts_right, contract_date,
                                 contracts_data, self.exchange))

    def get_data(self):
        with open(self.Storage_, 'rb') as f:
            return pickle.load(f)

    async def running(self, contracts_right, contract_date, contracts_data,
                      exchange):
        # print(self.symbol, ': ', contracts_right, ' - running - ', contract_date, '\n',contracts_data,'\n',exchange)
        # await asyncio.sleep(1)
        start_inner_time = time.perf_counter()
        price_tasks = []
        for s in contracts_data['strikes']:
            contracts_data['strikes'][s]['event'] = asyncio.Event()
            contracts_data['strikes'][s]['price'] = 0
            c = contracts_data['strikes'][s]['contract']
            o_price_fut = asyncio.ensure_future(self.ib_.reqTickersAsync(c))
            price_task = asyncio.ensure_future(
                self.add_success_callback(o_price_fut, self.put_price_in_array,
                                          contracts_data))
            price_tasks.append(price_task)
        self.get_legs_arrived_tasks(contracts_right, contract_date,
                                    contracts_data, exchange)
        results = await asyncio.gather(*price_tasks)

        end_time = time.perf_counter()
        #print('End of running ', contracts_right, ' ', contract_date, ' Time of running: ',
        #      end_time-start_inner_time, ' ', ' Total time:', end_time-self.start_time, 'Prices:\n', results)
        await self.running(contracts_right, contract_date, contracts_data,
                           exchange)

    async def add_success_callback(self, fut, callback, *args, **kwargs):
        result = await fut
        result = callback(result, *args, **kwargs)
        return result

    async def get_legs_arrived_task(self, strategy, contracts_right,
                                    contract_date, contracts_data, exchange):
        await contracts_data['strikes'][str(strategy[0])]['event'].wait()
        await contracts_data['strikes'][str(strategy[1])]['event'].wait()
        await contracts_data['strikes'][str(strategy[2])]['event'].wait()
        await self.calculate_butterfly(strategy, contracts_right,
                                       contract_date, contracts_data, exchange)
        return strategy

    def get_legs_arrived_tasks(self, contracts_right, contract_date,
                               contracts_data, exchange):
        legs_arrived_tasks = []
        # print(contracts_data)
        # await asyncio.sleep(1)
        for strategy in contracts_data['strategies']:
            task = asyncio.ensure_future(
                self.get_legs_arrived_task(strategy, contracts_right,
                                           contract_date, contracts_data,
                                           exchange))
            legs_arrived_tasks.append(task)
        return legs_arrived_tasks

    # From here need to fix
    def put_price_in_array(self, ticker, contracts_data):
        try:
            t = ticker[0]
            #print('t0----')
            #print(t)
            #print('--0000---')
            #print(t.bidGreeks)
            #print('---11111---')
            #print(t.bidGreeks.undPrice)
            #print('t2222----')

            p = (t.ask + t.bid) / 2

            contracts_data['strikes'][str(t.contract.strike)]['bid'] = t.bid
            contracts_data['strikes'][str(
                t.contract.strike)]['bidSize'] = t.bidSize
            contracts_data['strikes'][str(t.contract.strike)]['ask'] = t.ask
            contracts_data['strikes'][str(
                t.contract.strike)]['askSize'] = t.askSize
            contracts_data['strikes'][str(
                t.contract.strike)]['close'] = t.close

            contracts_data['strikes'][str(t.contract.strike)]['price'] = p
            # print(contracts_data['strikes'][str(t.contract.strike)])

            contracts_data['strikes'][str(
                t.contract.strike)]['undPrice'] = t.bidGreeks.undPrice

            contracts_data['strikes'][str(t.contract.strike)]['event'].set()
            return p
        except Exception as e:
            print('=======ERRORR==============="')
            print(e)
            print('=======End ERRORR==============="')

    # need to improve.
    async def calculate_butterfly(self, strategy, contracts_right,
                                  contract_date, contracts_data, exchange):
        l = contracts_data['strikes'][str(strategy[0])]['ask']
        m = contracts_data['strikes'][str(strategy[1])]['bid']
        r = contracts_data['strikes'][str(strategy[2])]['ask']
        u0 = contracts_data['strikes'][str(strategy[0])]['undPrice']
        u1 = contracts_data['strikes'][str(strategy[1])]['undPrice']
        u2 = contracts_data['strikes'][str(strategy[2])]['undPrice']

        # print('u0: ', u0, 'u1: ', u1,'u2: ', u2)

        strategy_price = 999
        if l > -1 and m > -1 and r > -1:
            strategy_price = (l + r) - (2 * m)
            #if strategy_price < 100:
            #    await self.place_arbitrage(strategy, strategy_price, contracts_data, exchange)
            #    self.amount_of_arbitrages += 1
            if strategy_price < 0.09:
                await self.log_to_db(strategy, contracts_right, contract_date,
                                     contracts_data, strategy_price)
        return strategy_price

    # need to fix
    async def place_arbitrage(self, strategy, strategy_price, contracts_data,
                              exchange):
        for s in contracts_data['strikes']:
            c = contracts_data['strikes'][s]['contract']
            if c.strike == strategy[0]:
                lc = c
            elif c.strike == strategy[1]:
                mc = c
            elif c.strike == strategy[2]:
                rc = c

        # x = [lc, mc, rc]
        # x1 = self.ib_.qualifyContracts(x)

        #self.ib_.qualifyContracts(mc)
        #self.ib_.qualifyContracts(rc)

        combo_legs = [
            ComboLeg(conId=lc.conId, ratio=1, action='BUY', exchange=exchange),
            ComboLeg(conId=mc.conId, ratio=2, action='SELL',
                     exchange=exchange),
            ComboLeg(conId=rc.conId, ratio=1, action='BUY', exchange=exchange),
        ]

        c = Contract(symbol=self.parent.symbol,
                     secType='BAG',
                     exchange=exchange,
                     currency='USD',
                     comboLegs=combo_legs)

        o = MarketOrder(action='BUY', totalQuantity=1000)

        # lo = LimitOrder(action='BUY', totalQuantity=1, lmtPrice=strategy_price)

        if self.test_counter < 3:
            # t = self.ib_.placeOrder(contract=c, order=o)
            print('------100')
            print('place_arbitrage: order issued ', strategy, strategy_price)
            print(c)
            print('------100')

            # print(t)
            self.test_counter += 1

    async def log_to_db(self, strategy, contracts_right, contract_date,
                        contracts_data, strategy_price):
        # print('log_to_db: ', contracts_right, contract_date, ' ', strategy, ' ', strategy_price)
        lstrike = round(float(strategy[0]), 2)
        lb = round(contracts_data['strikes'][str(strategy[0])]['bid'], 2)
        lbs = contracts_data['strikes'][str(strategy[0])]['bidSize']
        la = round(contracts_data['strikes'][str(strategy[0])]['ask'], 2)
        las = contracts_data['strikes'][str(strategy[0])]['askSize']
        lc = round(contracts_data['strikes'][str(strategy[0])]['close'], 2)
        lp = round(contracts_data['strikes'][str(strategy[0])]['price'], 2)
        lu = round(contracts_data['strikes'][str(strategy[0])]['undPrice'], 2)

        rstrike = float(strategy[2])
        rb = round(contracts_data['strikes'][str(strategy[2])]['bid'], 2)
        rbs = contracts_data['strikes'][str(strategy[2])]['bidSize']
        ra = round(contracts_data['strikes'][str(strategy[2])]['ask'], 2)
        ras = contracts_data['strikes'][str(strategy[2])]['askSize']
        rc = round(contracts_data['strikes'][str(strategy[2])]['close'], 2)
        rp = round(contracts_data['strikes'][str(strategy[2])]['price'], 2)
        ru = round(contracts_data['strikes'][str(strategy[2])]['undPrice'], 2)

        mstrike = float(strategy[1])
        mb = round(contracts_data['strikes'][str(strategy[1])]['bid'], 2)
        mbs = contracts_data['strikes'][str(strategy[1])]['bidSize']
        ma = round(contracts_data['strikes'][str(strategy[1])]['ask'], 2)
        mas = contracts_data['strikes'][str(strategy[1])]['askSize']
        mc = round(contracts_data['strikes'][str(strategy[1])]['close'], 2)
        mp = round(contracts_data['strikes'][str(strategy[1])]['price'], 2)
        mu = round(contracts_data['strikes'][str(strategy[1])]['undPrice'], 2)

        #print('==========================================')
        #print('lb: ', lb, ' lbs: ', lbs, ' la: ', la, ' las: ', las, ' lc: ', lc , ' lp: ',  lp , ' lu: ', lu)
        #print('rb: ', rb, ' rbs: ', rbs, ' ra: ', ra, ' ras: ', ras, ' rc: ', rc , ' rp: ',  rp , ' ru: ', ru)
        #print('mb: ', mb, ' mbs: ', mbs, ' ma: ', ma, ' mas: ', mas, ' mc: ', mc , ' mp: ',  mp , ' mu: ', mu)
        #print('-----------------+++++++++++++++++++++++++++++----------------------------------')

        try:
            PlacedOrders.objects.create(Right=contracts_right,
                                        Ticker=self.symbol,
                                        ContractDate=contract_date,
                                        LeftStrike=lstrike,
                                        LeftOrderAskPrice=la,
                                        LeftOrderBidPrice=lb,
                                        LeftOrderAveragePrice=lp,
                                        LeftOrderClose=lc,
                                        LeftOrderBidSize=lbs,
                                        LeftOrderAskSize=las,
                                        LeftActualPrice=0,
                                        LeftActualUndPrice=lu,
                                        MidStrike=mstrike,
                                        MidOrderAskPrice=ma,
                                        MidOrderBidPrice=mb,
                                        MidOrderAveragePrice=mp,
                                        MidOrderClose=mc,
                                        MidOrderBidSize=mbs,
                                        MidOrderAskSize=mas,
                                        MidActualPrice=0,
                                        MidActualUndPrice=mu,
                                        RightStrike=rstrike,
                                        RightOrderAskPrice=ra,
                                        RightOrderBidPrice=rb,
                                        RightOrderAveragePrice=rp,
                                        RightOrderClose=rc,
                                        RightOrderBidSize=rbs,
                                        RightOrderAskSize=ras,
                                        RightActualPrice=0,
                                        RightActualUndPrice=ru,
                                        StrategyPrice=strategy_price)
        except Exception as e:
            print("======ERROR-DB---------")
            print(e)
            print("======End ERROR-DB---------")
Beispiel #25
0
def currency_exchange(request, currencies='EURUSD'):
    # print(currencies)
    ss1 = 'ss1'
    ss2 = 'ss2'
    ss3 = 'ss3'
    ss4 = 'ss4'
    ss5 = 'ss5'
    ss6 = 'ss6'
    ss7 = 'ss7'
    ss8 = 'ss8'
    ss9 = 'ss9'
    df = None
    is_error = 0
    try:
        loop = asyncio.get_event_loop_policy().new_event_loop()
        asyncio.set_event_loop(loop)
        ib_server = 'twoprojectsib1_tws_1'
        ib_port = 4003
        if settings.DEBUG:
            ib_server = '127.0.0.1'
            ib_port = 4002
        ib_ = IB()
        ci = randint(0, 100000)
        ib_.connect(ib_server, ib_port, clientId=ci)
        # print('ib_')
        # print(ib_)
        # print('ib_')
        ss1 = str(ib_)
    except Exception as e:
        ss1 = "Error connecting to: " + ib_server + ":" + str(ib_port)
        ss2 = e
        is_error = 1

    try:
        c = Forex(currencies)
        bars = ib_.reqHistoricalData(c,
                                     endDateTime='',
                                     durationStr='1 D',
                                     barSizeSetting='1 min',
                                     whatToShow='MIDPOINT',
                                     useRTH=True)
        # print(bars)
        ss3 = 'good 3'
        df = util.df(bars)
        # print(df[['date', 'open', 'high', 'low', 'close']])
        ss4 = 'good 4'
        df = df.sort_values(by=['date'], ascending=False)
        ss5 = 'good 5'

        ib_.disconnect()
        del ib_

        ss6 = 'good 6'
    except Exception as e2:
        ss7 = e2
        is_error = 1

    context = {
        'df':
        df,
        'ss1':
        ss1,
        'ss2':
        ss2,
        'ss3':
        ss3,
        'ss4':
        ss4,
        'ss5':
        ss5,
        'ss6':
        ss6,
        'ss7':
        ss7,
        'ss8':
        ss8,
        'ss9':
        ss9,
        'is_error':
        is_error,
        'currencies':
        currencies,
        'title':
        'Currency Exchange',
        'cur_list': [
            'GBPUSD', 'GBPZAR', 'HKDJPY', 'KRWAUD', 'KRWCAD', 'KRWCHF',
            'KRWEUR', 'KRWGBP', 'KRWHKD', 'KRWJPY', 'KRWUSD', 'MXNJPY',
            'NOKJPY', 'NOKSEK', 'NZDCAD', 'NZDCHF', 'NZDJPY', 'NZDUSD',
            'SEKJPY', 'SGDCNH', 'SGDJPY', 'TRYJPY', 'USDCAD', 'USDCHF',
            'USDCNH', 'USDCZK', 'USDDKK', 'USDHKD', 'USDHUF', 'USDILS',
            'USDJPY', 'USDKRW', 'USDMXN', 'USDNOK', 'USDPLN', 'USDRUB',
            'USDSEK', 'USDSGD', 'USDTRY', 'USDZAR', 'ZARJPY', 'EURPLN',
            'EURRUB', 'EURSEK', 'EURSGD', 'EURTRY', 'EURUSD', 'EURZAR',
            'GBPAUD', 'GBPCAD', 'GBPCHF', 'GBPCNH', 'GBPCZK', 'GBPDKK',
            'GBPHKD', 'GBPHUF', 'GBPJPY', 'GBPMXN', 'GBPNOK', 'GBPNZD',
            'GBPPLN', 'GBPSEK', 'GBPSGD', 'GBPTRY', 'GBPUSD', 'GBPZAR',
            'HKDJPY', 'KRWAUD', 'KRWCAD', 'KRWCHF', 'KRWEUR', 'KRWGBP',
            'KRWHKD', 'KRWJPY', 'KRWUSD', 'MXNJPY', 'NOKJPY', 'NOKSEK',
            'NZDCAD', 'NZDCHF', 'NZDJPY', 'NZDUSD', 'SEKJPY', 'SGDCNH',
            'SGDJPY', 'TRYJPY', 'USDCAD', 'USDCHF', 'USDCNH', 'USDCZK',
            'USDDKK', 'USDHKD', 'USDHUF', 'USDILS', 'USDJPY', 'USDKRW',
            'USDMXN', 'USDNOK', 'USDPLN', 'USDRUB', 'USDSEK', 'USDSGD',
            'USDTRY', 'USDZAR', 'ZARJPY'
        ]
    }
    return render(request, 'trades/currency_exchange.html', context)