Ejemplo n.º 1
0
def valuesField(ibc, account, field, usd=None):
    aVal = values(ibc, account)
    for i in range(0, len(aVal)):
        if aVal[i][1] == field and (not usd or aVal[i][3] == 'USD'):
            return aVal[i][2]
    fatal.errorAndExit('problem: did not find {} in account values: {}'.format(
        field, aVal))
Ejemplo n.º 2
0
def summaryField(ibc, account, field, usd=None):
    aSum = summary(ibc, account)
    for i in range(0, len(aSum)):
        if aSum[i][1] == field and (not usd or aSum[i][3] == 'USD'):
            return aSum[i][2]
    fatal.errorAndExit(
        'problem: did not find {} in account summary: {}'.format(field, aSum))
Ejemplo n.º 3
0
 def ibContract(self):
     c = None
     if self.symbol == 'TQQQ' or self.symbol == 'AAPL' or self.symbol == 'AMZN' or self.symbol == 'FB' or self.symbol == 'GOOG':
         c = Stock(symbol=self.symbol,
                   exchange='SMART',
                   currency='USD',
                   primaryExchange='NASDAQ')
     elif self.symbol == 'SQQQ':
         c = Stock(symbol=self.symbol,
                   exchange='SMART',
                   currency='USD',
                   primaryExchange='NASDAQ')
     elif self.symbol == 'AAP2' or self.symbol == 'AMZ2' or self.symbol == 'CRM2' or self.symbol == 'FB2' or self.symbol == 'GOO2' or self.symbol == 'GS2' or self.symbol == 'MSF2' or self.symbol == 'NFL2' or self.symbol == 'NVD2' or self.symbol == 'VIS2':
         c = Stock(symbol=self.symbol,
                   exchange='SMART',
                   currency='USD',
                   primaryExchange='LSE')
     elif (self.symbol == 'ES'
           or self.symbol == 'NQ') and self.localSymbol != None:
         c = Contract(secType='FUT',
                      symbol=self.symbol,
                      localSymbol=self.localSymbol,
                      exchange='GLOBEX',
                      currency='USD')
     else:
         fatal.errorAndExit('no security specified')
     self.contract = c
Ejemplo n.º 4
0
def connect(conf=None, debug=None):
    util.logToConsole(logging.WARN)
    if debug:
        util.logToConsole(logging.DEBUG)

    ibc = IB()
    connected = False
    n = 0
    while not connected and n < 3:
        n += 1
        try:
            if conf.prod:
                if conf.tradingMode != 'live':
                    fatal.fatal(conf, 'prod set but trading mode is not live')
                ibc.connect(host="localhost",
                            port=getPort(conf.prod),
                            clientId=rand.Int(),
                            timeout=3,
                            readonly=False,
                            account=conf.account)
            else:
                ibc.connect(host="localhost",
                            port=getPort(conf.prod),
                            clientId=rand.Int(),
                            account=conf.account)
            ibc.sleep(0.25)
            connected = ibc.isConnected()
        except:
            pass

    if not connected:
        fatal.errorAndExit('could not connect')
    return ibc
Ejemplo n.º 5
0
def _marketNextCloseTime(r):
    dt = nowInUtc()
    if len(r) < 2:
        fatal.errorAndExit('seem like this might not be a range')
    for r_ in r:
        if dt in r_:
            return r_.end_datetime
    fatal.errorAndExit('cannot find next close time {} {}'.format(dt, r))
Ejemplo n.º 6
0
def _marketOpenedAt(r):
    dt = nowInUtc()
    if len(r) < 2:
        fatal.errorAndExit('seem like this might not be a range')
    for r_ in r:
        if dt in r_:
            return r_.start_datetime
    fatal.errorAndExit('cannot find market open time {} {}'.format(dt, r))
Ejemplo n.º 7
0
 def qualify(self):
     r = self.ibClient.qualifyContracts(self.contract)
     if len(r) != 1 or r[0].symbol != self.symbol:
         fatal.errorAndExit('could not validate response: %s', r[0])
     if self.localSymbol == None:  # sometimes the local symbol isn't passed in (like with stocks)
         if self.contract.localSymbol == None:
             fatal.errorAndExit('problem with looking up contract')
         else:
             self.localSymbol = self.contract.localSymbol
Ejemplo n.º 8
0
def _marketOpenedLessThan(r, td):
    dt = nowInUtc()
    if len(r) < 2:
        fatal.errorAndExit('seems like this might not be a range')
    for r_ in r:
        if dt not in r_:
            continue
        elif dt - td not in r_:
            return True
    return False
