def __init__(self, ib: IB, func: Callable) -> None: self.func = func self.ib = ib log.debug('Initializing watchdog') ibc = IBC( twsVersion=978, gateway=True, tradingMode='paper', ) watchdog = Watchdog( ibc, ib, port='4002', clientId=10, ) log.debug('Attaching handlers...') IBHandlers.__init__(self, ib) watchdog.startedEvent += self.onStarted log.debug('Initializing watchdog...') watchdog.start() log.debug('Watchdog started.') ib.run() log.debug('ib run.')
def startGatewayWatchdog(configFile): conf = getConfig(configFile) logging.warn('config: {}'.format(conf)) if conf.prod and conf.tradingMode != 'live': raise RuntimeError('prod is live') controller = ibcontroller.IBC(twsVersion=978, gateway=True, tradingMode=conf.tradingMode, ibcIni=paths.creds() + '/config.ini', ibcPath=paths.rootDir() + '/ibc') logging.warn('starting API gateway using watchdog in {} mode'.format( conf.tradingMode)) ib = IB() ib.connectedEvent += onConnected watchdog = ibcontroller.Watchdog(controller=controller, ib=ib, host='localhost', port=getPort(conf.prod), appStartupTime=35) watchdog.start() import signal import sys import time def term(*args): logging.warn('shutting down controller') watchdog.controller._proc.send_signal(signal.SIGTERM) time.sleep(1) logging.warn('shutting down watchdog') sys.exit(0) signal.signal(signal.SIGTERM, term) ib.run()
] 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()
def start(config): import toml import thetagang.config_defaults as config_defaults with open(config, "r") as f: config = toml.load(f) config = normalize_config(config) validate_config(config) click.secho(f"Config:", fg="green") click.echo() click.secho(f" Account details:", fg="green") click.secho( f" Number = {config['account']['number']}", fg="cyan") click.secho( f" Cancel existing orders = {config['account']['cancel_orders']}", fg="cyan", ) click.secho( f" Margin usage = {config['account']['margin_usage']} ({config['account']['margin_usage'] * 100}%)", fg="cyan", ) click.secho( f" Market data type = {config['account']['market_data_type']}", fg="cyan", ) click.echo() click.secho(f" Roll options when either condition is true:", fg="green") click.secho( f" Days to expiry <= {config['roll_when']['dte']} and P&L >= {config['roll_when']['min_pnl']} ({config['roll_when']['min_pnl'] * 100}%)", fg="cyan", ) click.secho( f" P&L >= {config['roll_when']['pnl']} ({config['roll_when']['pnl'] * 100}%)", fg="cyan", ) click.echo() click.secho(f" When contracts are ITM:", fg="green") click.secho( f" Roll puts = {config['roll_when']['puts']['itm']}", fg="cyan", ) click.secho( f" Roll calls = {config['roll_when']['calls']['itm']}", fg="cyan", ) click.echo() click.secho(f" Write options with targets of:", fg="green") click.secho(f" Days to expiry >= {config['target']['dte']}", fg="cyan") click.secho(f" Default delta <= {config['target']['delta']}", fg="cyan") if "puts" in config["target"]: click.secho( f" Delta for puts <= {config['target']['puts']['delta']}", fg="cyan", ) if "calls" in config["target"]: click.secho( f" Delta for calls <= {config['target']['calls']['delta']}", fg="cyan", ) click.secho( f" Maximum new contracts = {config['target']['maximum_new_contracts']}", fg="cyan", ) click.secho( f" Minimum open interest = {config['target']['minimum_open_interest']}", fg="cyan", ) click.echo() click.secho(f" Symbols:", fg="green") for s in config["symbols"].keys(): c = config["symbols"][s] c_delta = f"{get_target_delta(config, s, 'C'):.2f}".rjust(4) p_delta = f"{get_target_delta(config, s, 'P'):.2f}".rjust(4) weight = f"{c['weight']:.2f}".rjust(4) weight_p = f"{(c['weight'] * 100):.1f}".rjust(4) click.secho( f" {s.rjust(5)} weight = {weight} ({weight_p}%), delta = {p_delta}p, {c_delta}c", fg="cyan", ) assert (sum([ config["symbols"][s]["weight"] for s in config["symbols"].keys() ]) == 1.0) click.echo() if config.get("ib_insync", {}).get("logfile"): util.logToFile(config["ib_insync"]["logfile"]) # TWS version is pinned to current stable ibc = IBC(978, **config["ibc"]) def onConnected(): portfolio_manager.manage() ib = IB() ib.connectedEvent += onConnected completion_future = asyncio.Future() portfolio_manager = PortfolioManager(config, ib, completion_future) probeContractConfig = config["watchdog"]["probeContract"] watchdogConfig = config.get("watchdog") del watchdogConfig["probeContract"] probeContract = Contract( secType=probeContractConfig["secType"], symbol=probeContractConfig["symbol"], currency=probeContractConfig["currency"], exchange=probeContractConfig["exchange"], ) watchdog = Watchdog(ibc, ib, probeContract=probeContract, **watchdogConfig) watchdog.start() ib.run(completion_future) watchdog.stop() ibc.terminate()
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()
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)
def start(config): import toml import thetagang.config_defaults as config_defaults # NOQA with open(config, "r") as f: config = toml.load(f) config = normalize_config(config) validate_config(config) click.secho("Config:", fg="green") click.echo() click.secho(" Account details:", fg="green") click.secho( f" Number = {config['account']['number']}", fg="cyan") click.secho( f" Cancel existing orders = {config['account']['cancel_orders']}", fg="cyan", ) click.secho( f" Margin usage = {config['account']['margin_usage']} ({config['account']['margin_usage'] * 100}%)", fg="cyan", ) click.secho( f" Market data type = {config['account']['market_data_type']}", fg="cyan", ) click.echo() click.secho(" Roll options when either condition is true:", fg="green") click.secho( f" Days to expiry <= {config['roll_when']['dte']} and P&L >= {config['roll_when']['min_pnl']} ({config['roll_when']['min_pnl'] * 100}%)", fg="cyan", ) if "max_dte" in config["roll_when"]: click.secho( f" P&L >= {config['roll_when']['pnl']} ({config['roll_when']['pnl'] * 100}%) and DTE < {config['roll_when']['max_dte']}", fg="cyan", ) else: click.secho( f" P&L >= {config['roll_when']['pnl']} ({config['roll_when']['pnl'] * 100}%)", fg="cyan", ) click.echo() click.secho(" When contracts are ITM:", fg="green") click.secho( f" Roll puts = {config['roll_when']['puts']['itm']}", fg="cyan", ) click.secho( f" Roll calls = {config['roll_when']['calls']['itm']}", fg="cyan", ) click.echo() click.secho(" Write options with targets of:", fg="green") click.secho(f" Days to expiry >= {config['target']['dte']}", fg="cyan") click.secho(f" Default delta <= {config['target']['delta']}", fg="cyan") if "puts" in config["target"]: click.secho( f" Delta for puts <= {config['target']['puts']['delta']}", fg="cyan", ) if "calls" in config["target"]: click.secho( f" Delta for calls <= {config['target']['calls']['delta']}", fg="cyan", ) click.secho( f" Maximum new contracts = {config['target']['maximum_new_contracts_percent'] * 100}% of buying power", fg="cyan", ) click.secho( f" Minimum open interest = {config['target']['minimum_open_interest']}", fg="cyan", ) click.echo() click.secho(" Symbols:", fg="green") for s in config["symbols"].keys(): c = config["symbols"][s] c_delta = f"{get_target_delta(config, s, 'C'):.2f}".rjust(4) p_delta = f"{get_target_delta(config, s, 'P'):.2f}".rjust(4) weight_p = f"{(c['weight'] * 100):.2f}".rjust(4) strike_limits = "" c_limit = get_strike_limit(config, s, "C") p_limit = get_strike_limit(config, s, "P") if c_limit: strike_limits += f", call strike >= ${c_limit:.2f}" if p_limit: strike_limits += f", put strike <= ${p_limit:.2f}" click.secho( f" {s.rjust(5)} weight = {weight_p}%, delta = {p_delta}p, {c_delta}c{strike_limits}", fg="cyan", ) assert (round( sum([config["symbols"][s]["weight"] for s in config["symbols"].keys()]), 5) == 1.00000) click.echo() if config.get("ib_insync", {}).get("logfile"): util.logToFile(config["ib_insync"]["logfile"]) # TWS version is pinned to current stable ibc_config = config.get("ibc", {}) # Remove any config params that aren't valid keywords for IBC ibc_keywords = { k: ibc_config[k] for k in ibc_config if k not in ["RaiseRequestErrors"] } ibc = IBC(981, **ibc_keywords) def onConnected(): portfolio_manager.manage() ib = IB() ib.RaiseRequestErrors = ibc_config.get("RaiseRequestErrors", False) ib.connectedEvent += onConnected completion_future = asyncio.Future() portfolio_manager = PortfolioManager(config, ib, completion_future) probeContractConfig = config["watchdog"]["probeContract"] watchdogConfig = config.get("watchdog") del watchdogConfig["probeContract"] probeContract = Contract( secType=probeContractConfig["secType"], symbol=probeContractConfig["symbol"], currency=probeContractConfig["currency"], exchange=probeContractConfig["exchange"], ) watchdog = Watchdog(ibc, ib, probeContract=probeContract, **watchdogConfig) watchdog.start() ib.run(completion_future) watchdog.stop() ibc.terminate()
def runProg(): """run program""" util.patchAsyncio() # log to a file utils.logToFile(f'getRecentHistoricalData4.log', level=logging.INFO) # utils.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() # create some contracts qcs = [] c = Contract(symbol='EUR',currency='CHF',exchange='IDEALPRO',secType='CASH') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='EUR',currency='CNH',exchange='IDEALPRO',secType='CASH') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='EUR',currency='GBP',exchange='IDEALPRO',secType='CASH') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='EUR', currency='JPY', exchange='IDEALPRO', secType='CASH') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='EUR', currency='RUB', exchange='IDEALPRO', secType='CASH') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='EUR', currency='USD', exchange='IDEALPRO', secType='CASH') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='IBDE30',currency='EUR',exchange='SMART',secType='CFD') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='DAX',currency='EUR',exchange='DTB',secType='IND') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='HSC50',currency='HKD',exchange='HKFE',secType='IND') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='INDU',currency='USD',exchange='CME',secType='IND') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='N225',currency='JPY',exchange='OSE.JPN',secType='IND') qc = ib.qualifyContracts(c)[0] qcs.append(qc) c = Contract(symbol='SPX',currency='USD',exchange='CBOE',secType='IND') qc = ib.qualifyContracts(c)[0] qcs.append(qc) # qcs = [qc for qc in qcs if qc.localSymbol in ['N225','EUR.USD','IBDE30','DJI']] # qcs = [qc for qc in qcs if qc.localSymbol in ['N225','DJI']] qcs = [qc for qc in qcs if qc.localSymbol in ['N225','DAX','DJI']] # function to request historical bars def requestHistoricalBars(qcs): # request historical bars barss = [] for qc in qcs: whatToShow = 'TRADES' if qc.secType == 'IND' else 'MIDPOINT' bars = ib.reqHistoricalData( qc, endDateTime='', durationStr='1 W', barSizeSetting='1 min', whatToShow=whatToShow, useRTH=False, formatDate=2, keepUpToDate=True) barss.append(bars) pass return barss barss = requestHistoricalBars(qcs) print('er', barss[0][-1]) print('er2', barss[1][-1]) print('er2', barss[2][-1]) def requestMarketData(qcs): for qc in qcs: ib.reqMktData(contract=qc, genericTickList='', snapshot=False, regulatorySnapshot=False, mktDataOptions=None) pass pass def requestRealTimeBars(qcs): barss = [] for qc in qcs: bars = ib.reqRealTimeBars(contract=qc, barSize='', whatToShow='MIDPOINT', useRTH=False, realTimeBarsOptions=None) barss.append(bars) pass return (barss) # define some callback def onBarUpdate(bars, hasNewBar): localSymbol = bars.contract.localSymbol secType = bars.contract.secType b0 = bars[0] if isinstance(b0, objects.RealTimeBar): dateTimeAttributeName = 'time' barType = 'RealTimeBar' else: dateTimeAttributeName = 'date' barType = 'BarData' pass dt0 = pd.to_datetime(getattr(b0,dateTimeAttributeName)).tz_localize(None) bm1 = bars[-1] dtm1 = pd.to_datetime(getattr(bm1,dateTimeAttributeName)).tz_localize(None) nowUTC = pd.to_datetime(pd.datetime.utcnow()).tz_localize(None) diffDateTIme = (nowUTC - dtm1) / pd.Timedelta('1 sec') if (hasNewBar or localSymbol in ['N225','DAX']): print(f'local Symbol: {localSymbol}, hasNewBar: {hasNewBar}; barType: {barType}, nBars: {len(bars)}, diffDateTime: {diffDateTIme}, close: {bm1.close}') 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 False: # if errorCode == 322: print("myErrorCallback", reqId, errorCode, errorString, contract) # more than 50 simultaneous historical data requests app.ib.client.cancelHistoricalData(reqId) def onConnectedCallback(): print('connected') barss = requestHistoricalBars(qcs) # barss = requestRealTimeBars(qcs) ib.barUpdateEvent.clear() ib.barUpdateEvent += onBarUpdate print('connected 2') # requestMarketData(qcs) # ib.pendingTickersEvent.clear() # ib.pendingTickersEvent += onPendingTickers print('connected 3') pass def onDisconnectedCallback(): print ('disconnected') def myTimeoutCallback(timeout): print (f'timeout {timeout}') # request the bars barss = requestHistoricalBars(qcs) # request market data # requestMarketData(qcs) # request real time bars # requestRealTimeBars(qcs) # register the callbacks with ib ib.connectedEvent.clear() ib.connectedEvent += onConnectedCallback ib.disconnectedEvent.clear ib.disconnectedEvent = onDisconnectedCallback ib.barUpdateEvent.clear() ib.barUpdateEvent += onBarUpdate ib.pendingTickersEvent.clear() # ib.pendingTickersEvent += onPendingTickers ib.errorEvent.clear() ib.errorEvent += myErrorCallback ib.timeoutEvent.clear() ib.timeoutEvent += myTimeoutCallback def mySoftTimeoutCallback(watchdogApp): print (f'soft time out {watchdogApp}') def myHardTimeoutCallback(watchdogApp): print (f'hard time out {watchdogApp}') watchdogApp.flush() # def myStoppingCallback(sthg): # print (f'Stopping Event {sthg}') # def myStoppedCallback(sthg): # print (f'Stopped Event {sthg}') # watchdogApp.softTimeoutEvent.clear() watchdogApp.softTimeoutEvent += mySoftTimeoutCallback # watchdogApp.hardTimeoutEvent.clear() watchdogApp.hardTimeoutEvent += myHardTimeoutCallback # watchdogApp.stoppingEvent.clear() # watchdogApp.stoppingEvent += myStoppingCallback # # watchdogApp.stoppedEvent.clear() # watchdogApp.stoppedEvent += myStoppedCallback # run and never stop ib.run()
def start(config): import toml with open(config, "r") as f: config = toml.load(f) validate_config(config) click.secho(f"Config:", fg="green") click.echo() click.secho(f" Account details:", fg="green") click.secho( f" Number = {config['account']['number']}", fg="cyan") click.secho( f" Cancel existing orders = {config['account']['cancel_orders']}", fg="cyan", ) click.secho( f" Margin usage = {config['account']['margin_usage']} ({config['account']['margin_usage'] * 100}%)", fg="cyan", ) click.secho( f" Market data type = {config['account']['market_data_type']}", fg="cyan", ) click.echo() click.secho(f" Roll options when either condition is true:", fg="green") click.secho(f" Days to expiry <= {config['roll_when']['dte']}", fg="cyan") click.secho( f" P&L >= {config['roll_when']['pnl']} ({config['roll_when']['pnl'] * 100}%)", fg="cyan", ) click.echo() click.secho(f" Write options with targets of:", fg="green") click.secho(f" Days to expiry >= {config['target']['dte']}", fg="cyan") click.secho(f" Delta <= {config['target']['delta']}", fg="cyan") click.secho( f" Minimum open interest >= {config['target']['minimum_open_interest']}", fg="cyan", ) click.echo() click.secho(f" Symbols:", fg="green") for s in config["symbols"].keys(): click.secho( f" {s}, weight = {config['symbols'][s]['weight']} ({config['symbols'][s]['weight'] * 100}%)", fg="cyan", ) assert (sum([ config["symbols"][s]["weight"] for s in config["symbols"].keys() ]) == 1.0) click.echo() if config.get("ib_insync", {}).get("logfile"): util.logToFile(config["ib_insync"]["logfile"]) ibc = IBC(**config["ibc"]) def onConnected(): portfolio_manager.manage() ib = IB() ib.connectedEvent += onConnected completion_future = asyncio.Future() portfolio_manager = PortfolioManager(config, ib, completion_future) probeContractConfig = config["watchdog"]["probeContract"] watchdogConfig = config.get("watchdog") del watchdogConfig["probeContract"] probeContract = Contract( secType=probeContractConfig["secType"], symbol=probeContractConfig["symbol"], currency=probeContractConfig["currency"], exchange=probeContractConfig["exchange"], ) watchdog = Watchdog(ibc, ib, probeContract=probeContract, **watchdogConfig) watchdog.start() ib.run(completion_future) watchdog.stop() ibc.terminate()
def findConIds(**kwargs): """prints a list of conIds for a hard-coded list of currencies""" ib = IB() ib.errorEvent += myErrorCallback clientId = kwargs.get('clientId'.lower()) ib.connect('127.0.0.1', 4002, clientId=clientId) # build a list of valid contracts # define contracts ForexStrs = [ # 'AUD', # 'CAD', 'CHF', 'CNH', 'GBP', 'JPY', 'USD', 'RUB', # 'CZK', # 'DKK', # 'HUF', # 'ILS', # 'MXN', # 'NOK', # 'NZD', # 'PLN', # 'SEK', # 'SGD', # 'TRY', # 'ZAR', ] # Indices and CFDs others = [ # { # 'secType': 'IND', # 'symbol': 'DAX', # 'exchange': 'DTB', # 'currency': 'EUR' # }, # { # 'secType': 'IND', # 'symbol': 'INDU', # 'exchange': 'CME', # 'currency': 'USD' # }, # { # 'secType': 'IND', # 'symbol': 'HSC50', # 'exchange': 'HKFE', # 'currency': 'HKD' # }, # { # 'secType': 'IND', # 'symbol': 'N225', # 'exchange': 'OSE.JPN', # 'currency': 'JPY' # }, # { # 'secType': 'IND', # 'symbol': 'SPX', # 'exchange': 'CBOE', # 'currency': 'USD' # }, { 'secType': 'CFD', 'symbol': 'IBCH20', 'exchange': 'SMART', 'currency': 'CHF' }, { 'secType': 'CFD', 'symbol': 'IBDE30', 'exchange': 'SMART', 'currency': 'EUR' }, { 'secType': 'CFD', 'symbol': 'IBEU50', 'exchange': 'SMART', 'currency': 'EUR' }, { 'secType': 'CFD', 'symbol': 'IBFR40', 'exchange': 'SMART', 'currency': 'EUR' }, { 'secType': 'CFD', 'symbol': 'IBGB100', 'exchange': 'SMART', 'currency': 'GBP' }, { 'secType': 'CFD', 'symbol': 'IBJP225', 'exchange': 'SMART', 'currency': 'JPY' }, { 'secType': 'CFD', 'symbol': 'IBHK50', 'exchange': 'SMART', 'currency': 'HKD' }, { 'secType': 'CFD', 'symbol': 'IBUS30', 'exchange': 'SMART', 'currency': 'USD' }, { 'secType': 'CFD', 'symbol': 'IBUS500', 'exchange': 'SMART', 'currency': 'USD' }, ] contractsQualified = [] # Forex for s in ForexStrs: try: contractsQualified.append( ib.qualifyContracts( Contract(secType='CASH', symbol='EUR', exchange='IDEALPRO', currency=s))[0]) pass except: print('could not qualify the contract for {}'.format(s)) pass pass # others for d in others: try: contractsQualified.append(ib.qualifyContracts(Contract(**d))[0]) pass except: print('could not qualify the contract for {}'.format(s)) pass pass # get contract information conIds = [] for c in contractsQualified: if c.secType in ['CASH', 'CFD']: whatToShow = 'MIDPOINT' else: whatToShow = 'TRADES' eDT = None try: req = ib.reqHeadTimeStampAsync(c, whatToShow=whatToShow, useRTH=False, formatDate=2) try: eDT = ib.run(asyncio.wait_for(req, 10)) except asyncio.TimeoutError: print('timeout') pass pass except: pass print(c.symbol, c.currency, c.localSymbol, c.exchange, c.conId, c.secType, eDT) # cD = ib.reqContractDetails(c)[0] # secType=cD.summary.secType # print (c.symbol, c.currency, c.localSymbol, c.exchange, c.conId, eDT, c.secType) conIds.append(c.conId) print(conIds)
from ib_insync import IB, util from logger import logger from trader import Candle, Trader, Blotter, get_contracts log = logger(__file__[:-3]) ib = IB() ib.connect('127.0.0.1', 4002, clientId=10) contracts = [ ('NQ', 'GLOBEX'), ('ES', 'GLOBEX'), ('NKD', 'GLOBEX'), ('CL', 'NYMEX'), ('GC', 'NYMEX'), ] # util.patchAsyncio() blotter = Blotter() trader = Trader(ib, blotter) futures = get_contracts(contracts, ib) candles = [Candle(contract, trader, ib) for contract in futures] ib.run()
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()
symAll += symbolList #log.debug(symAll) #symbolList=myconnutils.selectSymFromTbl("scantbl") symList = list(set(symAll)) log.debug(symList) #log.FileHandler #log.basicConfig(format='%(asctime)s %(filename)s:%(levelname)s line no: %(lineno)d %(message)s', filename='example.log',level=logging.DEBUG) # util.logToConsole() # get connection to Gateway #ib = IB_connection().ib ib = IB() ib.connect('127.0.0.1', 7499, clientId=19) BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # object where data is stored store = Store() # symbols = pd.read_csv(os.path.join( # BASE_DIR, 'contracts.csv')).to_dict('records') # log.debug(symbols) # *lookup_contracts(symbols), contracts = [*lookup_contracts_Stock(symList)] #exit() number_of_workers = min(len(contracts), max_number_of_workers) ib.run(main(contracts, number_of_workers)) log.debug('script finished, about to disconnect') ib.disconnect()