예제 #1
0
    def _st_start(self, instart=True, tmout=None):
        if self.p.historical:
            self.put_notification(self.DELAYED)
            dtend = None
            if self.todate < float('inf'):
                dtend = num2date(self.todate)

            dtbegin = None
            if self.fromdate > float('-inf'):
                dtbegin = num2date(self.fromdate)

            self.qhist = self.o.candles(
                self.p.dataname, dtbegin, dtend,
                self._timeframe, self._compression,
                candleFormat=self._candleFormat,
                includeFirst=self.p.includeFirst)

            self._state = self._ST_HISTORBACK
            return True

        self.qlive = self.o.streaming_prices(self.p.dataname, tmout=tmout)
        if instart:
            self._statelivereconn = self.p.backfill_start
        else:
            self._statelivereconn = self.p.backfill

        if self._statelivereconn:
            self.put_notification(self.DELAYED)

        self._state = self._ST_LIVE
        if instart:
            self._reconns = self.p.reconnections

        return True  # no return before - implicit continue
예제 #2
0
    def _st_start(self):
        if self.p.historical:
            self.put_notification(self.DELAYED)
            dtend = None
            if self.todate < float('inf'):
                dtend = num2date(self.todate)

            dtbegin = None
            if self.fromdate > float('-inf'):
                dtbegin = num2date(self.fromdate)

            self.qhist = self.ib.reqHistoricalDataEx(
                contract=self.contract, enddate=dtend, begindate=dtbegin,
                timeframe=self._timeframe, compression=self._compression,
                what=self.p.what, useRTH=self.p.useRTH, tz=self._tz,
                sessionend=self.p.sessionend)

            self._state = self._ST_HISTORBACK
            return True  # continue before

        # Live is requested
        if not self.ib.reconnect(resub=True):
            self.put_notification(self.DISCONNECTED)
            self._state = self._ST_OVER
            return False  # failed - was so

        self._statelivereconn = self.p.backfill_start
        if self.p.backfill_start:
            self.put_notification(self.DELAYED)

        self._state = self._ST_LIVE
        return True  # no return before - implicit continue
예제 #3
0
    def _getnexteos(self):
        '''Returns the next eos using a trading calendar if available'''
        if self._clone:
            return self.data._getnexteos()

        if not len(self):
            return datetime.datetime.min, 0.0

        dt = self.lines.datetime[0]
        dtime = num2date(dt)
        if self._calendar is None:
            nexteos = datetime.datetime.combine(dtime, self.p.sessionend)
            nextdteos = self.date2num(nexteos)  # locl'ed -> utc-like
            nexteos = num2date(nextdteos)  # utc
            while dtime > nexteos:
                nexteos += datetime.timedelta(days=1)  # already utc-like

            nextdteos = date2num(nexteos)  # -> utc-like

        else:
            # returns times in utc
            _, nexteos = self._calendar.schedule(dtime, self._tz)
            nextdteos = date2num(nexteos)  # nextos is already utc

        return nexteos, nextdteos
 def log(self, txt, dt=None, nodate=False):
     if not nodate:
         dt = dt or self.data.datetime[0]
         dt = bt.num2date(dt)
         print('%s, %s' % (dt.isoformat(), txt))
     else:
         print('---------- %s' % (txt))
예제 #5
0
 def notify_order(self, order):
     if not order.alive():
         print('{} {} {}@{}'.format(
             bt.num2date(order.executed.dt),
             'buy' if order.isbuy() else 'sell',
             order.executed.size,
             order.executed.price)
         )
예제 #6
0
 def notify_order(self, order):
     curdtstr = self.data.datetime.datetime().strftime('%a %Y-%m-%d %H:%M:%S')
     if order.status in [order.Completed]:
         dtstr = bt.num2date(order.executed.dt).strftime('%a %Y-%m-%d %H:%M:%S')
         if order.isbuy():
             print('%s: BUY  EXECUTED, on:' % curdtstr, dtstr)
             self.order = None
         else:  # Sell
             print('%s: SELL EXECUTED, on:' % curdtstr, dtstr)
예제 #7
0
    def notify_order(self, order):
        if order.status != order.Completed:
            return

        self.order = None
        print('{} {} Executed at price {}'.format(
            bt.num2date(order.executed.dt).date(),
            'Buy' * order.isbuy() or 'Sell', order.executed.price)
        )
예제 #8
0
    def stop(self):
        # Must have stats.broker
        cur_year = None

        value_start = 0.0
        value_cur = 0.0
        value_end = 0.0

        self.rets = list()
        self.ret = OrderedDict()

        for i in xrange(len(self.strategy.data)):
            dt = num2date(self.strategy.data.datetime.getzeroval(i))

            value_cur = self.strategy.stats.broker.value.getzeroval(i)

            if dt.year > cur_year:

                if cur_year is not None:
                    annualret = (value_end / value_start) - 1.0
                    self.rets.append(annualret)
                    self.ret[cur_year] = annualret

                    # changing between real years, use last value as new start
                    value_start = value_end
                else:
                    # No value set whatsoever, use the currently loaded value
                    value_start = value_cur

                cur_year = dt.year

            # No matter what, the last value is always the last loaded value
            value_end = value_cur

        if cur_year not in self.ret:
            # finish calculating pending data
            annualret = (value_end / value_start) - 1.0
            self.rets.append(annualret)
            self.ret[cur_year] = annualret
