Example #1
0
    def manage_open_order(self, order, position, bars, to_update, to_cancel, open_positions):
        super().manage_open_order(order, position, bars, to_update, to_cancel, open_positions)

        data: Data = self.channel.get_data(bars[1])
        if data is None:
            return

        orderType = TradingBot.order_type_from_order_id(order.id)

        # check for triggered but not filled
        if order.stop_triggered:
            # clear other side
            other_id = TradingBot.get_other_direction_id(posId=position.id)
            if other_id in open_positions.keys():
                open_positions[other_id].markForCancel = bars[0].tstamp

            position.status = PositionStatus.TRIGGERED
            if not hasattr(position, 'waitingToFillSince'):
                position.waitingToFillSince = bars[0].tstamp
            if (bars[0].tstamp - position.waitingToFillSince) > self.bars_till_cancel_triggered * (
                    bars[0].tstamp - bars[1].tstamp):
                # cancel
                position.status = PositionStatus.MISSED
                position.exit_tstamp = bars[0].tstamp
                del open_positions[position.id]
                self.logger.info("canceling not filled position: " + position.id)
                to_cancel.append(order)

        if orderType == OrderType.ENTRY and \
                (data.longSwing is None or data.shortSwing is None or
                 (self.cancel_on_filter and not self.entries_allowed(bars))):
            if position.status == PositionStatus.PENDING:  # don't delete if triggered
                self.logger.info("canceling cause channel got invalid: " + position.id)
                to_cancel.append(order)
                del open_positions[position.id]
Example #2
0
    def position_got_opened(self, position: Position, bars: List[Bar], account: Account, open_positions):
        other_id = TradingBot.get_other_direction_id(position.id)
        if other_id in open_positions.keys():
            open_positions[other_id].markForCancel = bars[0].tstamp

        # add stop
        order = Order(orderId=TradingBot.generate_order_id(positionId=position.id,
                                                           type=OrderType.SL),
                      stop=position.initial_stop,
                      amount=-position.amount)
        self.order_interface.send_order(order)
        # added temporarily, cause sync with open orders is in the next loop and otherwise the orders vs
        # position check fails
        if order not in account.open_orders:  # outside world might have already added it
            account.open_orders.append(order)
 def manage_open_order(self, order, position, bars, to_update, to_cancel,
                       open_positions):
     orderType = TradingBot.order_type_from_order_id(order.id)
     if orderType == OrderType.SL:
         for module in self.exitModules:
             module.manage_open_order(order, position, bars, to_update,
                                      to_cancel, open_positions)
Example #4
0
    def manage_open_order(self, order, position, bars, to_update, to_cancel,
                          open_positions):
        # first the modules
        super().manage_open_order(order, position, bars, to_update, to_cancel,
                                  open_positions)
        # now the swing trail
        data: Data = self.swings.get_data(bars[1])
        if data is not None:
            stopLong = data.swingLow
            stopShort = data.swingHigh

            orderType = TradingBot.order_type_from_order_id(order.id)
            if position is not None and orderType == OrderType.SL:
                # trail
                newStop = order.stop_price
                isLong = position.amount > 0
                trail = stopLong if isLong else stopShort
                if trail is not None and (trail -
                                          newStop) * position.amount > 0:
                    newStop = math.floor(trail) if not isLong else math.ceil(
                        trail)

                if newStop != order.stop_price:
                    order.stop_price = newStop
                    to_update.append(order)
Example #5
0
    def manage_open_order(self, order, position, bars, to_update, to_cancel,
                          open_positions):
        # first the modules
        super().manage_open_order(order, position, bars, to_update, to_cancel,
                                  open_positions)
        # now the channel stuff
        last_data: Data = self.channel.get_data(bars[2])
        data: Data = self.channel.get_data(bars[1])
        if data is not None:
            stopLong = data.longTrail
            stopShort = data.shortTrail
            if self.trail_to_swing and \
                    data.longSwing is not None and data.shortSwing is not None and \
                    (not self.delayed_swing_trail or (last_data is not None and
                                                      last_data.longSwing is not None and
                                                      last_data.shortSwing is not None)):
                stopLong = max(data.shortSwing, stopLong)
                stopShort = min(data.longSwing, stopShort)

            orderType = TradingBot.order_type_from_order_id(order.id)
            if position is not None and orderType == OrderType.SL:
                # trail
                newStop = order.stop_price
                isLong = position.amount > 0
                if self.trail_active:
                    trail = stopLong if isLong else stopShort
                    if (trail - newStop) * position.amount > 0 or \
                            (self.trail_back and position.initial_stop is not None
                                and (trail - position.initial_stop) * position.amount > 0):
                        newStop = math.floor(
                            trail) if not isLong else math.ceil(trail)

                if newStop != order.stop_price:
                    order.stop_price = newStop
                    to_update.append(order)
