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)
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
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))