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
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()
] FUTURES = [ "ES", "NQ", "RTY", "CL", "NG", "ZB", "ZN", "GC", "MXP", "EUR", "JPY", "GBP" ] stockContracts = [Stock(s, "SMART", "USD") for s in STOCK] ib.qualifyContracts(*stockContracts) futures = [ib.reqContractDetails(Future(f)) for f in FUTURES] futuresContracts = [c.contract for f in futures for c in f] futuresContracts = [ c for c in futuresContracts if c.tradingClass == c.symbol and c.lastTradeDateOrContractMonth.startswith("2019") ] for contract in stockContracts + futuresContracts: ib.reqMktData(contract, "", False, False) def onPendingTickers(tickers): ticks = [] for t in tickers: encodedTick = json.dumps(util.tree(t)) ticks.append({"Data": encodedTick}) firehose.put_record_batch(DeliveryStreamName=firehoseStream, Records=ticks) ib.pendingTickersEvent += onPendingTickers IB.run()
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'
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)}")
lista2.append(contract.conId) lista2.append(contract.localSymbol) lista2.append(contract.lastTradeDateOrContractMonth) lista1.append(lista2) lista1.sort(key=lambda x: x[2]) futuros2 = lista1[:primerosN] '''MEJORAR: Estoy dando por supuesto que los N primeros de las dos listas corresponden a los mismos meses''' '''Esto no será siempre cierto, hay que mejorar este proceso para que tenga en cuenta los meses''' df = pd.DataFrame(columns=('MES', 'CL', 'BZ', 'DIFF1', 'DIFF2', 'DIF')) midF1ant = 0 midF2ant = 0 for i in range(0, len(futuros1)): contract = Future(localSymbol=futuros1[i][1], exchange=exchange1) ticker = ib.reqMktData(contract) ib.sleep(2) ib.cancelMktData(contract) midF1 = round((ticker.bid + ticker.ask) / 2, 3) if i == 0: difF1 = 0 else: difF1 = midF1 - midF1ant midF1ant = midF1 contract = Future(localSymbol=futuros2[i][1], exchange=exchange2) ticker = ib.reqMktData(contract) ib.sleep(2) ib.cancelMktData(contract) midF2 = round((ticker.bid + ticker.ask) / 2, 3) if i == 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 runProg(): """run program""" util.patchAsyncio() # log to a file util.logToFile(f'getRecentHistoricalData2.log') # util.logToConsole() # set pandas option pd.set_option('display.width', 200) # specify connection details host = '127.0.0.1' port = 4002 ibcIni = '/home/bn/IBController/configPaper.ini' tradingMode = 'paper' clientId = 12 # start watchdog ibc = IBC(970, gateway=True, tradingMode=tradingMode, ibcIni=ibcIni) ib = IB() watchdogApp = ibcontroller.Watchdog(ibc, ib=ib, appStartupTime=15, host=host, port=port, clientId=clientId) watchdogApp.start() pass # create some contracts qcs = [] c = Contract(symbol='EUR', currency='USD', exchange='IDEALPRO', secType='CASH') qc = ib.qualifyContracts(c)[0] qcs.append(qc) # request market data for qc in qcs: ib.reqMktData(contract=qc, genericTickList='', snapshot=False, regulatorySnapshot=False, mktDataOptions=None) pass # define some callback def onPendingTickers(tickers): for t in tickers: localSymbol = t.contract.localSymbol if localSymbol == "EUR.USD": nowUTC = pd.to_datetime(pd.datetime.utcnow()).tz_localize(None) nowUTCRounded = nowUTC.floor('1 min') dateTime = pd.to_datetime(t.time).tz_localize(None) print(localSymbol, nowUTCRounded, ((dateTime - nowUTCRounded) / pd.Timedelta('1 sec')), t.close) pass pass pass def myErrorCallback(reqId, errorCode, errorString, contract): # print("myErrorCallback", reqId,errorCode,errorString,contract) if errorCode == 322: print("myErrorCallback", reqId, errorCode, errorString, contract) # more than 50 simultaneous historical data requests app.ib.client.cancelHistoricalData(reqId) # register the callbacks with ib ib.setCallback('error', myErrorCallback) ib.setCallback('pendingTickers', onPendingTickers) # run and never stop ib.run()
def runProg(args): """run program""" util.patchAsyncio() # log to a file utils.logToFile(f'getRecentHistoricalData.log') # utils.logToConsole() apschedulerLogger = logging.getLogger('apscheduler') apschedulerLogger.setLevel(logging.ERROR) tradingLogger = logging.getLogger('trading') tradingLogger.setLevel(logging.WARNING) pd.set_option('display.width', 200) # 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') DBType = config.get('DataBase', 'DBType') DBFileName = config.get('DataBase', 'DBFileName') clientId = config.get('InteractiveBrokers', 'clientId') # for production mode: watchdog if 1: # 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) myWatchdogapp = myWatchdog.myWatchdog(ibc, appStartupTime=15, port=4002) myWatchdogapp.start() ib = myWatchdogapp.ib pass if 0: # faster way for now ib = IB() ib.connect(host=host, port=port, clientId=clientId) 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) qcs = mydb.MarketDataInfoTableDataFrame.qualifiedContract for qc in qcs: print(qc, type(qc)) ib.reqMktData(contract=qc, genericTickList='', snapshot=False, regulatorySnapshot=False, mktDataOptions=None) pass df = pd.DataFrame( columns='symbol bidSize bid ask askSize high low close'.split()) df['symbol'] = [qc.localSymbol for qc in qcs] contract2Row = {qc: i for (i, qc) in enumerate(qcs)} pprint.pprint(contract2Row) def onPendingTickers(tickers): for t in tickers: iRow = contract2Row[t.contract] localSymbol = t.contract.localSymbol if localSymbol == "EUR.USD": nowUTC = pd.to_datetime(pd.datetime.utcnow()).tz_localize(None) nowUTCRounded = nowUTC.floor('1 min') dateTime = pd.to_datetime(t.time).tz_localize(None) print(localSymbol, nowUTCRounded, ((dateTime - nowUTCRounded) / pd.Timedelta('1 sec')), t.close) # df.iloc[iRow, 1:] = (t.bidSize, t.bid, t.ask, t.askSize, t.high, t.low, t.close) # print(df) ib.setCallback('pendingTickers', onPendingTickers) # ib.sleep(300) if 1: util.allowCtrlC() # Execution will block here until Ctrl+C (Ctrl+Break on Windows) is pressed. try: asyncio.get_event_loop().run_forever() except (KeyboardInterrupt, SystemExit): pass
class IbManager(object): log_file = 'ib_manager' def __init__(self, ip: str, port: int, client_id: int): self._ib = IB() self._ib_ip: str = ip self._ib_port: int = port self._client_id: int = client_id self._subscribed_mkt_contracts: List[str] = [] self._subscribed_mkt_depth_contracts: List[str] = [] self._log: Log = Log.create(Log.path(self.log_file)) self._logger = self._log.get_logger('ibmanager') self._recorder: Recorder = Recorder(self._log) self._market_recorder: MarketRecorder = MarketRecorder( self._ib, self._recorder) self._account_recorder: AccountRecorder = AccountRecorder( self._ib, self._recorder) self._keep_connection_task: asyncio.Task = None self._ib.connectedEvent += self.on_ib_connected self._ib.disconnectedEvent += self.on_ib_disconnected self._reconnect_flag: bool = False def on_ib_connected(self) -> None: self._logger.info('connected with ib') self._reconnect_flag = False self._recover_subscriptions() def on_ib_disconnected(self) -> None: self._logger.warning('disconnected with ib') self._reconnect_flag = True if self._keep_connection_task is None: self._keep_connection_task = asyncio.create_task(self._reconnect()) async def _reconnect(self) -> None: while self._reconnect_flag: await asyncio.sleep(20) self._logger.info('try to reconnect ib gateway') await self.initialize() self._keep_connection_task = None def _recover_subscriptions(self) -> None: for contract in self._subscribed_mkt_contracts: self._logger.info(f'recover subscribe {str(contract)}') self._ib.reqMktData(contract) for contract in self._subscribed_mkt_depth_contracts: self._logger.info(f'recover subscribe depth {str(contract)}') self._ib.reqMktDepth(contract) async def initialize(self): if self._ib.isConnected(): return try: await self._ib.connectAsync(self._ib_ip, self._ib_port, clientId=self._client_id) accounts = self._ib.managedAccounts() if len(accounts) > 0: self._account_recorder.update_account(accounts[0]) self.update_account() except Exception: pass def update_account(self): self._ib.reqAccountSummaryAsync() async def find_symbols(self, pattern: str) -> List[str]: symbols = await self._ib.reqMatchingSymbolsAsync(pattern) contracts = [symbol.contract.nonDefaults() for symbol in symbols] return contracts def make_contract(self, **kwargs) -> Contract: return Contract.create(**kwargs) def sub_market(self, contract: Contract) -> str: if contract in self._subscribed_mkt_contracts: return 'already subscribe {}'.format(str(contract)) self._subscribed_mkt_contracts.append(contract) self._ib.reqMktData(contract) return 'subscribe {} success'.format(str(contract)) def unsub_market(self, contract: Contract) -> str: if contract not in self._subscribed_mkt_contracts: return 'not ever subscribe {}'.format(str(contract)) self._subscribed_mkt_contracts.append(contract) self._ib.cancelMktData(contract) return 'unsubscribe {} success'.format(str(contract)) def sub_market_depth(self, contract: Contract) -> str: if contract in self._subscribed_mkt_depth_contracts: return 'already subscribe depth {}'.format(str(contract)) self._subscribed_mkt_depth_contracts.append(contract) self._ib.reqMktDepth(contract) return 'subscribe depth {} success'.format(str(contract)) def unsub_market_depth(self, contract: Contract) -> str: if contract not in self._subscribed_mkt_depth_contracts: return 'not ever subscribe depth {}'.format(str(contract)) self._subscribed_mkt_contracts.remove(contract) self._ib.cancelMktDepth(contract) return 'unsubscribe depth {} success'.format(str(contract)) def place_order(self, contract: Contract, side: str, size: int, price: float) -> str: trade = self._place_order(contract, side, size, price) return str(trade) def _place_order(self, contract: Contract, side: str, size: int, price: float) -> Trade: side = side.upper() if side not in ('SELL', 'BUY'): return [f'invalid order type: {side}'] price = float(f'{round(float(price), 3):.3f}') order = LimitOrder(side, size, price, tif='GTC') trade = self._ib.placeOrder(contract, order) return trade def cancel_order(self, order_id: int) -> str: order_id = int(order_id) order = Order(orderId=order_id) trade = self._ib.cancelOrder(order) return str(trade) async def orders(self) -> List[str]: orders = await self._ib.reqOpenOrdersAsync() return [str(order) for order in orders] def portfolio(self) -> List[str]: results = self._ib.portfolio() return [str(value) for value in results]
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()