Example #6
0
    def position_got_opened_or_changed(self, position: Position,
                                       bars: List[Bar], account: Account,
                                       open_positions):
        other_id = TradingBot.get_other_direction_id(position.id)
        if other_id in open_positions.keys():
            open_positions[other_id].markForCancel = bars[0].tstamp

        # add stop
        gotStop = False  # safety check needed to not add multiple SL in case of an error
        gotTp = False
        for order in account.open_orders:
            orderType = TradingBot.order_type_from_order_id(order.id)
            posId = TradingBot.position_id_from_order_id(order.id)
            if orderType == OrderType.SL and posId == position.id:
                gotStop = True
                if abs(order.amount +
                       position.current_open_amount) > self.symbol.lotSize / 2:
                    order.amount = -position.current_open_amount
                    self.order_interface.update_order(order)
            elif self.tp_fac > 0 and orderType == OrderType.TP and posId == position.id:
                gotTp = True
                amount = self.symbol.normalizeSize(
                    -position.current_open_amount + order.executed_amount)
                if abs(order.amount - amount) > self.symbol.lotSize / 2:
                    order.amount = amount
                    self.order_interface.update_order(order)

        if not gotStop:
            order = Order(orderId=TradingBot.generate_order_id(
                positionId=position.id, type=OrderType.SL),
                          stop=position.initial_stop,
                          amount=-position.amount)
            self.order_interface.send_order(order)
        if self.tp_fac > 0 and not gotTp:
            ref = position.filled_entry - position.initial_stop
            #tp = position.filled_entry + ref * self.tp_fac
            data: Data = self.channel.get_data(bars[1])
            if order.amount < 0:
                tp = data.shortTrail
            else:
                tp = data.longTrail

            order = Order(orderId=TradingBot.generate_order_id(
                positionId=position.id, type=OrderType.TP),
                          limit=tp,
                          amount=-position.amount)
Example #7
0
 def manage_open_position(self, position, bars, account, pos_ids_to_cancel):
     if self.close_after_bars >= 0 \
             and position.status == PositionStatus.OPEN \
             and position.entry_tstamp < bars[self.close_after_bars].tstamp:
         self.order_interface.send_order(
             Order(orderId=TradingBot.generate_order_id(
                 positionId=position.id, type=OrderType.SL),
                   amount=-position.currentOpenAmount))
Example #8
0
    def position_got_opened(self, position: Position, bars: List[Bar],
                            account: Account, open_positions):

        gotTP = False
        gotSL = False
        for order in position.connectedOrders:
            type = TradingBot.order_type_from_order_id(order.id)
            if type == OrderType.TP:
                gotTP = True
                amount = self.symbol.normalizeSize(
                    -position.currentOpenAmount + order.executed_amount)
                if abs(order.amount - amount) > self.symbol.lotSize / 2:
                    order.amount = amount
                    self.order_interface.update_order(order)
            if type == OrderType.SL:
                gotSL = True
                amount = self.symbol.normalizeSize(-position.currentOpenAmount)
                if abs(order.amount - amount) > self.symbol.lotSize / 2:
                    order.amount = amount
                    self.order_interface.update_order(order)

        if not gotTP:
            slDiff = position.wanted_entry - position.initial_stop
            # reverse calc the std at time of signal and use tp factor accordingly
            tp = self.symbol.normalizePrice(
                position.wanted_entry + slDiff /
                (self.sl_factor - self.entry_factor) *
                (self.entry_factor - self.tp_factor), position.amount > 0)

            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    position.id, OrderType.TP),
                      amount=-position.currentOpenAmount,
                      stop=None,
                      limit=tp))
        if not gotSL:
            order = Order(orderId=TradingBot.generate_order_id(
                positionId=position.id, type=OrderType.SL),
                          stop=position.initial_stop,
                          amount=-position.currentOpenAmount)
            self.order_interface.send_order(order)
            # added temporarily, cause sync with open orders is in the next loop and otherwise the orders vs
            # position check fails
            if order not in account.open_orders:  # outside world might have already added it
                account.open_orders.append(order)