예제 #9
0
파일: ibdata.py 프로젝트: Aulla/backtrader
    def _load(self):
        if self.contract is None:
            return False  # nothing can be done

        while True:
            if self._state == self._ST_LIVE:
                try:
                    msg = (self._storedmsg.pop(None, None) or
                           self.qlive.get(timeout=self.p.qcheck))
                except queue.Empty:
                    return None  # indicate timeout situation

                if msg is None:  # Conn broken during historical/backfilling
                    self.put_notification(self.CONNBROKEN)
                    # Try to reconnect
                    if not self.ib.reconnect(resub=True):
                        self.put_notification(self.DISCONNECTED)
                        return False  # failed

                    self._statelivereconn = self.p.backfill
                    continue

                if msg == -354:
                    self.put_notification(self.NOTSUBSCRIBED)
                    return False

                elif msg == -1100:  # conn broken
                    # Tell to wait for a message to do a backfill
                    # self._state = self._ST_DISCONN
                    self._statelivereconn = self.p.backfill
                    continue

                elif msg == -1102:  # conn broken/restored tickerId maintained
                    # The message may be duplicated
                    if not self._statelivereconn:
                        self._statelivereconn = self.p.backfill
                    continue

                elif msg == -1101:  # conn broken/restored tickerId gone
                    # The message may be duplicated
                    if not self._statelivereconn:
                        self._statelivereconn = self.p.backfill
                        self.reqdata()  # resubscribe
                    continue

                elif isinstance(msg, integer_types):
                    # Unexpected notification for historical data skip it
                    # May be a "not connected not yet processed"
                    self.put_notification(self.UNKNOWN, msg)
                    continue

                # Process the message according to expected return type
                if not self._statelivereconn:
                    if self._laststatus != self.LIVE:
                        if self.qlive.qsize() <= 1:  # very short live queue
                            self.put_notification(self.LIVE)

                    if self._usertvol:
                        ret = self._load_rtvolume(msg)
                    else:
                        ret = self._load_rtbar(msg)
                    if ret:
                        return True

                    # could not load bar ... go and get new one
                    continue

                # Fall through to processing reconnect - try to backfill
                self._storedmsg[None] = msg  # keep the msg

                # else do a backfill
                if self._laststatus != self.DELAYED:
                    self.put_notification(self.DELAYED)

                dtend = None
                if len(self) > 1:
                    # len == 1 ... forwarded for the 1st time
                    dtbegin = self.datetime.datetime(-1)
                elif self.fromdate > float('-inf'):
                    dtbegin = num2date(self.fromdate)
                else:  # 1st bar and no begin set
                    # passing None to fetch max possible in 1 request
                    dtbegin = None

                dtend = msg.datetime if self._usertvol else msg.time

                self.qhist = self.ib.reqHistoricalDataEx(
                    self.contract, dtend, dtbegin,
                    self._timeframe, self._compression,
                    what=self.p.what,
                    useRTH=self.p.useRTH)

                self._state = self._ST_HISTORBACK
                self._statelivereconn = False  # no longer in live
                continue

            elif self._state == self._ST_HISTORBACK:
                msg = self.qhist.get()
                if msg is None:  # Conn broken during historical/backfilling
                    # Situation not managed. Simply bail out
                    self.put_notification(self.DISCONNECTED)
                    return False  # error management cancelled the queue

                elif msg == -354:  # Data not subscribed
                    self.put_notification(self.NOTSUBSCRIBED)
                    return False

                elif msg == -420:  # No permissions for the data
                    self.put_notification(self.NOTSUBSCRIBED)
                    return False

                elif isinstance(msg, integer_types):
                    # Unexpected notification for historical data skip it
                    # May be a "not connected not yet processed"
                    self.put_notification(self.UNKNOWN, msg)
                    continue

                if msg.date is not None:
                    if self._load_rtbar(msg, hist=True):
                        return True  # loading worked

                    # the date is from overlapping historical request
                    continue

                # End of histdata
                if self.p.historical:  # only historical
                    self.put_notification(self.DISCONNECTED)
                    return False  # end of historical

                # Live is also wished - go for it
                self._state = self._ST_LIVE
                continue

            elif self._state == self._ST_START:
                if self.p.historical:
                    self.put_notification(self.DELAYED)
                    dtend = None
                    if self.todate < float('inf'):
                        dtend = num2date(self.todate)

                    dtbegin = None
                    if self.fromdate > float('-inf'):
                        dtbegin = num2date(self.fromdate)

                    self.qhist = self.ib.reqHistoricalDataEx(
                        self.contract, dtend, dtbegin,
                        self._timeframe, self._compression,
                        what=self.p.what, useRTH=self.p.useRTH)

                    self._state = self._ST_HISTORBACK
                    continue

                # Live is requested
                if not self.ib.reconnect(resub=True):
                    self.put_notification(self.DISCONNECTED)
                    return False  # failed

                self._statelivereconn = self.p.backfill_start
                if not self.p.backfill_start:
                    self.put_notification(self.DELAYED)

                self._state = self._ST_LIVE

            elif self._state == self._ST_FROM:
                if not self.p.backfill_from.next():
                    # additional data source is consumed
                    self._state = self._ST_START
                    continue

                # copy lines of the same name
                for alias in self.lines.getaliases():
                    lsrc = getattr(self.p.backfill_from.lines, alias)
                    ldst = getattr(self.lines, alias)

                    ldst[0] = lsrc[0]

                return True
예제 #10
0
    def _load(self):
        if self._state == self._ST_OVER:
            return False

        while True:
            if self._state == self._ST_LIVE:
                try:
                    msg = (self._storedmsg.pop(None, None) or
                           self.qlive.get(timeout=self._qcheck))
                except queue.Empty:
                    return None  # indicate timeout situation
                if msg is None:  # Conn broken during historical/backfilling
                    self.put_notification(self.CONNBROKEN)
                    # Try to reconnect
                    if not self.p.reconnect or self._reconns == 0:
                        # Can no longer reconnect
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed

                    self._reconns -= 1
                    self._st_start(instart=False, tmout=self.p.reconntimeout)
                    continue

                if 'code' in msg:
                    self.put_notification(self.CONNBROKEN)
                    code = msg['code']
                    if code not in [599, 598, 596]:
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed

                    if not self.p.reconnect or self._reconns == 0:
                        # Can no longer reconnect
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed

                    # Can reconnect
                    self._reconns -= 1
                    self._st_start(instart=False, tmout=self.p.reconntimeout)
                    continue

                self._reconns = self.p.reconnections

                # Process the message according to expected return type
                if not self._statelivereconn:
                    if self._laststatus != self.LIVE:
                        if self.qlive.qsize() <= 1:  # very short live queue
                            self.put_notification(self.LIVE)

                    ret = self._load_tick(msg)
                    if ret:
                        return True

                    # could not load bar ... go and get new one
                    continue

                # Fall through to processing reconnect - try to backfill
                self._storedmsg[None] = msg  # keep the msg

                # else do a backfill
                if self._laststatus != self.DELAYED:
                    self.put_notification(self.DELAYED)

                dtend = None
                if len(self) > 1:
                    # len == 1 ... forwarded for the 1st time
                    dtbegin = self.datetime.datetime(-1)
                elif self.fromdate > float('-inf'):
                    dtbegin = num2date(self.fromdate)
                else:  # 1st bar and no begin set
                    # passing None to fetch max possible in 1 request
                    dtbegin = None

                dtend = datetime.utcfromtimestamp(int(msg['time']))

                self.qhist = self.o.candles(
                    self.p.dataname, dtbegin, dtend,
                    self._timeframe, self._compression,
                    candleFormat=self._candleFormat,
                    includeFirst=self.p.includeFirst)

                self._state = self._ST_HISTORBACK
                self._statelivereconn = False  # no longer in live
                continue

            elif self._state == self._ST_HISTORBACK:
                msg = self.qhist.get()
                if msg is None:  # Conn broken during historical/backfilling
                    # Situation not managed. Simply bail out
                    self.put_notification(self.DISCONNECTED)
                    self._state = self._ST_OVER
                    return False  # error management cancelled the queue

                elif 'code' in msg:  # Error
                    self.put_notification(self.NOTSUBSCRIBED)
                    self.put_notification(self.DISCONNECTED)
                    self._state = self._ST_OVER
                    return False

                if msg:
                    if self._load_history(msg):
                        return True  # loading worked

                    continue  # not loaded ... date may have been seen
                else:
                    # End of histdata
                    if self.p.historical:  # only historical
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # end of historical

                # Live is also wished - go for it
                self._state = self._ST_LIVE
                continue

            elif self._state == self._ST_FROM:
                if not self.p.backfill_from.next():
                    # additional data source is consumed
                    self._state = self._ST_START
                    continue

                # copy lines of the same name
                for alias in self.lines.getlinealiases():
                    lsrc = getattr(self.p.backfill_from.lines, alias)
                    ldst = getattr(self.lines, alias)

                    ldst[0] = lsrc[0]

                return True

            elif self._state == self._ST_START:
                if not self._st_start(instart=False):
                    self._state = self._ST_OVER
                    return False
