コード例 #1
0
ファイル: trading_bot.py プロジェクト: austinekrash/kuegiBot
    def handle_opened_position(self, position: Position, order: Order, account: Account, bars: List[Bar]):
        position.status = PositionStatus.OPEN
        position.filled_entry = order.executed_price if order is not None else None
        position.entry_tstamp = order.execution_tstamp if order is not None and order.execution_tstamp > 0 else bars[
            0].tstamp

        self.position_got_opened(position, bars, account)
コード例 #2
0
ファイル: trading_bot.py プロジェクト: xn2333/kuegiBot
    def init(self, bars: List[Bar], account: Account, symbol: Symbol, unique_id: str = ""):
        '''init open position etc.'''
        self.symbol = symbol
        self.unique_id = unique_id
        if unique_id is not None:
            base = 'openPositions/'
            try:
                os.makedirs(base)
            except Exception:
                pass
            try:
                with open(base + self._get_pos_file(), 'r') as file:
                    data = json.load(file)
                    self.last_time = data["last_time"]
                    for pos_json in data["positions"]:
                        pos: Position = Position.from_json(pos_json)
                        self.open_positions[pos.id] = pos
                    self.logger.info("done loading " + str(
                        len(self.open_positions)) + " positions from " + self._get_pos_file() + " last time " + str(
                        self.last_time))
            except Exception as e:
                self.logger.warn("Error loading open positions: " + str(e))
                self.open_positions = {}

        # init positions from existing orders
        self.sync_positions_with_open_orders(bars, account)
コード例 #3
0
    def read_open_positions(self,bars: List[Bar]):
        if self.unique_id is not None:
            base = 'openPositions/'
            try:
                os.makedirs(base)
            except Exception:
                pass
            try:
                with open(base + self._get_pos_file(), 'r') as file:
                    data = json.load(file)
                    self.last_time = data["last_time"]
                    if "max_equity" in data.keys():
                        self.max_equity= data["max_equity"]
                        self.time_of_max_equity= data["time_of_max_equity"]
                    for pos_json in data["positions"]:
                        pos: Position = Position.from_json(pos_json)
                        self.open_positions[pos.id] = pos
                    if "moduleData" in data.keys():
                        if str(bars[0].tstamp) in data["moduleData"].keys():
                            moduleData = data['moduleData'][str(bars[0].tstamp)]
                            ExitModule.set_data_from_json(bars[0], moduleData)
                        if str(bars[1].tstamp) in data["moduleData"].keys():
                            moduleData = data['moduleData'][str(bars[1].tstamp)]
                            ExitModule.set_data_from_json(bars[1], moduleData)

                    self.logger.info("done loading " + str(
                        len(self.open_positions)) + " positions from " + self._get_pos_file() + " last time " + str(
                        self.last_time))
            except Exception as e:
                self.logger.warn("Error loading open positions: " + str(e))
                self.open_positions = {}
コード例 #4
0
ファイル: trading_bot.py プロジェクト: SteWolk/kuegiBot
    def position_closed(self, position: Position, account: Account):
        if position.exit_tstamp == 0:
            position.exit_tstamp = time.time()
        position.exit_equity = account.equity
        self.position_history.append(position)
        del self.open_positions[position.id]

        # cancel other open orders of this position (sl/tp etc)
        self.logger.info("canceling remaining orders for position: " + position.id)
        self.cancel_all_orders_for_position(position.id, account)

        if self.unique_id is None:
            return
        base = 'positionHistory/'
        filename = base + self._get_pos_file()
        size = 0
        try:
            os.makedirs(base)
        except Exception:
            pass
        try:
            size = os.path.getsize(filename)
        except Exception:
            pass
        with open(filename, 'a') as file:
            writer = csv.writer(file)
            if size == 0:
                csv_columns = ['signalTStamp', 'size', 'wantedEntry', 'initialStop', 'openTime', 'openPrice',
                               'closeTime',
                               'closePrice', 'equityOnExit']
                writer.writerow(csv_columns)
            writer.writerow([
                datetime.fromtimestamp(position.signal_tstamp).isoformat(),
                position.amount,
                position.wanted_entry,
                position.initial_stop,
                datetime.fromtimestamp(position.entry_tstamp).isoformat(),
                position.filled_entry,
                datetime.fromtimestamp(position.exit_tstamp).isoformat(),
                position.filled_exit,
                position.exit_equity
            ])