Example #9
0
 def update_order(self, order: Order):
     if self.telegram_bot is not None and TradingBot.order_type_from_order_id(
             order.id) == OrderType.SL:
         self.telegram_bot.send_log(
             "updating (" + self.id + "): " + order.print_info(), order.id)
     self.exchange.update_order(order)
     self.exchange.on_tick_callback(
         True
     )  ##simulate tick to prevent early updates (need to wait for exchange to update order
Example #10
0
    def send_order(self, order: Order):
        # check if order is val
        if order.amount == 0:
            self.logger.error("trying to send order without amount")
            return
        [posId,
         order_type] = TradingBot.position_id_and_type_from_order_id(order.id)
        if order_type == OrderType.ENTRY:
            [unused, direction] = TradingBot.split_pos_Id(posId)
            if direction == PositionDirection.LONG and order.amount < 0:
                self.logger.error("sending long entry with negative amount")
            if direction == PositionDirection.SHORT and order.amount > 0:
                self.logger.error("sending short entry with positive amount")

        self.logger.debug("added order %s" % (order.print_info()))

        order.tstamp = self.current_bars[0].tstamp
        if order not in self.account.open_orders:  # bot might add it himself temporarily.
            self.account.open_orders.append(order)
Example #11
0
    def position_got_opened(self, position: Position, bars: List[Bar], account: Account, open_positions):
        other_id = TradingBot.get_other_direction_id(position.id)
        if other_id in open_positions.keys():
            open_positions[other_id].markForCancel = bars[0].tstamp

        # add stop
        gotStop= False # safety check needed to not add multiple SL in case of an error
        for order in account.open_orders:
            orderType = TradingBot.order_type_from_order_id(order.id)
            posId = TradingBot.position_id_from_order_id(order.id)
            if orderType == OrderType.SL and posId == position.id:
                gotStop= True
                break
        if not gotStop:
            order = Order(orderId=TradingBot.generate_order_id(positionId=position.id,
                                                           type=OrderType.SL),
                      stop=position.initial_stop,
                      amount=-position.amount)
            self.order_interface.send_order(order)
            # added temporarily, cause sync with open orders is in the next loop and otherwise the orders vs
            # position check fails
            if order not in account.open_orders:  # outside world might have already added it
                account.open_orders.append(order)
Example #12
0
    def __open_position(self, direction, bars, swing, open_positions):
        directionFactor = 1
        oppDirection = PositionDirection.SHORT
        extreme = bars[1].low
        capFunc = min
        if direction == PositionDirection.SHORT:
            directionFactor = -1
            oppDirection = PositionDirection.LONG
            extreme = bars[1].high
            capFunc = max
        oppDirectionFactor = directionFactor * -1

        expectedEntrySplipagePerc = 0.0015
        expectedExitSlipagePerc = 0.0015

        data: Data = self.channel.get_data(bars[1])

        if self.close_on_opposite:
            for pos in open_positions.values():
                if pos.status == PositionStatus.OPEN and \
                        TradingBot.split_pos_Id(pos.id)[1] == oppDirection:
                    # execution will trigger close and cancel of other orders
                    self.order_interface.send_order(
                        Order(orderId=TradingBot.generate_order_id(
                            pos.id, OrderType.SL),
                              amount=-pos.amount,
                              stop=None,
                              limit=None))

        if self.init_stop_type == 1:
            stop = extreme
        elif self.init_stop_type == 2:
            stop = extreme + (extreme - bars[1].close) * 0.5
        else:
            stop = capFunc(swing, (extreme + bars[1].close) / 2)
        stop = stop + oppDirectionFactor  # buffer

        entry = bars[0].open
        signalId = self.get_signal_id(bars)

        #case long: entry * (1 + oppDirectionFactor*self.min_stop_diff_perc / 100) >= stop
        if 0 <= directionFactor*(entry * (1 + oppDirectionFactor*self.min_stop_diff_perc / 100) - stop) \
                or not self.ignore_on_tight_stop:
            stop = capFunc(
                stop,
                entry *
                (1 + oppDirectionFactor * self.min_stop_diff_perc / 100))

            amount = self.calc_pos_size(
                risk=self.risk_factor,
                exitPrice=stop *
                (1 + oppDirectionFactor * expectedExitSlipagePerc),
                entry=entry *
                (1 + directionFactor * expectedEntrySplipagePerc),
                atr=data.atr)

            posId = TradingBot.full_pos_id(signalId, direction)
            pos = Position(id=posId,
                           entry=entry,
                           amount=amount,
                           stop=stop,
                           tstamp=bars[0].tstamp)
            open_positions[posId] = pos
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.ENTRY),
                      amount=amount,
                      stop=None,
                      limit=None))
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.SL),
                      amount=-amount,
                      stop=stop,
                      limit=None))
            if self.tp_fac > 0:
                ref = entry - stop
                if self.tp_use_atr:
                    ref = math.copysign(data.atr, entry - stop)
                tp = entry + ref * self.tp_fac
                self.order_interface.send_order(
                    Order(orderId=TradingBot.generate_order_id(
                        posId, OrderType.TP),
                          amount=-amount,
                          stop=None,
                          limit=tp))
            pos.status = PositionStatus.OPEN