Ejemplo n.º 9
0
 def anotate(self):  # used for three-bar pattern detection
     self.barSize = abs(self.open - self.close)
     self.lineSize = abs(self.high - self.low)
     if self.open < self.close:
         self.color = 'G'
     elif self.close < self.open:
         self.color = 'R'
     elif self.close == self.open and self.high != self.low:
         self.color = 'G'
     elif math.isnan(self.close) or math.isnan(self.open):
         fatal.errorAndExit('got a self with NaN: {}'.format(self))
Ejemplo n.º 10
0
 def marketRule(self):
     if not isinstance(self.details.marketRuleIds, str):
         fatal.errorAndExit('wrong format {}'.format(self.details))
     mrStr = self.details.marketRuleIds
     mrs = mrStr.split(',')
     if len(mrs) < 1:
         fatal.errorAndExit('wrong format {}'.format(self.details))
     r0 = mrs[0]
     for r in mrs:
         if r != r0:
             fatal.errorAndExit(
                 'multiple market rules for a single contract {}'.format(
                     self.details))
     mr = self.ibClient.reqMarketRule(r0)
     self.marketRule = mr
     penny = False
     if len(self.marketRule) > 1:
         for r in self.marketRule:
             if r.increment == 0.01:
                 penny = True
         if not penny:
             fatal.errorAndExit('multiple price incmrenets {} {}'.format(
                 self.details, self.marketRule))
         logging.warn(
             'default to a penny for the increment, multiple price increments found {} {}'
             .format(self.marketRule, self.symbol))
         self.priceIncrement = 0.01
     else:
         self.priceIncrement = self.marketRule[0].increment
Ejemplo n.º 11
0
    def analyze(self):
        entryPrice = None
        if self.first.color == 'X' or self.second.color == 'X' or self.third.color == 'X':
            logging.debug('got a partial bar')
        #FIXME: the bar size testing seems to have a large impact on not entering, to the detriment of the return
        elif not self.first.color == 'G' and not self.second.color == 'R' and not self.third.color == 'G' and not self.second.barSize < 0.3 * self.first.barSize and not self.second.barSize < 0.5 * self.third.barSize and not self.third.barSize > self.second.barSize:
            entryPrice = None
        else:
            entryPrice = self.third.close
            if math.isnan(entryPrice):
                fatal.errorAndExit(
                    'got floating point which is NaN {} {}'.format(
                        entryPrice, self.third))

            logging.info('found a potential entry point: %d', entryPrice)
        return entryPrice
Ejemplo n.º 12
0
 def __init__(self,
              barSizeStr,
              wContract,
              shortInterval=None,
              longInterval=None,
              watchCount=None):
     if shortInterval is not None:
         self.shortInterval = shortInterval
     if longInterval is not None:
         self.longInterval = longInterval
     if watchCount is not None:
         self.watchCount = watchCount
     dur = data.barSizeToDuration[barSizeStr]
     self.wContract = wContract
     if dur['unit'] != 'S' or not dur['value'] or not isinstance(
             dur['value'], int):
         fatal.errorAndExit('re-factor')
     self.barSize = dur['value']
Ejemplo n.º 13
0
    def initIndicators(self, dataStream):
        short = 0
        long_ = 0
        logging.info('datastream is {}'.format(len(dataStream)))
        for interval in [self.shortInterval, self.longInterval]:
            if self.backTest:  # in backtest, we can just start from 0 instead of later
                sma = 0
                startIndex = 0
                if self.byPeriod:
                    startIndex = len(dataStream) - 1 - int(
                        self.byPeriod * 60 * 60 / self.barSize)
                    logging.info(
                        'doing by period, using index/period(hours): {}/{}'.
                        format(startIndex, self.byPeriod))
                sma = data.calcSMA(interval, dataStream, startIndex)
                # FIXME: might be a bug here, because interval calculations
                ema = data.calcEMA(dataStream[startIndex + interval].close,
                                   sma, interval)
                self.curEmaIndex = startIndex + interval
            else:
                # first we calculate the SMA over the interval (going backwards) one interval back in the dataStream
                smaStartIndex = len(dataStream) - 1 - interval * 2
                if interval == self.longInterval and smaStartIndex < 0:
                    fatal.errorAndExit('wrong interval calc: {} {} {}'.format(
                        smaStartIndex, len(dataStream), interval))
                sma = data.calcSMA(interval, dataStream, smaStartIndex)
                logging.info(
                    'calculated sma of {} for {} starting at {}'.format(
                        sma, interval, smaStartIndex))

                prevEMA = sma
                ema = 0
                index = len(dataStream) - 1 - interval
                for point in range(index, len(dataStream)):
                    midpoint = dataStream[index].close
                    ema = data.calcEMA(midpoint, prevEMA, interval)
                    prevEMA = ema
                    index += 1
            logging.info('calculated ema for {} as {}'.format(interval, ema))
            if interval == self.shortInterval:
                short = ema
            elif interval == self.longInterval:
                long_ = ema
        self.updateIndicators(short, long_)