コード例 #5
0
ファイル: trading_bot.py プロジェクト: SteWolk/kuegiBot
 def fill_openpositions(self, data, bars: List[Bar]):
     self.last_time = data["last_time"]
     if "last_tick_tstamp" in data:
         self.last_tick_time = datetime.fromtimestamp(data["last_tick_tstamp"])
     if "max_equity" in data.keys():
         self.max_equity = data["max_equity"]
         self.time_of_max_equity = data["time_of_max_equity"]
     for pos_json in data["positions"]:
         pos: Position = Position.from_json(pos_json)
         self.open_positions[pos.id] = pos
     if "moduleData" in data.keys():
         for idx in range(5):
             if str(bars[idx].tstamp) in data["moduleData"].keys():
                 moduleData = data['moduleData'][str(bars[idx].tstamp)]
                 ExitModule.set_data_from_json(bars[idx], moduleData)
コード例 #6
0
ファイル: trading_bot.py プロジェクト: xn2333/kuegiBot
    def sync_positions_with_open_orders(self, bars: List[Bar], account: Account):
        open_pos = 0
        for pos in self.open_positions.values():
            pos.connectedOrders= [] # will be filled now
            if pos.status == PositionStatus.OPEN:
                open_pos += pos.amount

        if not self.got_data_for_position_sync(bars):
            self.logger.warn("got no initial data, can't sync positions")
            return

        remaining_pos_ids = []
        remaining_pos_ids += self.open_positions.keys()
        remaining_orders = []
        remaining_orders += account.open_orders

        # first check if there even is a diparity (positions without stops, or orders without position)
        for order in account.open_orders:
            if not order.active:
                remaining_orders.remove(order)
                continue  # got cancelled during run
            orderType = self.order_type_from_order_id(order.id)
            if orderType is None:
                remaining_orders.remove(order)
                continue  # none of ours
            posId = self.position_id_from_order_id(order.id)
            if posId in self.open_positions.keys():
                pos = self.open_positions[posId]
                pos.connectedOrders.append(order)
                remaining_orders.remove(order)
                if posId in remaining_pos_ids:
                    if (orderType == OrderType.SL and pos.status == PositionStatus.OPEN) \
                            or (orderType == OrderType.ENTRY and pos.status == PositionStatus.PENDING):
                        # only remove from remaining if its open with SL or pending with entry. every position needs
                        # a stoploss!
                        remaining_pos_ids.remove(posId)

        for pos in self.open_positions.values():
            self.check_open_orders_in_position(pos)

        if len(remaining_orders) == 0 and len(remaining_pos_ids) == 0 and abs(
                open_pos - account.open_position.quantity) < 0.1:
            return

        self.logger.info("Has to start order/pos sync with bot vs acc: %.3f vs. %.3f and %i vs %i, remaining: %i,  %i"
                         % (
                             open_pos, account.open_position.quantity, len(self.open_positions),
                             len(account.open_orders),
                             len(remaining_orders), len(remaining_pos_ids)))

        remainingPosition = account.open_position.quantity
        for pos in self.open_positions.values():
            if pos.status == PositionStatus.OPEN:
                remainingPosition -= pos.amount

        waiting_tps = []

        # now remaining orders and remaining positions contain the not matched ones
        for order in remaining_orders:
            orderType = self.order_type_from_order_id(order.id)
            posId = self.position_id_from_order_id(order.id)
            if not order.active:  # already canceled or executed
                continue

            if orderType == OrderType.ENTRY:
                # add position for unkown order
                stop = self.get_stop_for_unmatched_amount(order.amount, bars)
                if stop is not None:
                    newPos = Position(id=posId,
                                      entry=order.limit_price if order.limit_price is not None else order.stop_price,
                                      amount=order.amount,
                                      stop=stop,
                                      tstamp=bars[0].tstamp)
                    newPos.status = PositionStatus.PENDING if not order.stop_triggered else PositionStatus.TRIGGERED
                    self.open_positions[posId] = newPos
                    self.logger.warn("found unknown entry %s %.1f @ %.1f, added position"
                                     % (order.id, order.amount,
                                        order.stop_price if order.stop_price is not None else order.limit_price))
                else:
                    self.logger.warn(
                        "found unknown entry %s %.1f @ %.1f, but don't know what stop to use -> canceling"
                        % (order.id, order.amount,
                           order.stop_price if order.stop_price is not None else order.limit_price))
                    self.order_interface.cancel_order(order)

            elif orderType == OrderType.SL and remainingPosition * order.amount < 0 and abs(remainingPosition) > abs(
                    order.amount):
                # only assume open position for the waiting SL with the remainingPosition also indicates it, 
                # otherwise it might be a pending cancel (from executed TP) or already executed
                newPos = Position(id=posId, entry=None, amount=-order.amount,
                                  stop=order.stop_price, tstamp=bars[0].tstamp)
                newPos.status = PositionStatus.OPEN
                remainingPosition -= newPos.amount
                self.open_positions[posId] = newPos
                self.logger.warn("found unknown exit %s %.1f @ %.1f, opened position for it" % (
                    order.id, order.amount,
                    order.stop_price if order.stop_price is not None else order.limit_price))
            else:
                waiting_tps.append(order)

        # cancel orphaned TPs
        for order in waiting_tps:
            orderType = self.order_type_from_order_id(order.id)
            posId = self.position_id_from_order_id(order.id)
            if posId not in self.open_positions.keys():  # still not in (might have been added in previous for)
                self.logger.warn(
                    "didn't find matching position for order %s %.1f @ %.1f -> canceling"
                    % (order.id, order.amount,
                       order.stop_price if order.stop_price is not None else order.limit_price))
                self.order_interface.cancel_order(order)

        self.logger.info("found " + str(len(self.open_positions)) + " existing positions on sync")

        # positions with no exit in the market
        for posId in remaining_pos_ids:
            pos = self.open_positions[posId]
            if pos.status == PositionStatus.PENDING or pos.status == PositionStatus.TRIGGERED:
                # should have the opening order in the system, but doesn't
                # not sure why: in doubt: not create wrong orders
                if remainingPosition * pos.amount > 0 and abs(remainingPosition) >= abs(pos.amount):
                    # assume position was opened without us realizing (during downtime)
                    self.logger.warn(
                        "pending position with no entry order but open position looks like it was opened: %s" % (posId))
                    self.handle_opened_position(position=pos, order=None, bars=bars, account=account)
                    remainingPosition -= pos.amount
                else:
                    self.logger.warn(
                        "pending position with no entry order and no sign of opening -> close missed: %s" % (posId))
                    pos.status = PositionStatus.MISSED
                    self.position_closed(pos, account)
            elif pos.status == PositionStatus.OPEN:
                if remainingPosition == 0 and pos.initial_stop is not None:  # for some reason everything matches but we are missing the stop in the market
                    self.logger.warn(
                        "found position with no stop in market. added stop for it: %s with %.1f contracts" % (
                        posId, pos.amount))
                    self.order_interface.send_order(
                        Order(orderId=self.generate_order_id(posId, OrderType.SL), amount=-pos.amount,
                              stop=pos.initial_stop))
                else:
                    self.logger.warn(
                        "found position with no stop in market. %s with %.1f contracts. but remaining Position doesn't match so assume it was already closed." % (
                        posId, pos.amount))
                    self.position_closed(pos, account)
                    remainingPosition += pos.amount
            else:
                self.logger.warn(
                        "pending position with noconnection order not pending or open? closed: %s" % (posId))
                self.position_closed(pos, account)

        # now there should not be any mismatch between positions and orders.
        if remainingPosition != 0:
            unmatched_stop = self.get_stop_for_unmatched_amount(remainingPosition, bars)
            signalId = str(bars[1].tstamp) + '+' + str(randint(0, 99))
            if unmatched_stop is not None:
                posId = self.full_pos_id(signalId,
                                         PositionDirection.LONG if remainingPosition > 0 else PositionDirection.SHORT)
                newPos = Position(id=posId, entry=None, amount=remainingPosition,
                                  stop=unmatched_stop, tstamp=bars[0].tstamp)
                newPos.status = PositionStatus.OPEN
                self.open_positions[posId] = newPos
                # add stop
                self.logger.info(
                    "couldn't account for " + str(newPos.amount) + " open contracts. Adding position with stop for it")
                self.order_interface.send_order(Order(orderId=self.generate_order_id(posId, OrderType.SL),
                                                      stop=newPos.initial_stop, amount=-newPos.amount))
            elif account.open_position.quantity * remainingPosition > 0:
                self.logger.info(
                    "couldn't account for " + str(remainingPosition) + " open contracts. Market close")
                self.order_interface.send_order(Order(orderId=signalId + "_marketClose", amount=-remainingPosition))
            else:
                self.logger.info(
                    "couldn't account for " + str(
                        remainingPosition) + " open contracts. But close would increase exposure-> ignored")