Example #13
0
    def open_orders(self, is_new_bar, directionFilter, bars, account,
                    open_positions):
        if (not is_new_bar) or len(bars) < self.min_bars_needed():
            return  # only open orders on beginning of bar

        if not self.entries_allowed(bars):
            self.logger.info("no entries allowed")
            return

        # check for signal. we are at the open of the new bar. so bars[0] contains of only 1 tick.
        # we look at data bars[1] and bars[2]
        prevFast = self.fastMA.get_data(bars[2])
        currentFast = self.fastMA.get_data(bars[1])
        prevSlow = self.slowMA.get_data(bars[2])
        currentSlow = self.slowMA.get_data(bars[1])
        swingData: Data = self.swings.get_data(bars[1])  # for stops

        # include the expected slipage in the risk calculation
        expectedEntrySplipagePerc = 0.0015
        expectedExitSlipagePerc = 0.0015
        signalId = "MACross+" + str(bars[0].tstamp)

        if prevFast <= prevSlow and currentFast > currentSlow:
            # cross up -> long entry
            entry = bars[0].open  # current price
            stop = swingData.swingLow
            if stop is None:
                stop = lowest(bars, self.swings.before + self.swings.after, 1,
                              BarSeries.LOW)
            amount = self.calc_pos_size(
                risk=self.risk_factor,
                exitPrice=stop * (1 - expectedExitSlipagePerc),
                entry=entry * (1 + expectedEntrySplipagePerc))

            # open the position and save it
            posId = TradingBot.full_pos_id(signalId, PositionDirection.LONG)
            pos = Position(id=posId,
                           entry=entry,
                           amount=amount,
                           stop=stop,
                           tstamp=bars[0].tstamp)
            open_positions[posId] = pos
            # send entry as market, immediatly send SL too
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.ENTRY),
                      amount=amount,
                      stop=None,
                      limit=None))
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.SL),
                      amount=-amount,
                      stop=stop,
                      limit=None))
            pos.status = PositionStatus.OPEN

        elif prevFast >= prevSlow and currentFast < currentSlow:
            # cross down -> short entry
            entry = bars[0].open  # current price
            stop = swingData.swingHigh
            if stop is None:
                stop = highest(bars, self.swings.before + self.swings.after, 1,
                               BarSeries.HIGH)
            amount = self.calc_pos_size(
                risk=self.risk_factor,
                exitPrice=stop * (1 + expectedExitSlipagePerc),
                entry=entry * (1 - expectedEntrySplipagePerc))

            # open the position and save it
            posId = TradingBot.full_pos_id(signalId, PositionDirection.SHORT)
            pos = Position(id=posId,
                           entry=entry,
                           amount=amount,
                           stop=stop,
                           tstamp=bars[0].tstamp)
            open_positions[posId] = pos
            # send entry as market, immediatly send SL too
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.ENTRY),
                      amount=amount,
                      stop=None,
                      limit=None))
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.SL),
                      amount=-amount,
                      stop=stop,
                      limit=None))
            pos.status = PositionStatus.OPEN