예제 #11
0
    def __init__(self, action, **kwargs):

        # Marker to indicate an openOrder has been seen with
        # PendinCancel/Cancelled which is indication of an upcoming
        # cancellation
        self._willexpire = False

        self.ordtype = self.Buy if action == 'BUY' else self.Sell

        super(IBOrder, self).__init__()
        ib.ext.Order.Order.__init__(self)  # Invoke 2nd base class

        # Now fill in the specific IB parameters
        self.m_orderType = self._IBOrdTypes[self.exectype]
        self.m_permid = 0

        # 'B' or 'S' should be enough
        self.m_action = bytes(action)

        # Set the prices
        self.m_lmtPrice = 0.0
        self.m_auxPrice = 0.0

        if self.exectype == self.Market:  # is it really needed for Market?
            pass
        elif self.exectype == self.Close:  # is it ireally needed for Close?
            pass
        elif self.exectype == self.Limit:
            self.m_lmtPrice = self.price
        elif self.exectype == self.Stop:
            self.m_auxPrice = self.price  # stop price / exec is market
        elif self.exectype == self.StopLimit:
            self.m_lmtPrice = self.pricelimit  # req limit execution
            self.m_auxPrice = self.price  # trigger price

        self.m_totalQuantity = abs(self.size)  # ib takes only positives

        self.m_transmit = True

        # Time In Force: DAY, GTC, IOC, GTD
        if self.valid is None:
            tif = 'GTC'  # Good til cancelled
        elif isinstance(self.valid, (datetime, date)):
            tif = 'GTD'  # Good til date
            self.m_goodTillDate = bytes(self.valid.strftime('%Y%m%d %H:%M:%S'))
        elif isinstance(self.valid, (timedelta, )):
            if self.valid == self.DAY:
                tif = 'DAY'
            else:
                tif = 'GTD'  # Good til date
                valid = datetime.now() + self.valid  # .now, using localtime
                self.m_goodTillDate = bytes(valid.strftime('%Y%m%d %H:%M:%S'))

        elif self.valid == 0:
            tif = 'DAY'
        else:
            tif = 'GTD'  # Good til date
            valid = num2date(self.valid)
            self.m_goodTillDate = bytes(valid.strftime('%Y%m%d %H:%M:%S'))

        self.m_tif = bytes(tif)

        # pass any custom arguments to the order
        for k in kwargs:
            setattr(self, (not hasattr(self, k)) * 'm_' + k, kwargs[k])
예제 #12
0
 def num2date(self, dt=None, tz=None, naive=False):
     if dt is None:
         dt = self.lines.datetime[0]
     if tz is None:
         tz = self._tz
     return num2date(dt, tz, naive)
예제 #13
0
    def _load(self):
        if self.contract is None or self._state == self._ST_OVER:
            return False  # nothing can be done

        while True:
            if self._state == self._ST_LIVE:
                try:
                    msg = (self._storedmsg.pop(None, None) or
                           self.qlive.get(timeout=self._qcheck))
                except queue.Empty:
                    if True:
                        return None

                    # Code invalidated until further checking is done
                    if not self._statelivereconn:
                        return None  # indicate timeout situation

                    # Awaiting data and nothing came in - fake it up until now
                    dtend = self.num2date(date2num(datetime.datetime.utcnow()))
                    dtbegin = None
                    if len(self) > 1:
                        dtbegin = self.num2date(self.datetime[-1])

                    self.qhist = self.ib.reqHistoricalDataEx(
                        contract=self.contract,
                        enddate=dtend, begindate=dtbegin,
                        timeframe=self._timeframe,
                        compression=self._compression,
                        what=self.p.what, useRTH=self.p.useRTH, tz=self._tz,
                        sessionend=self.p.sessionend)

                    if self._laststatus != self.DELAYED:
                        self.put_notification(self.DELAYED)

                    self._state = self._ST_HISTORBACK

                    self._statelivereconn = False
                    continue  # to reenter the loop and hit st_historback

                if msg is None:  # Conn broken during historical/backfilling
                    self.put_notification(self.CONNBROKEN)
                    # Try to reconnect
                    if not self.ib.reconnect(resub=True):
                        self.put_notification(self.DISCONNECTED)
                        return False  # failed

                    self._statelivereconn = self.p.backfill
                    continue

                if msg == -354:
                    self.put_notification(self.NOTSUBSCRIBED)
                    return False

                elif msg == -1100:  # conn broken
                    # Tell to wait for a message to do a backfill
                    # self._state = self._ST_DISCONN
                    self._statelivereconn = self.p.backfill
                    continue

                elif msg == -1102:  # conn broken/restored tickerId maintained
                    # The message may be duplicated
                    if not self._statelivereconn:
                        self._statelivereconn = self.p.backfill
                    continue

                elif msg == -1101:  # conn broken/restored tickerId gone
                    # The message may be duplicated
                    if not self._statelivereconn:
                        self._statelivereconn = self.p.backfill
                        self.reqdata()  # resubscribe
                    continue

                elif isinstance(msg, integer_types):
                    # Unexpected notification for historical data skip it
                    # May be a "not connected not yet processed"
                    self.put_notification(self.UNKNOWN, msg)
                    continue

                # Process the message according to expected return type
                if not self._statelivereconn:
                    if self._laststatus != self.LIVE:
                        if self.qlive.qsize() <= 1:  # very short live queue
                            self.put_notification(self.LIVE)

                    if self._usertvol:
                        ret = self._load_rtvolume(msg)
                    else:
                        ret = self._load_rtbar(msg)
                    if ret:
                        return True

                    # could not load bar ... go and get new one
                    continue

                # Fall through to processing reconnect - try to backfill
                self._storedmsg[None] = msg  # keep the msg

                # else do a backfill
                if self._laststatus != self.DELAYED:
                    self.put_notification(self.DELAYED)

                dtend = None
                if len(self) > 1:
                    # len == 1 ... forwarded for the 1st time
                    # get begin date in utc-like format like msg.datetime
                    dtbegin = num2date(self.datetime[-1])
                elif self.fromdate > float('-inf'):
                    dtbegin = num2date(self.fromdate)
                else:  # 1st bar and no begin set
                    # passing None to fetch max possible in 1 request
                    dtbegin = None

                dtend = msg.datetime if self._usertvol else msg.time

                self.qhist = self.ib.reqHistoricalDataEx(
                    contract=self.contract, enddate=dtend, begindate=dtbegin,
                    timeframe=self._timeframe, compression=self._compression,
                    what=self.p.what, useRTH=self.p.useRTH, tz=self._tz,
                    sessionend=self.p.sessionend)

                self._state = self._ST_HISTORBACK
                self._statelivereconn = False  # no longer in live
                continue

            elif self._state == self._ST_HISTORBACK:
                msg = self.qhist.get()
                if msg is None:  # Conn broken during historical/backfilling
                    # Situation not managed. Simply bail out
                    self.put_notification(self.DISCONNECTED)
                    return False  # error management cancelled the queue

                elif msg == -354:  # Data not subscribed
                    self.put_notification(self.NOTSUBSCRIBED)
                    return False

                elif msg == -420:  # No permissions for the data
                    self.put_notification(self.NOTSUBSCRIBED)
                    return False

                elif isinstance(msg, integer_types):
                    # Unexpected notification for historical data skip it
                    # May be a "not connected not yet processed"
                    self.put_notification(self.UNKNOWN, msg)
                    continue

                if msg.date is not None:
                    if self._load_rtbar(msg, hist=True):
                        return True  # loading worked

                    # the date is from overlapping historical request
                    continue

                # End of histdata
                if self.p.historical:  # only historical
                    self.put_notification(self.DISCONNECTED)
                    return False  # end of historical

                # Live is also wished - go for it
                self._state = self._ST_LIVE
                continue

            elif self._state == self._ST_FROM:
                if not self.p.backfill_from.next():
                    # additional data source is consumed
                    self._state = self._ST_START
                    continue

                # copy lines of the same name
                for alias in self.lines.getlinealiases():
                    lsrc = getattr(self.p.backfill_from.lines, alias)
                    ldst = getattr(self.lines, alias)

                    ldst[0] = lsrc[0]

                return True

            elif self._state == self._ST_START:
                if not self._st_start():
                    return False