Ejemplo n.º 14
0
def getHistData(wc,
                barSizeStr,
                longInterval,
                e='',
                d=None,
                t='MIDPOINT',
                r=False,
                f=2,
                k=False):
    duration = barSizeToDuration[barSizeStr]
    if not duration['unit'] or duration['unit'] != 'S' or not duration[
            'value'] or not isinstance(duration['value'], int):
        fatal.errorAndExit('using seconds is supported')

    durationStr = ''
    if d is not None:  # doing a backtest, so add the long interval to build the SMA
        d = d * 60 * 60 + longInterval * duration[
            'value']  # force to seconds, then back up to bar size
        if d > 86400:  # d is in minutes because barSizeToDuration supports minutes atm
            d = int(d / 60 / 60) if int(d / 60 / 60) > 0 else 1
            durationStr = str(d) + ' D'
        else:
            durationStr = str(d) + ' S'
    else:  # not doing a backtest
        # add one because when market closed, latest bar is not yet ready (crazy but true)
        # happens especially when there are two closes (like with the futures maintenace
        # window)
        d = 2 * longInterval + 1
        durationStr = str(d * duration['value']) + ' ' + duration['unit']

    logging.info(
        'getting historical data for c:{}/{}, e:{}, d:{}, b:{}, w:{}, u:{}, f:{}, k:{}'
        .format(wc.symbol, wc.localSymbol, e, durationStr, barSizeStr, t, r, f,
                k))
    histData = wc.ibClient.reqHistoricalData(contract=wc.contract,
                                             endDateTime=e,
                                             durationStr=durationStr,
                                             barSizeSetting=barSizeStr,
                                             whatToShow=t,
                                             useRTH=r,
                                             formatDate=f,
                                             keepUpToDate=k)
    return histData
Ejemplo n.º 15
0
def adequateFunds(orderDetails, orders):
    qty = calculateQty(orderDetails)
    availableFunds = account.availableFunds(orderDetails.wContract.ibClient, orderDetails.config.account)
    buyingPower = account.buyingPower(orderDetails.wContract.ibClient, orderDetails.config.account)
    lhs = orderDetails.entryPrice * qty
    af_rhs = availableFunds - orderDetails.config.bufferAmt
    bp_rhs = buyingPower - orderDetails.config.bufferAmt
    os = None
    if orderDetails.wContract.contract.secType == 'FUT':
        wio = whatIfOrder(orders.entryOrder)
        os = orderDetails.wContract.ibClient.whatIfOrder(orderDetails.wContract.contract, wio)
        if not os.initMarginAfter or not isinstance(os.initMarginAfter, str):
            fatal.errorAndExit('got back invalid format: {} {} {}'.format(os, orderDetails, order))
        ima = float( os.initMarginAfter )
        lhs += ima
    if lhs < af_rhs and lhs < bp_rhs:
        logging.warn('detected adequate funds {} {} {}'.format(lhs, af_rhs, bp_rhs))
        return True
    logging.error('not enough funds: {} {} {}'.format(os, orderDetails, orders))
    return False
Ejemplo n.º 16
0
def parseIbHours(ibHours, tz):
    if not isinstance(ibHours, str):
        fatal.errorAndExit('trading hours is a string')
    openHours = []
    # '20200427:0930-20200427:1600;20200428:0930-20200428:1600'
    ranges = ibHours.split(';')
    m = re.compile('.*:CLOSED')
    for range_ in ranges:
        if range_ == '':
            continue
        if m.match(range_):  # skip closed days
            continue
        ts = range_.split('-')
        if len(ts) != 2:
            fatal.errorAndExit(
                'only two timestamps per range: {}     {}'.format(ts, ibHours))
        start = tz.localize(datetime.strptime(
            ts[0], '%Y%m%d:%H%M')).astimezone(pytz.utc)
        end = tz.localize(datetime.strptime(ts[1], '%Y%m%d:%H%M')).astimezone(
            pytz.utc)
        r = DateTimeRange(start, end)
        if not r.is_valid_timerange():
            fatal.errorAndExit('should get a valid timerange')
        openHours.append(r)
    logging.debug('openHours: %s', openHours)
    return openHours