Example #14
0
 def update_order(self, order: Order):
     if self.telegram_bot is not None and TradingBot.order_type_from_order_id(
             order.id) == OrderType.SL:
         self.telegram_bot.send_log(
             "updating (" + self.id + "): " + order.print_info(), order.id)
     self.exchange.update_order(order)
Example #15
0
    def open_orders(self, is_new_bar, directionFilter, bars, account, open_positions):
        if (not is_new_bar) or len(bars) < 5:
            return  # only open orders on beginning of bar

        if not self.entries_allowed(bars):
            self.logger.info(" no entries allowed")
            return

        atr = clean_range(bars, offset=0, length=self.channel.max_look_back * 2)
        risk = self.risk_factor

        # test for SFP:
        # High > HH der letzten X
        # Close < HH der vorigen X
        # ? min Wick size?
        # initial SL

        data: Data = self.channel.get_data(bars[1])
        maxLength = min(len(bars), self.range_length)
        minRejLength = min(len(bars),self.min_rej_length)
        highSupreme = 0
        hhBack = 0
        hh = bars[2].high
        swingHigh = 0
        gotHighSwing = False
        for idx in range(2, maxLength):
            if bars[idx].high < bars[1].high:
                highSupreme = idx - 1
                if hh < bars[idx].high:
                    hh = bars[idx].high
                    hhBack = idx
                elif self.min_swing_length < hhBack <= idx - self.min_swing_length:
                    gotHighSwing = True
                    swingHigh = hh  # confirmed
            else:
                break

        lowSupreme = 0
        llBack = 0
        ll = bars[2].low
        swingLow = 0
        gotLowSwing = False
        for idx in range(2, maxLength):
            if bars[idx].low > bars[1].low:
                lowSupreme = idx - 1
                if ll > bars[idx].low:
                    ll = bars[idx].low
                    llBack = idx
                elif self.min_swing_length < llBack <= idx - self.min_swing_length:
                    gotLowSwing = True
                    swingLow = ll  # confirmed
            else:
                break

        rangeMedian = (bars[maxLength - 1].high + bars[maxLength - 1].low) / 2
        alpha = 2 / (maxLength + 1)
        for idx in range(maxLength - 2, 0, -1):
            rangeMedian = rangeMedian * alpha + (bars[idx].high + bars[idx].low) / 2 * (1 - alpha)

        expectedEntrySplipagePerc = 0.0015
        expectedExitSlipagePerc = 0.0015

        signalId = "sfp+" + str(bars[0].tstamp)

        # SHORT
        longSFP = self.entries != 1 and gotHighSwing and bars[1].close + data.buffer < swingHigh
        longRej = self.entries != 2 and bars[1].high > hh > bars[1].close + data.buffer and \
                    highSupreme > minRejLength and bars[1].high - bars[1].close > (bars[1].high - bars[1].low) / 2

        # LONG
        shortSFP = self.entries != 1 and gotLowSwing and bars[1].close - data.buffer > swingLow
        shortRej = self.entries != 2 and bars[1].low < ll < bars[1].close - data.buffer and lowSupreme > minRejLength \
                   and bars[1].close - bars[1].low > (bars[1].high - bars[1].low) / 2

        self.logger.info("---- analyzing: %s: %.1f %.1f %.0f | %s %.0f %i or %i %.0f %.0f | %s %.0f %i or %i %.0f %.0f " %
                         (str(datetime.fromtimestamp(bars[0].tstamp)), data.buffer, atr, rangeMedian,
                          gotHighSwing, swingHigh, hhBack, highSupreme, hh ,bars[1].high - bars[1].close,
                          gotLowSwing, swingLow, llBack, lowSupreme, ll ,bars[1].close - bars[1].low ))
        
        if (longSFP or longRej) and (bars[1].high - bars[1].close) > atr * self.min_wick_fac \
                and directionFilter <= 0 and bars[1].high > rangeMedian + atr * self.range_filter_fac:
            # close existing short pos
            if self.close_on_opposite:
                for pos in open_positions.values():
                    if pos.status == PositionStatus.OPEN and TradingBot.split_pos_Id(pos.id)[1] == PositionDirection.LONG:
                        # execution will trigger close and cancel of other orders
                        self.order_interface.send_order(
                            Order(orderId=TradingBot.generate_order_id(pos.id, OrderType.SL),
                                  amount=-pos.amount, stop=None, limit=None))

            if self.init_stop_type == 1:
                stop = bars[1].high
            elif self.init_stop_type == 2:
                stop = bars[1].high + (bars[0].high - bars[0].close) * 0.5
            else:
                stop = max(swingHigh, (bars[1].high + bars[1].close) / 2)
            stop = stop + 1  # buffer

            entry = bars[0].open
            amount = self.calc_pos_size(risk=risk, exitPrice=stop * (1 + expectedExitSlipagePerc),
                                        entry=entry * (1 - expectedEntrySplipagePerc), data=data)

            posId = TradingBot.full_pos_id(signalId, PositionDirection.SHORT)
            pos = Position(id=posId, entry=entry, amount=amount, stop=stop,
                                             tstamp=bars[0].tstamp)
            open_positions[posId]= pos
            self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.ENTRY),
                                                  amount=amount, stop=None, limit=None))
            self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.SL),
                                                  amount=-amount, stop=stop, limit=None))
            if self.tp_fac > 0:
                tp = entry - (stop - entry) * self.tp_fac
                self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.TP),
                                                      amount=-amount, stop=None, limit=tp))
            pos.status= PositionStatus.OPEN

        if (shortSFP or shortRej) and (bars[1].close - bars[1].low) > atr * self.min_wick_fac \
                and directionFilter >= 0 and bars[1].low < rangeMedian - self.range_filter_fac:
            # close existing short pos
            if self.close_on_opposite:
                for pos in open_positions.values():
                    if pos.status == PositionStatus.OPEN and TradingBot.split_pos_Id(pos.id)[1] == PositionDirection.SHORT:
                        # execution will trigger close and cancel of other orders
                        self.order_interface.send_order(
                            Order(orderId=TradingBot.generate_order_id(pos.id, OrderType.SL),
                                  amount=-pos.amount, stop=None, limit=None))

            if self.init_stop_type == 1:
                stop = bars[1].low
            elif self.init_stop_type == 2:
                stop = bars[1].low + (bars[0].low - bars[0].close) * 0.5
            else:
                stop = min(swingLow, (bars[1].low + bars[1].close) / 2)
            stop = stop - 1  # buffer

            entry = bars[0].open
            amount = self.calc_pos_size(risk=risk, exitPrice=stop * (1 - expectedExitSlipagePerc),
                                        entry=entry * (1 + expectedEntrySplipagePerc), data=data)

            posId = TradingBot.full_pos_id(signalId, PositionDirection.LONG)
            pos = Position(id=posId, entry=entry, amount=amount, stop=stop,
                                             tstamp=bars[0].tstamp)
            pos.status= PositionStatus.TRIGGERED
            open_positions[posId]= pos
            self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.ENTRY),
                                                  amount=amount, stop=None, limit=None))
            self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.SL),
                                                  amount=-amount, stop=stop, limit=None))
            if self.tp_fac > 0:
                tp = entry + (entry - stop) * self.tp_fac
                self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.TP),
                                                      amount=-amount, stop=None, limit=tp))