예제 #14
0
 def log(self, txt, dt=None):
     """Вывод строки с датой на консоль"""
     dt = bt.num2date(self.datas[0].datetime[0]).date(
     ) if dt is None else dt  # Заданная дата или дата текущего бара
     print(f'{dt.strftime("%d.%m.%Y")}, {txt}'
           )  # Выводим дату с заданным текстом на консоль
 def log(self, txt, dt=None):
     """Вывод строки с датой на консоль"""
     dt = bt.num2date(self.datas[0].datetime[0]) if dt is None else dt
     print(f'{dt.strftime("%d.%m.%Y %H:%M")}, {txt}')
예제 #16
0
 def next(self):
     msg = '***** NEXT: {} '.format(
         bt.num2date(self.data.datetime[0], pytz.timezone('Asia/Shanghai')))
     for d in self.datas:
         msg += '{} {} {} '.format(d._name, len(d), d.close[0])
     print(msg)
예제 #17
0
    def _load(self):
        if self.contract is None:
            self.put_notification(self.DISCONNECTED)
            return False  # nothing can be done

        while True:
            if self._state == self._ST_START:
                if self.p.historical:
                    self.put_notification(self.DELAYED)
                    dtend = None
                    if self.todate < float('inf'):
                        dtend = num2date(self.todate)

                    dtbegin = None
                    if self.fromdate > float('-inf'):
                        dtbegin = num2date(self.fromdate)

                    self.qhist = self.ib.reqHistoricalDataEx(
                        self.contract, dtend, dtbegin,
                        self._timeframe, self._compression,
                        what=self.p.what, useRTH=self.p.useRTH)

                    self._state = self._ST_HISTORBACK
                    continue

                # Live is requested
                if not self.ib.reconnect(resub=True):
                    self.put_notification(self.DISCONNECTED)
                    return False  # failed

                self.put_notification(self.DELAYED)
                self._statelivereconn = True  # attempt backfilling
                self._state = self._ST_LIVE

            elif self._state == self._ST_HISTORBACK:
                msg = self.qhist.get()
                if msg is None:  # Conn broken during historical/backfilling
                    # Situation not managed. Simply bail out
                    self.put_notification(self.DISCONNECTED)
                    return False  # error management cancelled the queue

                if msg.date is not None:
                    if self._load_rtbar(msg, hist=True):
                        return True  # loading worked

                    # the date is from overlapping historical request
                    continue

                # End of histdata
                if self.p.historical:  # only historical
                    self.put_notification(self.DISCONNECTED)
                    return False  # end of historical

                # Live is also wished - go for it
                self._state = self._ST_LIVE
                continue

            elif self._state == self._ST_LIVE:
                try:
                    # FIXME: timeout as parameter and automatically calculated
                    # with a potentially top limit
                    msg = self._storedmsg.pop(
                        None, self.qlive.get(timeout=2.0))
                except queue.Empty:
                    return None  # indicate timeout situation

                if msg is None:  # Conn broken during historical/backfilling
                    self.put_notification(self.CONNBROKEN)
                    # Try to reconnect
                    if not self.ib.reconnect(resub=True):
                        self.put_notification(self.DISCONNECTED)
                        return False  # failed

                    self._statelivereconn = True
                    continue

                if msg == -1102:  # conn broken/restored / tickerId maintained
                    self._statelivereconn = True  # backfill and live again
                    continue

                elif msg == -1101:  # conn broken/restored tickerId gone
                    self._statelivereconn = True  # backfill and live again
                    self.reqdata()  # resubscribe
                    continue

                # Process the message according to expected return type
                if not self._statelivereconn:
                    if self._laststatus != self.LIVE:
                        if self.qlive.qsize() <= 1:  # very short live queue
                            self.put_notification(self.LIVE)

                    if not self.p.useRT or self.cashtype:
                        return self._load_rtvolume(msg)

                    return self._load_rtbar(msg)

                # Fall through to processing reconnect - try to backfill
                self._storedmsg[None] = msg  # keep the msg

                # else do a backfill
                self.put_notification(self.DELAYED)

                dtend = None
                if len(self) > 1:
                    # len == 1 ... forwarded for the 1st time
                    dtbegin = self.datetime.datetime(-1)
                elif self.fromdate > float('-inf'):
                    dtbegin = num2date(self.fromdate)
                else:  # 1st bar and no begin set
                    # passing None to fetch max possible in 1 request
                    dtbegin = None

                rtvolume = not self.p.useRT or self.cashtype
                dtend = msg.datetime if rtvolume else msg.time

                self.qhist = self.ib.reqHistoricalDataEx(
                    self.contract, dtend, dtbegin,
                    self._timeframe, self._compression,
                    what=self.p.what,
                    useRTH=self.p.useRTH)

                self._state = self._ST_HISTORBACK
                self._statelivereconn = False
                continue
예제 #18
0
    def _load(self):
        '''
        steps

        1 - check if we status live. If so process message
                - Check for error codes in message and change status appropriately
                - Process the message as long as the status is not trying to reconnect
                - Setup a backfill if data is missing.
        2 - If not, is the status set to perform a backfill?

        '''

        if self._state == self._ST_OVER:
            return False

        while True:
            if self._state == self._ST_LIVE:
                try:
                    msg = (self._storedmsg.pop(None, None)
                           or self.qlive.get(timeout=self._qcheck))
                except queue.Empty:
                    return None  # indicate timeout situation

                if msg is None:  # Conn broken during historical/backfilling
                    self.put_notification(self.CONNBROKEN)
                    self.put_notification(self.DISCONNECTED)
                    self._state = self._ST_OVER
                    return False  # failed

                #TODO handle error messages in feed

                #Check for empty data. Sometimes all the fields return None...
                if msg['UTM'] is None:
                    return None

                #self._reconns = self.p.reconnections

                # Process the message according to expected return type
                if not self._statelivereconn:
                    if self._laststatus != self.LIVE:
                        if self.qlive.qsize() <= 1:  # very short live queue
                            self.put_notification(self.LIVE)

                    ret = self._load_tick(msg)
                    if ret:
                        return True

                    # could not load bar ... go and get new one
                    continue

                dtend = None
                if len(self) > 1:
                    # len == 1 ... forwarded for the 1st time
                    dtbegin = self.datetime.datetime(-1)
                elif self.fromdate > float('-inf'):
                    dtbegin = num2date(self.fromdate)
                else:  # 1st bar and no begin set
                    # passing None to fetch max possible in 1 request
                    dtbegin = None

                if dtbegin:
                    dtend = datetime.utcfromtimestamp(int(msg['time']) / 10**6)

                    self.qhist = self.o.candles(self.p.dataname, dtbegin,
                                                dtend, self._timeframe,
                                                self._compression)
                else:
                    self.qhist = self.o.candles(self.p.dataname,
                                                dtbegin,
                                                dtend,
                                                self._timeframe,
                                                self._compression,
                                                numpoints=True,
                                                bars=self.p.backfill_bars)

                self._state = self._ST_HISTORBACK
                self._statelivereconn = False  # no longer in live

                continue

            elif self._state == self._ST_HISTORBACK:
                msg = self.qhist.get()
                if msg is None:  # Conn broken during historical/backfilling
                    # Situation not managed. Simply bail out
                    self.put_notification(self.DISCONNECTED)
                    self._state = self._ST_OVER
                    return False  # error management cancelled the queue

                if msg:
                    if self._load_history(msg):
                        return True  # loading worked

                    continue  # not loaded ... date may have been seen
                else:
                    # End of histdata
                    if self.p.historical:  # only historical
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # end of historical

                # Live is also wished - go for it
                self._state = self._ST_LIVE
                continue

            elif self._state == self._ST_START:
                if not self._st_start(instart=False):
                    self._state = self._ST_OVER
                    return False