コード例 #7
0
ファイル: SfpStrat.py プロジェクト: skneher/kuegiBot
    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
コード例 #8
0
ファイル: MACross.py プロジェクト: swissbeats93/kuegiBot
    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
コード例 #9
0
    def open_orders(self, bars: List[Bar], account: Account):
        if (not self.is_new_bar) or len(bars) < 5:
            return  # only open orders on beginning of bar

        last_data: Data = self.channel.get_data(bars[2])
        data: Data = self.channel.get_data(bars[1])
        if data is not None:
            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 data is not None and 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
                stopLong = int(max(data.shortSwing, data.longTrail))
                stopShort = int(min(data.longSwing, data.shortTrail))

                longEntry = int(max(data.longSwing, bars[0].high))
                shortEntry = int(min(data.shortSwing, bars[0].low))

                expectedEntrySplipagePerc = 0.0015 if self.stop_entry 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),
                    data=data)
                shortAmount = self.calc_pos_size(
                    risk=risk,
                    exitPrice=stopShort * (1 + expectedExitSlipagePerc),
                    entry=shortEntry * (1 - expectedEntrySplipagePerc),
                    data=data)
                if longEntry < stopLong or shortEntry > stopShort:
                    self.logger.warn("can't put initial stop above entry")

                foundLong = False
                foundShort = False
                for position in self.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)

                        for order in account.open_orders:
                            if self.position_id_from_order_id(
                                    order.id) == position.id:
                                newEntry = int(position.wanted_entry *
                                               (1 - self.entry_tightening) +
                                               entry * self.entry_tightening)
                                newStop = int(position.initial_stop *
                                              (1 - self.entry_tightening) +
                                              stop * self.entry_tightening)
                                amount = self.calc_pos_size(
                                    risk=risk,
                                    exitPrice=newStop * exitFac,
                                    entry=newEntry * entryFac,
                                    data=data)
                                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 not self.stop_entry:
                                    changed = changed or order.limit_price != newEntry - math.copysign(
                                        1, amount)
                                    order.limit_price = newEntry - math.copysign(
                                        1, amount)
                                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 = str(bars[0].tstamp)
                if not foundLong and self.directionFilter >= 0:
                    posId = self.full_pos_id(signalId, PositionDirection.LONG)
                    self.order_interface.send_order(
                        Order(orderId=self.generate_order_id(
                            posId, OrderType.ENTRY),
                              amount=longAmount,
                              stop=longEntry,
                              limit=longEntry -
                              1 if not self.stop_entry else None))
                    self.open_positions[posId] = Position(
                        id=posId,
                        entry=longEntry,
                        amount=longAmount,
                        stop=stopLong,
                        tstamp=bars[0].tstamp)
                if not foundShort and self.directionFilter <= 0:
                    posId = self.full_pos_id(signalId, PositionDirection.SHORT)
                    self.order_interface.send_order(
                        Order(orderId=self.generate_order_id(
                            posId, OrderType.ENTRY),
                              amount=shortAmount,
                              stop=shortEntry,
                              limit=shortEntry +
                              1 if not self.stop_entry else None))
                    self.open_positions[posId] = Position(
                        id=posId,
                        entry=shortEntry,
                        amount=shortAmount,
                        stop=stopShort,
                        tstamp=bars[0].tstamp)
