Esempio n. 1
0
 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.')
Esempio n. 2
0
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()
Esempio n. 3
0
]
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()
Esempio n. 4
0
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()
Esempio n. 5
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()
Esempio n. 6
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)
Esempio n. 7
0
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()
Esempio n. 8
0
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()
Esempio n. 9
0
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()
Esempio n. 10
0
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)
Esempio n. 11
0
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()
Esempio n. 12
0
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()
Esempio n. 13
0
        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()