예제 #19
0
 def log(self, txt, dt=None):
     if self.p.printout:
         dt = dt or self.data.datetime[0]
         dt = bt.num2date(dt)
         print(f'{dt.isoformat()}  {txt}')
예제 #20
0
 def next(self):
     print('*' * 5, 'NEXT:', bt.num2date(self.data0.datetime[0]),
           self.data0._name, self.data0.open[0],
           bt.TimeFrame.getname(self.data0._timeframe), len(self.data0))
예제 #21
0
 def log(txt, dt=None, data=None):
     dt = dt or data.datetime[0]
     dt = bt.num2date(dt)
     _logger.info('%s, %s' % (dt.isoformat(), txt))
예제 #22
0
 def get_clock_time_at_idx(self, idx):
     return bt.num2date(self._clk.array[idx], self._tz)
예제 #23
0
    if False:
        # save the indicator
        print('save the indicator')
        Indicator_utl = HdfUtility()
        stat = cerebro.runstrats[0][0]
        indicator_byvt = stat.Mmt_ind
        params = cerebro.runstrats[0][0].od_params
        for indicator, vt in indicator_byvt.items():
            indicator_data = indicator.array
            tradingday = cerebro.datasbyname(vt + '0000').datetime.array
            df = pd.DataFrame({
                'Indicator': indicatoe_data,
                'Date': tradingday
            })
            date_parse = lambda x: num2date(x)
            df['Date'] = df['Date'].apply(date_parse)
            excode = params['excode'][params['vt'].index(vt)]
            Indicator_utl.hdfWrite(
                EXT_Hdf_Path,
                excode,
                vt,
                df.set_index('Date'),
                kind1='Indicator',
                kind2=stat.indicator_name,
                kind3={'window_prd': stat.params.rollover_window_prd})

    # 由于多个品种,所以品种的收盘价数据就不画了
    for data in cerebro.datas:
        data.plotinfo.plot = False
    cerebro.plot()
예제 #24
0
    def notify_order(self, order):
        date = self.data.datetime.datetime().date()
        if order.status == order.Submitted:
            print('-'*32,' NOTIFY ORDER ','-'*32)
            print(f'{order.info.ticker} Order Submitted')
            print('{}, Status: {}, Type: {}-{}, Ref: {}, Size: {}, Price: {}'.format(
                                                        date,
                                                        order.status,
                                                        order.ordtypename(),
                                                        order.getordername(),
                                                        order.ref,
                                                        order.size,
                                                        'NA' if not order.price else round(order.price,5)
                                                        ))

            print('-'*80)

        if order.status == order.Accepted:
            print('-'*32,' NOTIFY ORDER ','-'*32)
            print(f'{order.info.ticker} Order Accepted')
            print('{}, Status: {}, Type: {}-{}, Ref: {}, Size: {}, Price: {}'.format(
                                                        date,
                                                        order.status,
                                                        order.ordtypename(),
                                                        order.getordername(),
                                                        order.ref,
                                                        order.size,
                                                        'NA' if not order.price else round(order.price,5)
                                                        ))
            print('-'*80)

        if order.status == order.Completed:
            print('-'*32,' NOTIFY ORDER ','-'*32)
            print(f'{order.info.ticker} Completed')
            print('{}, Status: {}, Type: {}-{}, Ref: {}, Size: {}, Price: {}'.format(
                                                        date,
                                                        order.status,
                                                        order.getordername(),
                                                        order.ordtypename(),
                                                        order.ref,
                                                        order.size,
                                                        'NA' if not order.price else round(order.price,5)
                                                        ))
            print('Created: {} Price: {} Size: {}'.format(bt.num2date(order.created.dt), order.created.price,order.created.size))
            print('-'*80)

        if order.status == order.Canceled:
            print('-'*32,' NOTIFY ORDER ','-'*32)
            print(f'Order Canceled')
            print('{}, Status {}: Type: {}-{}, Ref: {}, Size: {}, Price: {}'.format(
                                                        date,
                                                        order.status,
                                                        order.getordername(),
                                                        order.ordtypename(),
                                                        order.ref,
                                                        order.size,
                                                        'NA' if not order.price else round(order.price,5)
                                                        ))
            print('-'*80)

        if order.status == order.Rejected:
            print('-'*32,' NOTIFY ORDER ','-'*32)
            print(f'WARNING! {order.info.ticker} Order Rejected')
            print('{}, Status: {}, Type: {}-{}, Ref: {}, Size: {}, Price: {}'.format(
                                                        date,
                                                        order.status,
                                                        order.getordername(),
                                                        order.ordtypename(),
                                                        order.ref,
                                                        order.size,
                                                        'NA' if not order.price else round(order.price,5)
                                                        ))
            print('-'*80)
예제 #25
0
 def log(self, txt, dt=None):
     dt = dt or bt.num2date(self.datetime[0])
     print('%s, %s' % (dt.isoformat(), txt))
예제 #26
0
 def notify_order(self, order):
     if not order.alive():
         print('{} {} {}@{}'.format(bt.num2date(order.executed.dt),
                                    'buy' if order.isbuy() else 'sell',
                                    order.executed.size,
                                    order.executed.price))
예제 #27
0
 def next(self):
     # 记录收盘价
     if self.order:  # 检查是否有指令等待执行,
         return
     for i, data in enumerate(self.datas):
         position = self.getposition(data=data)
         name = data._name
         if not position:
             if data.close[0] > self.sma[i][0]:
                 # 执行买入
                 upper_price = round(data.close[0]*1.05,2)
                 self.log('BUY %s CREATE,close_price:%.2f,upper_price:%.2f' % (name, data.close[0],upper_price))
                 self.order = self.buy(data,exectype=bt.Order.Limit,price=upper_price,valid=bt.num2date(data.datetime[1]))
                 # self.order = self.buy(data)
         else:
             # 执行卖出条件判断:收盘价格跌破15日均线
             if data.close[0] < self.sma[i][0]:
                 self.log('SELL %s CREATE, %.2f' % (name, data.close[0]))
                 # 执行卖出
                 self.order = self.sell(data)
예제 #28
0
 def log(self, txt, dt=None):
     dt = dt or self.data.datetime[0]
     dt = bt.num2date(dt)
     print('[%s] %s' % (dt.isoformat(), txt))
예제 #29
0
 def log(self, txt, dt=None):
     ''' Logging function fot this strategy'''
     dt = dt or self.data.datetime[0]
     if isinstance(dt, float):
         dt = bt.num2date(dt)
     print('%s, %s' % (dt.isoformat(), txt))
예제 #30
0
    def num2date(self, dt=None, tz=None, naive=True):
        if dt is None:
            return num2date(self.lines.datetime[0], tz or self._tz, naive)

        return num2date(dt, tz or self._tz, naive)
예제 #31
0
 def next(self):
     print('*' * 5, 'NEXT:', bt.num2date(self.data.datetime[0]),
           self.data._name, self.data.open[0], self.data.high[0],
           self.data.low[0], self.data.close[0], self.data.volume[0],
           bt.TimeFrame.getname(self.data._timeframe), len(self.data))
예제 #32
0
    def num2date(self, dt=None, tz=None, naive=True):
        if dt is None:
            return num2date(self.lines.datetime[0], tz or self._tz, naive)

        return num2date(dt, tz or self._tz, naive)