コード例 #10
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))
コード例 #11
0
ファイル: trading_bot.py プロジェクト: SteWolk/kuegiBot
    def sync_positions_with_open_orders(self, bars: List[Bar], account: Account):
        open_pos = 0
        for pos in self.open_positions.values():
            if pos.status == PositionStatus.OPEN:
                open_pos += pos.current_open_amount

        if not self.got_data_for_position_sync(bars):
            self.logger.warn("got no initial data, can't sync positions")
            self.unaccounted_position_cool_off = 0
            return

        remaining_pos_ids = []
        remaining_pos_ids += self.open_positions.keys()
        remaining_orders = []
        remaining_orders += account.open_orders

        # first check if there even is a diparity (positions without stops, or orders without position)
        for order in account.open_orders:
            if not order.active:
                remaining_orders.remove(order)
                continue  # got cancelled during run
            [posId, orderType] = self.position_id_and_type_from_order_id(order.id)
            if orderType is None:
                remaining_orders.remove(order)
                continue  # none of ours
            if posId in self.open_positions.keys():
                pos = self.open_positions[posId]
                remaining_orders.remove(order)
                if posId in remaining_pos_ids:
                    if (orderType == OrderType.SL and pos.status == PositionStatus.OPEN) \
                            or (orderType == OrderType.ENTRY and pos.status in [PositionStatus.PENDING,
                                                                                PositionStatus.TRIGGERED]):
                        # only remove from remaining if its open with SL or pending with entry. every position needs
                        # a stoploss!
                        remaining_pos_ids.remove(posId)

        for pos in self.open_positions.values():
            self.check_open_orders_in_position(pos)

        if len(remaining_orders) == 0 and len(remaining_pos_ids) == 0 and abs(
                open_pos - account.open_position.quantity) < self.symbol.lotSize / 10:
            self.unaccounted_position_cool_off = 0
            return

        self.logger.info("Has to start order/pos sync with bot vs acc: %.3f vs. %.3f and %i vs %i, remaining: %i,  %i"
                         % (
                             open_pos, account.open_position.quantity, len(self.open_positions),
                             len(account.open_orders),
                             len(remaining_orders), len(remaining_pos_ids)))

        remainingPosition = account.open_position.quantity
        for pos in self.open_positions.values():
            if pos.status == PositionStatus.OPEN:
                remainingPosition -= pos.current_open_amount

        waiting_tps = []

        # now remaining orders and remaining positions contain the not matched ones
        for order in remaining_orders:
            orderType = self.order_type_from_order_id(order.id)
            posId = self.position_id_from_order_id(order.id)
            if not order.active:  # already canceled or executed
                continue

            if orderType == OrderType.ENTRY:
                # add position for unkown order
                stop = self.get_stop_for_unmatched_amount(order.amount, bars)
                if stop is not None:
                    newPos = Position(id=posId,
                                      entry=order.limit_price if order.limit_price is not None else order.stop_price,
                                      amount=order.amount,
                                      stop=stop,
                                      tstamp=bars[0].tstamp)
                    newPos.status = PositionStatus.PENDING if not order.stop_triggered else PositionStatus.TRIGGERED
                    self.open_positions[posId] = newPos
                    self.logger.warn("found unknown entry %s %.1f @ %.1f, added position"
                                     % (order.id, order.amount,
                                        order.stop_price if order.stop_price is not None else order.limit_price))
                else:
                    self.logger.warn(
                        "found unknown entry %s %.1f @ %.1f, but don't know what stop to use -> canceling"
                        % (order.id, order.amount,
                           order.stop_price if order.stop_price is not None else order.limit_price))
                    self.order_interface.cancel_order(order)

            elif orderType == OrderType.SL and remainingPosition * order.amount < 0 and abs(
                    round(remainingPosition, self.symbol.quantityPrecision)) > abs(
                order.amount):
                # only assume open position for the waiting SL with the remainingPosition also indicates it, 
                # otherwise it might be a pending cancel (from executed TP) or already executed
                newPos = Position(id=posId, entry=None, amount=-order.amount,
                                  stop=order.stop_price, tstamp=bars[0].tstamp)
                newPos.status = PositionStatus.OPEN
                remainingPosition -= newPos.amount
                self.open_positions[posId] = newPos
                self.logger.warn("found unknown exit %s %.1f @ %.1f, opened position for it" % (
                    order.id, order.amount,
                    order.stop_price if order.stop_price is not None else order.limit_price))
            else:
                waiting_tps.append(order)

        # cancel orphaned TPs
        for order in waiting_tps:
            orderType = self.order_type_from_order_id(order.id)
            posId = self.position_id_from_order_id(order.id)
            if posId not in self.open_positions.keys():  # still not in (might have been added in previous for)
                self.logger.warn(
                    "didn't find matching position for order %s %.1f @ %.1f -> canceling"
                    % (order.id, order.amount,
                       order.stop_price if order.stop_price is not None else order.limit_price))
                self.order_interface.cancel_order(order)

        self.logger.info("found " + str(len(self.open_positions)) + " existing positions on sync")

        # positions with no exit in the market
        for posId in remaining_pos_ids:
            pos = self.open_positions[posId]
            if pos.status == PositionStatus.PENDING or pos.status == PositionStatus.TRIGGERED:
                # should have the opening order in the system, but doesn't
                # not sure why: in doubt: not create wrong orders
                if remainingPosition * pos.amount > 0 and abs(
                        round(remainingPosition, self.symbol.quantityPrecision)) >= abs(pos.amount):
                    # assume position was opened without us realizing (during downtime)
                    self.logger.warn(
                        "pending position with no entry order but open position looks like it was opened: %s" % (posId))
                    pos.last_filled_entry = pos.wanted_entry
                    pos.entry_tstamp = time.time()
                    pos.max_filled_amount += pos.amount
                    pos.current_open_amount = pos.amount
                    self.handle_opened_or_changed_position(position=pos, bars=bars, account=account)
                    remainingPosition -= pos.amount
                else:
                    self.logger.warn(
                        "pending position with no entry order and no sign of opening -> close missed: %s" % (posId))
                    pos.status = PositionStatus.MISSED
                    self.position_closed(pos, account)
            elif pos.status == PositionStatus.OPEN:
                if pos.changed:
                    self.logger.info(f"pos has no exit, but is marked changed, so its probably just a race {pos}")
                    continue
                if pos.initial_stop is not None:
                    # for some reason we are missing the stop in the market
                    self.logger.warn(
                        "found position with no stop in market. added stop for it: %s with %.1f contracts" % (
                            posId, pos.current_open_amount))
                    self.order_interface.send_order(
                        Order(orderId=self.generate_order_id(posId, OrderType.SL), amount=-pos.current_open_amount,
                              stop=pos.initial_stop))
                else:
                    self.logger.warn(
                        "found position with no stop in market. %s with %.1f contracts. but no initial stop on position had to close" % (
                            posId, pos.current_open_amount))
                    self.order_interface.send_order(
                        Order(orderId=self.generate_order_id(posId, OrderType.SL), amount=-pos.current_open_amount))
            else:
                self.logger.warn(
                    "pending position with noconnected order not pending or open? closed: %s" % (posId))
                self.position_closed(pos, account)

        remainingPosition = round(remainingPosition, self.symbol.quantityPrecision)
        # now there should not be any mismatch between positions and orders.
        if remainingPosition != 0:
            if self.unaccounted_position_cool_off > 1:
                unmatched_stop = self.get_stop_for_unmatched_amount(remainingPosition, bars)
                signalId = str(bars[1].tstamp) + '+' + str(randint(0, 99))
                if unmatched_stop is not None:
                    posId = self.full_pos_id(signalId,
                                             PositionDirection.LONG if remainingPosition > 0 else PositionDirection.SHORT)
                    newPos = Position(id=posId, entry=None, amount=remainingPosition,
                                      stop=unmatched_stop, tstamp=bars[0].tstamp)
                    newPos.status = PositionStatus.OPEN
                    self.open_positions[posId] = newPos
                    # add stop
                    self.logger.info(
                        "couldn't account for " + str(
                            newPos.current_open_amount) + " open contracts. Adding position with stop for it")
                    self.order_interface.send_order(Order(orderId=self.generate_order_id(posId, OrderType.SL),
                                                          stop=newPos.initial_stop, amount=-newPos.current_open_amount))
                elif account.open_position.quantity * remainingPosition > 0:
                    self.logger.info(
                        "couldn't account for " + str(remainingPosition) + " open contracts. Market close")
                    self.order_interface.send_order(Order(orderId=signalId + "_marketClose", amount=-remainingPosition))
                else:
                    self.logger.info(
                        "couldn't account for " + str(
                            remainingPosition) + " open contracts. But close would increase exposure-> mark positions as closed")

                    for pos in self.open_positions.values():
                        if pos.status == PositionStatus.OPEN and abs(
                                remainingPosition + pos.current_open_amount) < self.symbol.lotSize:
                            self.logger.info(f"marked position {pos.id} with exact size as closed ")
                            self.position_closed(pos, account)
                            remainingPosition += pos.current_open_amount
                            break

                    if abs(remainingPosition) >= self.symbol.lotSize:
                        # close orders until size closed
                        # TODO: sort by size, close until position flips side
                        pos_to_close = []
                        for pos in self.open_positions.values():
                            if pos.status == PositionStatus.OPEN and pos.current_open_amount * remainingPosition < 0:
                                # rough sorting to have the smallest first
                                if len(pos_to_close) > 0 and abs(pos.current_open_amount) <= abs(
                                        pos_to_close[0].current_open_amount):
                                    pos_to_close.insert(0, pos)
                                else:
                                    pos_to_close.append(pos)
                        direction = 1 if remainingPosition > 0 else -1
                        for pos in pos_to_close:
                            if direction * remainingPosition <= 0 or abs(remainingPosition) < self.symbol.lotSize:
                                break
                            self.logger.info(f"marked position {pos.id} as closed ")
                            remainingPosition += pos.current_open_amount
                            self.position_closed(pos, account)


            else:
                self.logger.info(
                    "couldn't account for " + str(
                        remainingPosition) + " open contracts. cooling off, hoping it's a glitch")
                self.unaccounted_position_cool_off += 1
        else:
            self.unaccounted_position_cool_off = 0