Example #16
0
    def open_orders(self, is_new_bar, directionFilter, bars, account, open_positions, all_open_pos: dict):
        if (not is_new_bar) or len(bars) < 5:
            return  # only open orders on beginning of bar

        entriesAllowed = self.entries_allowed(bars)
        if not entriesAllowed:
            self.logger.info("new entries not allowed by filter")

        last_data: Data = self.channel.get_data(bars[2])
        data: Data = self.channel.get_data(bars[1])
        if data is None:
            return

        self.logger.info("---- analyzing: %s atr: %.1f buffer: %.1f swings: %s/%s trails: %.1f/%.1f resets:%i/%i" %
                         (str(datetime.fromtimestamp(bars[0].tstamp)),
                          data.atr, data.buffer,
                          ("%.1f" % data.longSwing) if data.longSwing is not None else "-",
                          ("%.1f" % data.shortSwing) if data.shortSwing is not None else "-",
                          data.longTrail, data.shortTrail, data.sinceLongReset, data.sinceShortReset))
        if last_data is not None and \
                data.shortSwing is not None and data.longSwing is not None and \
                (not self.delayed_entry or (last_data.shortSwing is not None and last_data.longSwing is not None)):
            swing_range = data.longSwing - data.shortSwing

            atr = clean_range(bars, offset=0, length=self.channel.max_look_back * 2)
            if atr * self.min_channel_size_factor < swing_range < atr * self.max_channel_size_factor:
                risk = self.risk_factor
                longEntry = self.symbol.normalizePrice(max(data.longSwing, bars[0].high), roundUp=True)
                shortEntry = self.symbol.normalizePrice(min(data.shortSwing, bars[0].low), roundUp=False)

                stopLong = self.symbol.normalizePrice(max(data.shortSwing, data.longTrail), roundUp=False)
                stopShort = self.symbol.normalizePrice(min(data.longSwing, data.shortTrail), roundUp=True)

                stopLong = min(stopLong,longEntry - self.min_stop_diff_atr*atr)
                stopShort = max(stopShort, shortEntry + self.min_stop_diff_atr*atr)

                expectedEntrySplipagePerc = 0.0015 if self.limit_entry_offset_perc is None else 0
                expectedExitSlipagePerc = 0.0015

                # first check if we should update an existing one
                longAmount = self.calc_pos_size(risk=risk, exitPrice=stopLong * (1 - expectedExitSlipagePerc),
                                                entry=longEntry * (1 + expectedEntrySplipagePerc),
                                                atr=data.atr)
                shortAmount = self.calc_pos_size(risk=risk, exitPrice=stopShort * (1 + expectedExitSlipagePerc),
                                                 entry=shortEntry * (1 - expectedEntrySplipagePerc),
                                                 atr=data.atr)
                if longEntry < stopLong or shortEntry > stopShort:
                    self.logger.warn("can't put initial stop above entry")

                foundLong = False
                foundShort = False
                for position in open_positions.values():
                    if position.status == PositionStatus.PENDING:
                        if position.amount > 0:
                            foundLong = True
                            entry = longEntry
                            stop = stopLong
                            entryFac = (1 + expectedEntrySplipagePerc)
                            exitFac = (1 - expectedExitSlipagePerc)
                        else:
                            foundShort = True
                            entry = shortEntry
                            stop = stopShort
                            entryFac = (1 - expectedEntrySplipagePerc)
                            exitFac = (1 + expectedExitSlipagePerc)
                        entryBuffer = entry * self.limit_entry_offset_perc * 0.01 if self.limit_entry_offset_perc is not None else None
                        for order in account.open_orders:
                            if TradingBot.position_id_from_order_id(order.id) == position.id:
                                newEntry = position.wanted_entry * (
                                            1 - self.entry_tightening) + entry * self.entry_tightening
                                newEntry = self.symbol.normalizePrice(newEntry, roundUp=order.amount > 0)
                                newStop = position.initial_stop * (
                                            1 - self.entry_tightening) + stop * self.entry_tightening
                                newStop = self.symbol.normalizePrice(newStop, roundUp=order.amount < 0)
                                amount = self.calc_pos_size(risk=risk, exitPrice=newStop * exitFac,
                                                            entry=newEntry * entryFac, atr=data.atr)
                                if amount * order.amount < 0:
                                    self.logger.warn("updating order switching direction")
                                changed = False
                                changed = changed or order.stop_price != newEntry
                                order.stop_price = newEntry
                                if self.limit_entry_offset_perc is not None:
                                    newLimit = newEntry - entryBuffer * math.copysign(1, amount)
                                    changed = changed or order.limit_price != newLimit
                                    order.limit_price = newLimit
                                changed = changed or order.amount != amount
                                order.amount = amount
                                if changed:
                                    self.order_interface.update_order(order)
                                else:
                                    self.logger.info("order didn't change: %s" % order.print_info())

                                position.initial_stop = newStop
                                position.amount = amount
                                position.wanted_entry = newEntry
                                break

                # if len(self.open_positions) > 0:
                # return

                signalId = self.get_signal_id(bars)
                if not foundLong and directionFilter >= 0 and entriesAllowed:
                    posId = TradingBot.full_pos_id(signalId, PositionDirection.LONG)
                    entryBuffer = longEntry * self.limit_entry_offset_perc * 0.01 if self.limit_entry_offset_perc is not None else None

                    self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.ENTRY),
                                                          amount=longAmount, stop=longEntry,
                                                          limit=longEntry - entryBuffer if entryBuffer is not None else None))
                    open_positions[posId] = Position(id=posId, entry=longEntry, amount=longAmount, stop=stopLong,
                                                     tstamp=bars[0].tstamp)
                if not foundShort and directionFilter <= 0 and entriesAllowed:
                    posId = TradingBot.full_pos_id(signalId, PositionDirection.SHORT)
                    entryBuffer = shortEntry * self.limit_entry_offset_perc * 0.01 if self.limit_entry_offset_perc is not None else None
                    self.order_interface.send_order(Order(orderId=TradingBot.generate_order_id(posId, OrderType.ENTRY),
                                                          amount=shortAmount, stop=shortEntry,
                                                          limit=shortEntry + entryBuffer if entryBuffer is not None else None))
                    open_positions[posId] = Position(id=posId, entry=shortEntry, amount=shortAmount,
                                                     stop=stopShort, tstamp=bars[0].tstamp)