예제 #33
0
 def log(self, txt, dt=None):
     if self.p.printout:
         dt = dt or self.data.datetime[0]
         dt = bt.num2date(dt)
         print('%s, %s' % (dt.isoformat(), txt))
예제 #34
0
    def _blueprint_strategy(self,
                            strategy: bt.Strategy,
                            start=None,
                            end=None,
                            **kwargs):
        if not strategy.datas:
            return

        if not len(strategy):
            return

        strat_figures = []
        self._fp.analyzers = [a for _, a in strategy.analyzers.getitems()]

        st_dtime = strategy.lines.datetime.plot()
        if start is None:
            start = 0
        if end is None:
            end = len(st_dtime)

        if isinstance(start, datetime.date):
            start = bisect.bisect_left(st_dtime, bt.date2num(start))

        if isinstance(end, datetime.date):
            end = bisect.bisect_right(st_dtime, bt.date2num(end))

        if end < 0:
            end = len(st_dtime) + 1 + end  # -1 =  len() -2 = len() - 1

        # TODO: using a pandas.DataFrame is desired. On bokeh 0.12.13 this failed cause of this issue:
        # https://github.com/bokeh/bokeh/issues/7400
        strat_clk: array[float] = strategy.lines.datetime.plotrange(start, end)

        if self._fp.cds is None:
            # we use timezone of first data
            dtline = [bt.num2date(x, strategy.datas[0]._tz) for x in strat_clk]

            # add an index line to use as x-axis (instead of datetime axis) to avoid datetime gaps (e.g. weekends)
            indices = list(range(0, len(dtline)))
            self._fp.cds = ColumnDataSource(
                data=dict(datetime=dtline, index=indices))

        self._build_graph(strategy.datas, strategy.getindicators(),
                          strategy.getobservers())

        start, end = Bokeh._get_start_end(strategy, start, end)

        # reset hover container to not mix hovers with other strategies
        hoverc = HoverContainer()

        for master, slaves in self._data_graph.items():
            plotabove = getattr(master.plotinfo, 'plotabove', False)
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme, type(master), plotabove)
            strat_figures.append(bf)

            bf.plot(master, strat_clk, None)

            for s in slaves:
                bf.plot(s, strat_clk, master)

        for v in self._volume_graphs:
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme)
            bf.plot_volume(v, strat_clk, 1.0, start, end)

        # apply legend click policy
        for f in strat_figures:
            f.figure.legend.click_policy = self.p.scheme.legend_click

        for f in strat_figures:
            f.figure.legend.background_fill_color = self.p.scheme.legend_background_color
            f.figure.legend.label_text_color = self.p.scheme.legend_text_color

        # link axis
        for i in range(1, len(strat_figures)):
            strat_figures[i].figure.x_range = strat_figures[0].figure.x_range

        # configure xaxis visibility
        if self.p.scheme.xaxis_pos == "bottom":
            for i, f in enumerate(strat_figures):
                f.figure.xaxis.visible = False if i <= len(
                    strat_figures) else True

        hoverc.apply_hovertips(strat_figures)

        self._fp.figures += strat_figures
예제 #35
0
    def _plot_strategy(self,
                       strategy: bt.Strategy,
                       start=None,
                       end=None,
                       **kwargs):
        if not strategy.datas:
            return

        if not len(strategy):
            return

        strat_figures = []
        # reset hover container to not mix hovers with other strategies
        hoverc = HoverContainer()
        for name, a in strategy.analyzers.getitems():
            self._fp.analyzers.append((name, a, strategy, None))

        # TODO: using a pandas.DataFrame is desired. On bokeh 0.12.13 this failed cause of this issue:
        # https://github.com/bokeh/bokeh/issues/7400

        if self._fp.cds is None:
            # use datetime line of first data as master datetime. also convert it according to user provided tz
            dtline = pandas.Series([
                bt.num2date(x, strategy.datas[0]._tz)
                for x in strategy.datas[0].lines.datetime.plotrange(
                    start, end)
            ],
                                   name="DateTime")
            self._fp.cds = ColumnDataSource(data={'datetime': dtline})

        self._build_graph(strategy.datas, strategy.getindicators(),
                          strategy.getobservers())

        start, end = Bokeh._get_start_end(strategy, start, end)

        for master, slaves in self._data_graph.items():
            plotabove = getattr(master.plotinfo, 'plotabove', False)
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme, type(master), plotabove)
            strat_figures.append(bf)

            bf.plot(master, None)

            for s in slaves:
                bf.plot(s, master)

        for v in self._volume_graphs:
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme)
            bf.plot_volume(v, 1.0, start, end)

        # apply legend click policy
        for f in strat_figures:
            f.figure.legend.click_policy = self.p.scheme.legend_click

        for f in strat_figures:
            f.figure.legend.background_fill_color = self.p.scheme.legend_background_color
            f.figure.legend.label_text_color = self.p.scheme.legend_text_color

        # link axis
        for i in range(1, len(strat_figures)):
            strat_figures[i].figure.x_range = strat_figures[0].figure.x_range

        # configure xaxis visibility
        if self.p.scheme.xaxis_pos == "bottom":
            for i, f in enumerate(strat_figures):
                f.figure.xaxis.visible = False if i <= len(
                    strat_figures) else True

        hoverc.apply_hovertips(strat_figures)

        self._fp.figures += strat_figures
예제 #36
0
    def __init__(self, action, **kwargs):

        # Marker to indicate an openOrder has been seen with
        # PendinCancel/Cancelled which is indication of an upcoming
        # cancellation
        self._willexpire = False

        self.ordtype = self.Buy if action == 'BUY' else self.Sell

        super(IBOrder, self).__init__()
        ib.ext.Order.Order.__init__(self)  # Invoke 2nd base class

        # Now fill in the specific IB parameters
        self.m_orderType = self._IBOrdTypes[self.exectype]
        self.m_permid = 0

        # 'B' or 'S' should be enough
        self.m_action = bytes(action)

        # Set the prices
        self.m_lmtPrice = 0.0
        self.m_auxPrice = 0.0

        if self.exectype == self.Market:  # is it really needed for Market?
            pass
        elif self.exectype == self.Close:  # is it ireally needed for Close?
            pass
        elif self.exectype == self.Limit:
            self.m_lmtPrice = self.price
        elif self.exectype == self.Stop:
            self.m_auxPrice = self.price  # stop price / exec is market
        elif self.exectype == self.StopLimit:
            self.m_lmtPrice = self.pricelimit  # req limit execution
            self.m_auxPrice = self.price  # trigger price

        self.m_totalQuantity = abs(self.size)  # ib takes only positives

        self.m_transmit = True

        # Time In Force: DAY, GTC, IOC, GTD
        if self.valid is None:
            tif = 'GTC'  # Good til cancelled
        elif isinstance(self.valid, (datetime, date)):
            tif = 'GTD'  # Good til date
            self.m_goodTillDate = bytes(self.valid.strftime('%Y%m%d %H:%M:%S'))
        elif isinstance(self.valid, (timedelta,)):
            if self.valid == self.DAY:
                tif = 'DAY'
            else:
                tif = 'GTD'  # Good til date
                valid = datetime.now() + self.valid  # .now, using localtime
                self.m_goodTillDate = bytes(valid.strftime('%Y%m%d %H:%M:%S'))

        elif self.valid == 0:
            tif = 'DAY'
        else:
            tif = 'GTD'  # Good til date
            valid = num2date(self.valid)
            self.m_goodTillDate = bytes(valid.strftime('%Y%m%d %H:%M:%S'))

        self.m_tif = bytes(tif)

        # pass any custom arguments to the order
        for k in kwargs:
            setattr(self, (not hasattr(self, k)) * 'm_' + k, kwargs[k])