Ejemplo n.º 17
0
 def updatePnl(self, account):
     pnlR = self.ibClient.pnlSingle(account=account,
                                    conId=self.contract.conId)
     if len(pnlR) != 1:
         fatal.errorAndExit(
             'should get back one pnl for security: {} {}'.format(
                 pnlR, self.contract))
     pnl = pnlR[0]
     if pnl.account != account:
         fatal.errorAndExit('got back mismatched accounts: {} {} {}'.format(
             pnl, account, self.contract))
     elif pnl.conId != self.contract.conId:
         fatal.errorAndExit(
             'got back mismatched contract IDs: {} {} {}'.format(
                 pnl, account, self.contract))
     self.pnl = pnl
Ejemplo n.º 18
0
def parseTimezone(timeZoneId):
    if not isinstance(timeZoneId, str):
        fatal.errorAndExit('timeZoneId should be a string')
    return pytz.timezone(timeZoneId)
Ejemplo n.º 19
0
 def ibDetails(self):
     r = self.ibClient.reqContractDetails(self.contract)
     if len(r) != 1 or r[0].contract != self.contract:
         fatal.errorAndExit('problem getting contract details: %s', r)
     self.details = r[0]
     self.handleDaylightSavings()
Ejemplo n.º 20
0
def validate(aSum, account):
    for i in range(0, len(aSum)):
        if aSum[i][0] != account:
            fatal.errorAndExit(
                'problem: did not get back expected {} from account summary {}'
                .format(aSum[i], aSum))
Ejemplo n.º 21
0
 def validatePriceIncrement(self):
     if self.details.minTick != self.priceIncrement and len(
             self.marketRule) < 2:
         fatal.errorAndExit('ticks dont match: {} {}'.format(
             self.details.minTick, self.priceIncrement))
Ejemplo n.º 22
0
def setupData(wc, conf, backtestArgs=None):
    dataStore = None
    dataStream = None
    if conf.detector == 'threeBarPattern':
        dataStore = barSet = bars.BarSet()
    if backtestArgs is not None:
        logging.fatal('WARNING: DOING A BACKTEST, NOT USING LIVE DATA')
        if conf.detector == 'Crossover':
            dataStore = Crossover(conf.barSizeStr, wc,
                                  backtestArgs['shortInterval'],
                                  backtestArgs['longInterval'],
                                  backtestArgs['watchCount'])
            dataStore.backTest = True
            dataStream = data.getHistData(wc,
                                          barSizeStr=conf.barSizeStr,
                                          longInterval=dataStore.longInterval,
                                          e=backtestArgs['e'],
                                          d=backtestArgs['d'],
                                          t=backtestArgs['t'],
                                          r=backtestArgs['r'],
                                          f=backtestArgs['f'],
                                          k=backtestArgs['k'])
            dataStore.initIndicators(dataStream)
        else:
            dataStream = data.getHistData(
                wc,
                barSizeStr=conf.barSizeStr,
                longInterval=backtestArgs['longInterval'],
                e=backtestArgs['e'],
                d=backtestArgs['d'],
                t=backtestArgs['t'],
                r=backtestArgs['r'],
                f=backtestArgs['f'],
                k=backtestArgs['k'])
    elif conf.detector == 'threeBarPattern':
        dataStream = wc.getTicker()
    elif conf.detector == 'Crossover':
        dataStore = Crossover(conf.barSizeStr, wc, conf.shortEMA, conf.longEMA,
                              conf.watchCount)

        # disable wrapper logging to hide the API error for canceling the data every hour
        logging.getLogger('ib_insync.wrapper').setLevel(logging.CRITICAL)
        logging.warn('ignoring hdms broken errors')
        wc.ibClient.errorEvent += data.dataStreamErrorHandler

        logging.warn('installing auto restart handler.')
        wc.ibClient.errorEvent += connectivityError

        useRth = False if conf.enterOutsideRth else True
        histData = data.getHistData(wc,
                                    barSizeStr=conf.barSizeStr,
                                    longInterval=dataStore.longInterval,
                                    r=useRth)
        if len(histData) < dataStore.longInterval * 2:
            fatal.fatal(
                conf,
                'did not get back the right amount of data from historical data call, perhaps broken?'
            )
        dataStore.initIndicators(histData)
        wc.realtimeBars()
    else:
        fatal.errorAndExit('do not know what to do!')
    return dataStore, dataStream