def calc_swing(self, bars: List[Bar], direction, default, maxLookBack, minDelta): series = BarSeries.HIGH if direction > 0 else BarSeries.LOW for length in range(1, min(self.max_swing_length + 1, maxLookBack - 1)): cex = lowest(bars, length, 1, series) ex = highest(bars, length, 1, series) preRange = highest(bars, 2, length + 1, series) e = ex if direction < 0: e = cex preRange = lowest(bars, 2, length + 1, series) if direction * (e - preRange) > 0 \ and direction * (e - get_bar_value(bars[length + 1], series)) > minDelta \ and direction * (e - get_bar_value(bars[0], series)) > minDelta: return e + direction * minDelta return default
def calc_trail(self, bars: List[Bar], offset, direction, move_length, threshold, maxDist): if direction > 0: range = highest(bars, 2, offset + move_length, BarSeries.HIGH) move = bars[offset].high - range last_value = bars[0].low offset_value = bars[offset].low else: range = lowest(bars, 2, offset + move_length, BarSeries.LOW) move = range - bars[offset].low last_value = bars[0].high offset_value = bars[offset].high last_data: Data = self.get_data(bars[1]) if last_data is None: # defaults last_since_reset = 0 last_buffer = 0 else: last_buffer = last_data.buffer if direction > 0: last_since_reset = last_data.sinceLongReset else: last_since_reset = last_data.sinceShortReset if move > threshold and last_since_reset >= move_length and ( offset_value - last_value) * direction < 0 and ( range - last_value) * direction < 0: sinceReset = move_length + 1 else: sinceReset = min(last_since_reset + 1, self.max_look_back) if direction > 0: trail = max( lowest(bars, sinceReset - 1, 0, BarSeries.LOW) - maxDist, lowest(bars, sinceReset, 0, BarSeries.LOW) - last_buffer) else: trail = min( highest(bars, sinceReset - 1, 0, BarSeries.HIGH) + maxDist, highest(bars, sinceReset, 0, BarSeries.HIGH) + last_buffer) return [sinceReset, trail]
def process_bar(self, bars: List[Bar]): prevData: Data = self.get_data(bars[1]) swingHigh = prevData.swingHigh if prevData is not None else None highestAfter = highest(bars, self.after, 1, BarSeries.HIGH) candidate = bars[self.after + 1].high highestBefore = highest(bars, self.before, self.after + 2, BarSeries.HIGH) if highestAfter <= candidate and highestBefore <= candidate: swingHigh = candidate if swingHigh is not None and bars[0].high > swingHigh: swingHigh = None swingLow = prevData.swingLow if prevData is not None else None lowestAfter = lowest(bars, self.after, 1, BarSeries.LOW) candidate = bars[self.after + 1].low lowestBefore = lowest(bars, self.before, self.after + 2, BarSeries.LOW) if lowestAfter >= candidate and lowestBefore >= candidate: swingLow = candidate if swingLow is not None and bars[0].low < swingLow: swingLow = None self.write_data(bars[0], Data(swingHigh=swingHigh, swingLow=swingLow))
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