예제 #37
0
 def log(self, txt, dt=None):
     ''' Logging function fot this strategy'''
     dt = dt or self.data.datetime[0]
     if isinstance(dt, float):
         dt = bt.num2date(dt)
     print('%s, %s' % (dt.isoformat(), txt))
예제 #38
0
    def _load(self):
        if self._state == self._ST_OVER:
            return False

        while True:
            if self._state == self._ST_LIVE:
                try:
                    msg = (self._storedmsg.pop(None, None)
                           or self.qlive.get(timeout=self._qcheck))
                except queue.Empty:
                    return None

                if 'msg' in msg:
                    self.put_notification(self.CONNBROKEN)

                    if not self.p.reconnect or self._reconns == 0:
                        # Can no longer reconnect
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed
                    # sleep only on reconnect
                    if self._reconns != self.p.reconnections:
                        _time.sleep(self.o.p.reconntimeout)
                    # Can reconnect
                    self._reconns -= 1
                    self._st_start(instart=False)
                    continue

                self._reconns = self.p.reconnections

                # Process the message according to expected return type
                if not self._statelivereconn:
                    if self._laststatus != self.LIVE:
                        if self.qlive.qsize() <= 1:  # very short live queue
                            self.put_notification(self.LIVE)
                    if msg:
                        if self.p.candles:
                            ret = self._load_candle(msg)
                        else:
                            ret = self._load_tick(msg)
                        if ret:
                            return True

                    # could not load bar ... go and get new one
                    continue

                # Fall through to processing reconnect - try to backfill
                self._storedmsg[None] = msg  # keep the msg

                # else do a backfill
                if self._laststatus != self.DELAYED:
                    self.put_notification(self.DELAYED)

                dtend = None
                if len(self) > 1:
                    # len == 1 ... forwarded for the 1st time
                    dtbegin = self.datetime.datetime(-1).astimezone(
                        timezone.utc)
                elif self.fromdate > float('-inf'):
                    dtbegin = num2date(self.fromdate, tz=timezone.utc)
                else:  # 1st bar and no begin set
                    # passing None to fetch max possible in 1 request
                    dtbegin = None
                if msg:
                    dtend = datetime.utcfromtimestamp(float(msg['time']))

                # TODO not sure if incomplete candles may destruct something
                self.qhist = self.o.candles(self.p.dataname,
                                            dtbegin,
                                            dtend,
                                            self._timeframe,
                                            self._compression,
                                            candleFormat=self._candleFormat,
                                            includeFirst=True,
                                            onlyComplete=False)

                self._state = self._ST_HISTORBACK
                self._statelivereconn = False  # no longer in live
                continue

            elif self._state == self._ST_HISTORBACK:
                msg = self.qhist.get()
                if msg is None:
                    continue

                elif 'msg' in msg:  # Error
                    if not self.p.reconnect or self._reconns == 0:
                        # Can no longer reconnect
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed

                    # Can reconnect
                    self._reconns -= 1
                    self._st_start(instart=False)
                    continue

                if msg:
                    if self._load_candle(msg):
                        return True  # loading worked
                    continue  # not loaded ... date may have been seen
                else:
                    # End of histdata
                    if self.p.historical:  # only historical
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # end of historical

                # Live is also wished - go for it
                self._state = self._ST_LIVE
                continue

            elif self._state == self._ST_FROM:
                if not self.p.backfill_from.next():
                    # additional data source is consumed
                    self._state = self._ST_START
                    continue

                # copy lines of the same name
                for alias in self.l.getlinealiases():
                    lsrc = getattr(self.p.backfill_from.lines, alias)
                    ldst = getattr(self.lines, alias)

                    ldst[0] = lsrc[0]

                return True

            elif self._state == self._ST_START:
                if not self._st_start(instart=False):
                    self._state = self._ST_OVER
                    return False
예제 #39
0
    def load(self):
        while True:
            # move data pointer forward for new bar
            self.forward()

            if self._fromstack():  # bar is available
                return True

            if not self._fromstack(stash=True):
                _loadret = self._load()
                if not _loadret:  # no bar use force to make sure in exactbars
                    # the pointer is undone this covers especially (but not
                    # uniquely) the case in which the last bar has been seen
                    # and a backwards would ruin pointer accounting in the
                    # "stop" method of the strategy
                    self.backwards(force=True)  # undo data pointer

                    # return the actual returned value which may be None to
                    # signal no bar is available, but the data feed is not
                    # done. False means game over
                    return _loadret

            # Get a reference to current loaded time
            dt = self.lines.datetime[0]

            # A bar has been loaded, adapt the time
            if self._tzinput:
                # Input has been converted at face value but it's not UTC in
                # the input stream
                dtime = num2date(dt)  # get it in a naive datetime
                # localize it
                dtime = self._tzinput.localize(dtime)  # pytz compatible-ized
                self.lines.datetime[0] = dt = date2num(dtime)  # keep UTC val

            # Check standard date from/to filters
            if dt < self.fromdate:
                # discard loaded bar and carry on
                self.backwards()
                continue
            if dt > self.todate:
                # discard loaded bar and break out
                self.backwards(force=True)
                break

            # Pass through filters
            retff = False
            for ff, fargs, fkwargs in self._filters:
                # previous filter may have put things onto the stack
                if self._barstack:
                    for i in range(len(self._barstack)):
                        self._fromstack(forward=True)
                        retff = ff(self, *fargs, **fkwargs)
                else:
                    retff = ff(self, *fargs, **fkwargs)

                if retff:  # bar removed from systemn
                    break  # out of the inner loop

            if retff:  # bar removed from system - loop to get new bar
                continue  # in the greater loop

            # Checks let the bar through ... notify it
            return True

        # Out of the loop ... no more bars or past todate
        return False
    def notify_trade(self, trade):

        if trade.isclosed:

            brokervalue = self.strategy.broker.getvalue()

            dir = 'short'
            if trade.history[0].event.size > 0: dir = 'long'

            pricein = trade.history[len(trade.history) - 1].status.price
            priceout = trade.history[len(trade.history) - 1].event.price
            datein = bt.num2date(trade.history[0].status.dt)
            dateout = bt.num2date(trade.history[len(trade.history) -
                                                1].status.dt)
            if trade.data._timeframe >= bt.TimeFrame.Days:
                datein = datein.date()
                dateout = dateout.date()

            pcntchange = 100 * priceout / pricein - 100
            pnl = trade.history[len(trade.history) - 1].status.pnlcomm
            pnlpcnt = 100 * pnl / brokervalue
            barlen = trade.history[len(trade.history) - 1].status.barlen
            pbar = (pnl /
                    barlen) if barlen else pnl  # to avoid divide by 0 error
            self.cumprofit += pnl

            size = value = 0.0
            for record in trade.history:
                if abs(size) < abs(record.status.size):
                    size = record.status.size
                    value = record.status.value

            highest_in_trade = max(trade.data.high.get(ago=0, size=barlen + 1))
            lowest_in_trade = min(trade.data.low.get(ago=0, size=barlen + 1))
            hp = 100 * (highest_in_trade - pricein) / pricein
            lp = 100 * (lowest_in_trade - pricein) / pricein
            if dir == 'long':
                mfe = hp
                mae = lp
            if dir == 'short':
                mfe = -lp
                mae = -hp

            analyzer_result = {
                'run_id':
                self.strategy.db_run_id,
                'strategy':
                self.strategy.alias,
                'recorded_time':
                datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                'ref':
                trade.ref,
                'ticker':
                trade.data._name,
                'direction':
                dir,
                'datein':
                datein,
                'pricein':
                pricein,
                'dateout':
                dateout,
                'priceout':
                priceout,
                'change_percentage':
                round(pcntchange, 2),
                'pnl':
                pnl,
                'pnl_percentage':
                round(pnlpcnt, 2),
                'size':
                size,
                'value':
                value,
                'cumpnl':
                self.cumprofit,
                'nbars':
                barlen,
                'pnl_per_bar':
                round(pbar, 2),
                'mfe_percentage':
                round(mfe, 2),
                'mae_percentage':
                round(mae, 2)
            }

            write_to_db.write_to_db(conn=self.conn,
                                    data_dict=analyzer_result,
                                    table='position_performance')
            self.trades.append(analyzer_result)