コード例 #12
0
ファイル: trading_bot.py プロジェクト: SteWolk/kuegiBot
 def handle_opened_or_changed_position(self, position: Position, account: Account, bars: List[Bar]):
     position.status = PositionStatus.OPEN
     self.position_got_opened_or_changed(position, bars, account)
コード例 #13
0
ファイル: SfpStrat.py プロジェクト: tehfonsi/kuegiBot
    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))
コード例 #14
0
ファイル: ranging_strat.py プロジェクト: SteWolk/kuegiBot
    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(data.shortSwing, roundUp=False)
                #shortEntry = self.symbol.normalizePrice(data.longSwing, roundUp=True)

                longEntry = self.symbol.normalizePrice(data.longTrail,
                                                       roundUp=False)
                shortEntry = self.symbol.normalizePrice(data.shortTrail,
                                                        roundUp=True)

                stopLong = self.symbol.normalizePrice(
                    longEntry - self.sl_fac * (shortEntry - data.longTrail),
                    roundUp=False)
                stopShort = self.symbol.normalizePrice(
                    shortEntry + self.sl_fac * (data.shortTrail - longEntry),
                    roundUp=False)

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

                marketTrend = self.markettrend.get_market_trend()

                expectedEntrySlippagePer = 0.0015 if self.limit_entry_offset_perc is None else 0
                expectedExitSlippagePer = 0.0015

                # first check if we should update an existing one
                longAmount = self.calc_pos_size(
                    risk=risk,
                    exitPrice=stopLong * (1 - expectedExitSlippagePer),
                    entry=longEntry * (1 + expectedEntrySlippagePer),
                    atr=data.atr)
                shortAmount = self.calc_pos_size(
                    risk=risk,
                    exitPrice=stopShort * (1 + expectedExitSlippagePer),
                    entry=shortEntry * (1 - expectedEntrySlippagePer),
                    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 + expectedEntrySlippagePer)
                            exitFac = (1 - expectedExitSlippagePer)
                        else:
                            foundShort = True
                            entry = shortEntry
                            stop = stopShort
                            entryFac = (1 - expectedEntrySlippagePer)
                            exitFac = (1 + expectedExitSlippagePer)
                        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 and (
                        marketTrend == 0 or marketTrend == 1):
                    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 and (
                        marketTrend == 0 or marketTrend == -1):
                    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)