Example #17
0
    def open_orders(self, is_new_bar, directionFilter, bars, account,
                    open_positions, all_open_pos: dict):
        if (not is_new_bar) or len(bars) < self.min_bars_needed():
            return  # only open orders on beginning of bar

        if not self.entries_allowed(bars):
            self.logger.info("no entries allowed")
            return

        # include the expected slipage in the risk calculation
        expectedExitSlipagePerc = 0.0015

        data = self.mean.get_data(bars[1])
        # long:
        longEntry = self.symbol.normalizePrice(
            data.mean - data.std * self.entry_factor, False)
        longStop = self.symbol.normalizePrice(
            data.mean - data.std * self.sl_factor, True)
        longAmount = self.calc_pos_size(risk=self.risk_factor,
                                        exitPrice=longStop *
                                        (1 - expectedExitSlipagePerc),
                                        entry=longEntry)

        # short:
        shortEntry = self.symbol.normalizePrice(
            data.mean + data.std * self.entry_factor, True)
        shortStop = self.symbol.normalizePrice(
            data.mean + data.std * self.sl_factor, False)
        shortAmount = self.calc_pos_size(risk=self.risk_factor,
                                         exitPrice=shortStop *
                                         (1 + expectedExitSlipagePerc),
                                         entry=shortEntry)

        gotLong = False
        gotShort = False

        for pos in open_positions.values():
            if pos.amount > 0:
                gotLong = True
                if pos.status == PositionStatus.PENDING:
                    pos.amount = longAmount
                    pos.initialStop = longStop
                    pos.wantedEntry = longEntry
                    for order in pos.connectedOrders:
                        if order.limit_price != longEntry or order.amount != longAmount:
                            order.limit_price = longEntry
                            order.amount = longAmount
                            self.order_interface.update_order(order)
            else:
                gotShort = True
                if pos.status == PositionStatus.PENDING:
                    pos.amount = shortAmount
                    pos.initialStop = shortStop
                    pos.wantedEntry = shortEntry
                    for order in pos.connectedOrders:
                        if order.limit_price != shortEntry or order.amount != shortAmount:
                            order.limit_price = shortEntry
                            order.amount = shortAmount
                            self.order_interface.update_order(order)

        if not gotLong and bars[0].close > longEntry:
            posId = TradingBot.full_pos_id(
                self.get_signal_id(bars, self.myId()), PositionDirection.LONG)
            open_positions[posId] = Position(id=posId,
                                             entry=longEntry,
                                             amount=longAmount,
                                             stop=longStop,
                                             tstamp=bars[0].tstamp)
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.ENTRY),
                      amount=longAmount,
                      limit=longEntry))

        if not gotShort and bars[0].close < shortEntry:
            posId = TradingBot.full_pos_id(
                self.get_signal_id(bars, self.myId()), PositionDirection.SHORT)
            open_positions[posId] = Position(id=posId,
                                             entry=shortEntry,
                                             amount=shortAmount,
                                             stop=shortStop,
                                             tstamp=bars[0].tstamp)
            self.order_interface.send_order(
                Order(orderId=TradingBot.generate_order_id(
                    posId, OrderType.ENTRY),
                      amount=shortAmount,
                      limit=shortEntry))