예제 #41
0
    def load(self):
        while True:
            # move data pointer forward for new bar
            self.forward()

            if self._fromstack():  # bar is available
                return True

            if not self._fromstack(stash=True):
                _loadret = self._load()
                if not _loadret:  # no bar use force to make sure in exactbars
                    # the pointer is undone this covers especially (but not
                    # uniquely) the case in which the last bar has been seen
                    # and a backwards would ruin pointer accounting in the
                    # "stop" method of the strategy
                    self.backwards(force=True)  # undo data pointer

                    # return the actual returned value which may be None to
                    # signal no bar is available, but the data feed is not
                    # done. False means game over
                    return _loadret

            # Get a reference to current loaded time
            dt = self.lines.datetime[0]

            # A bar has been loaded, adapt the time
            if self._tzinput:
                # Input has been converted at face value but it's not UTC in
                # the input stream
                dtime = num2date(dt)  # get it in a naive datetime
                # localize it
                dtime = self._tzinput.localize(dtime)  # pytz compatible-ized
                self.lines.datetime[0] = dt = date2num(dtime)  # keep UTC val

            # Check standard date from/to filters
            if dt < self.fromdate:
                # discard loaded bar and carry on
                self.backwards()
                continue
            if dt > self.todate:
                # discard loaded bar and break out
                self.backwards(force=True)
                break

            # Pass through filters
            retff = False
            for ff, fargs, fkwargs in self._filters:
                # previous filter may have put things onto the stack
                if self._barstack:
                    for i in range(len(self._barstack)):
                        self._fromstack(forward=True)
                        retff = ff(self, *fargs, **fkwargs)
                else:
                    retff = ff(self, *fargs, **fkwargs)

                if retff:  # bar removed from systemn
                    break  # out of the inner loop

            if retff:  # bar removed from system - loop to get new bar
                continue  # in the greater loop

            # Checks let the bar through ... notify it
            return True

        # Out of the loop ... no more bars or past todate
        return False
예제 #42
0
 def log(self, txt, dt=None, doprint=False):
     ''' Logging function fot this strategy'''
     if self.params.printlog or doprint:
         dt = dt or bt.num2date(self.data.datetime[0])
         print('%s, %s' % (dt, txt))
예제 #43
0
    def _load(self):
        if self._state == self._ST_OVER:
            return False

        while True:
            if self._state == self._ST_LIVE:
                try:
                    msg = (self._storedmsg.pop(None, None) or
                           self.qlive.get(timeout=self._qcheck))
                except queue.Empty:
                    return None  # indicate timeout situation

                if msg is None:  # Conn broken during historical/backfilling
                    self.put_notification(self.CONNBROKEN)
                    # Try to reconnect
                    if not self.p.reconnect or self._reconns == 0:
                        # Can no longer reconnect
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed

                    self._reconns -= 1
                    self._st_start(instart=False, tmout=self.p.reconntimeout)
                    continue

                if 'code' in msg:
                    self.put_notification(self.CONNBROKEN)
                    code = msg['code']
                    if code not in [599, 598, 596]:
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed

                    if not self.p.reconnect or self._reconns == 0:
                        # Can no longer reconnect
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # failed

                    # Can reconnect
                    self._reconns -= 1
                    self._st_start(instart=False, tmout=self.p.reconntimeout)
                    continue

                self._reconns = self.p.reconnections

                # Process the message according to expected return type
                if not self._statelivereconn:
                    if self._laststatus != self.LIVE:
                        if self.qlive.qsize() <= 1:  # very short live queue
                            self.put_notification(self.LIVE)

                    ret = self._load_tick(msg)
                    if ret:
                        return True

                    # could not load bar ... go and get new one
                    continue

                # Fall through to processing reconnect - try to backfill
                self._storedmsg[None] = msg  # keep the msg

                # else do a backfill
                if self._laststatus != self.DELAYED:
                    self.put_notification(self.DELAYED)

                dtend = None
                if len(self) > 1:
                    # len == 1 ... forwarded for the 1st time
                    dtbegin = self.datetime.datetime(-1)
                elif self.fromdate > float('-inf'):
                    dtbegin = num2date(self.fromdate)
                else:  # 1st bar and no begin set
                    # passing None to fetch max possible in 1 request
                    dtbegin = None

                dtend = datetime.utcfromtimestamp(int(msg['time']) / 10 ** 6)

                self.qhist = self.o.candles(
                    self.p.dataname, dtbegin, dtend,
                    self._timeframe, self._compression,
                    candleFormat=self._candleFormat,
                    includeFirst=self.p.includeFirst)

                self._state = self._ST_HISTORBACK
                self._statelivereconn = False  # no longer in live
                continue

            elif self._state == self._ST_HISTORBACK:
                msg = self.qhist.get()
                if msg is None:  # Conn broken during historical/backfilling
                    # Situation not managed. Simply bail out
                    self.put_notification(self.DISCONNECTED)
                    self._state = self._ST_OVER
                    return False  # error management cancelled the queue

                elif 'code' in msg:  # Error
                    self.put_notification(self.NOTSUBSCRIBED)
                    self.put_notification(self.DISCONNECTED)
                    self._state = self._ST_OVER
                    return False

                if msg:
                    if self._load_history(msg):
                        return True  # loading worked

                    continue  # not loaded ... date may have been seen
                else:
                    # End of histdata
                    if self.p.historical:  # only historical
                        self.put_notification(self.DISCONNECTED)
                        self._state = self._ST_OVER
                        return False  # end of historical

                # Live is also wished - go for it
                self._state = self._ST_LIVE
                continue

            elif self._state == self._ST_FROM:
                if not self.p.backfill_from.next():
                    # additional data source is consumed
                    self._state = self._ST_START
                    continue

                # copy lines of the same name
                for alias in self.lines.getlinealiases():
                    lsrc = getattr(self.p.backfill_from.lines, alias)
                    ldst = getattr(self.lines, alias)

                    ldst[0] = lsrc[0]

                return True

            elif self._state == self._ST_START:
                if not self._st_start(instart=False):
                    self._state = self._ST_OVER
                    return False
 def log(self, txt, dt=None):
     dt = dt or self.data.datetime[0]
     dt = bt.num2date(dt)
     print(f"{dt.isoformat()}, {txt}")
예제 #45
0
 def log(self, txt, dt=None):
     if self.p.printout:
         dt = dt or self.data.datetime[0]
         dt = bt.num2date(dt)
         print('%s, %s' % (dt.isoformat(), txt))
예제 #46
0
 def next(self):
     # Simply log the closing price of the series from the reference
     self.log(bt.num2date(self.datas[0].datetime[0]),
              bt.num2date(self.datas[1].datetime[0]),
              self.datas[0].open[0],
              self.datas[1].open[0])