def compute(self, timestamp, high, low, close): # Breakout Indicator Inputs bb_basis = ta_EMA(close, self._bb_L) if self._use_EMA else ta_SMA( close, self._bb_L) fast_ma = ta_EMA(close, self._fast_MA_L) # Deviation (a simple BBAND) # dev = ta_STDDEV(close, self._bb_L) # bb_dev_inner = self._base_multiplier * dev # Upper bands # inner_high = bb_basis + bb_dev_inner # Lower Bands # inner_low = bb_basis - bb_dev_inner # Calculate Awesome Oscillator hl2 = (high + low) * 0.5 xSMA1_hl2 = ta_SMA(hl2, self._awesome_fast_L) xSMA2_hl2 = ta_SMA(hl2, self._awesome_slow_L) xSMA1_SMA2 = xSMA1_hl2 - xSMA2_hl2 # Calculate direction of AO if xSMA1_SMA2[-1] >= 0: if xSMA1_SMA2[-1] > xSMA1_SMA2[-2]: AO = 1 else: AO = 2 else: if xSMA1_SMA2[-1] > xSMA1_SMA2[-2]: AO = -1 else: AO = -2 # Calc breakouts break_down = crossunder( fast_ma, bb_basis) and close[-1] < bb_basis[-1] and AO < 0 # abs(AO)==2 break_up = crossover( fast_ma, bb_basis) and close[-1] > bb_basis[-1] and AO > 0 # abs(AO)==1 self._signal = 1 if break_up else -1 if break_down else 0 self._last_timestamp = timestamp return self._signal
def compute(self, timestamp, high, low, close): # Breakout Indicator Inputs bb_basis = ta_EMA(close, self._bb_L) if self._use_EMA else ta_SMA( close, self._bb_L) fast_ma = ta_EMA(close, self._fast_MA_L) # Calculate Awesome Oscillator hl2 = (high + low) * 0.5 xSMA1_hl2 = ta_SMA(hl2, self._awesome_fast_L) xSMA2_hl2 = ta_SMA(hl2, self._awesome_slow_L) xSMA1_SMA2 = xSMA1_hl2 - xSMA2_hl2 # Calculate direction of AO if xSMA1_SMA2[-1] >= 0: if xSMA1_SMA2[-1] > xSMA1_SMA2[-2]: AO = 1 else: AO = 2 else: if xSMA1_SMA2[-1] > xSMA1_SMA2[-2]: AO = -1 else: AO = -2 # Calc breakouts break_down = crossunder( fast_ma, bb_basis) and close[-1] < bb_basis[-1] and AO < 0 # abs(AO)==2 break_up = crossover( fast_ma, bb_basis) and close[-1] > bb_basis[-1] and AO > 0 # abs(AO)==1 self._signal = 1 if break_up else -1 if break_down else 0 self._last_timestamp = timestamp return self._signal
def process(self, timeframe, timestamp): # process only at base timeframe if timeframe != self.base_timeframe: return # update data at tick level if timeframe == self.base_timeframe: self.gen_candles_from_ticks(timestamp) accept, compute = self.filter_market(timestamp) if not accept: return # and compute entries = [] exits = [] if compute: entries, exits = self.compute(timeframe, timestamp) # # global indicators # ref_price = self.timeframes[self.ref_timeframe].price.last # sma200 = self.timeframes[self.ref_timeframe].sma200.last ref_sma55 = self.timeframes[self.ref_timeframe].sma55.last ref_sma = self.timeframes[self.ref_timeframe].sma.last ref_ema = self.timeframes[self.ref_timeframe].ema.last # # compute the entry # retained_entries = [] for entry in entries: # only allowed range of signal for entry if not (self.min_traded_timeframe <= entry.timeframe <= self.max_traded_timeframe): continue # trade region if not self.check_regions(timestamp, self.instrument.market_bid, self.instrument.market_ofr, entry, self.region_allow): continue # ref timeframe is contrary if entry.direction > 0 and not self.timeframes[ self.sltp_timeframe].can_long: continue if entry.direction < 0 and not self.timeframes[ self.sltp_timeframe].can_short: continue # initial stop-loss atr_stop = self.timeframes[self.sltp_timeframe].atr.stop_loss( entry.dir) if entry.direction > 0: # and an initial target take_profit = self.timeframes[ self.ref_timeframe].pivotpoint.last_resistances[2] if atr_stop < self.instrument.open_exec_price(entry.dir): entry.sl = atr_stop gain = (take_profit - entry.p) / entry.p loss = (entry.p - entry.sl) / entry.p elif entry.direction < 0: # and an initial target take_profit = self.timeframes[ self.ref_timeframe].pivotpoint.last_supports[2] if atr_stop > self.instrument.open_exec_price(entry.dir): entry.sl = atr_stop gain = (entry.p - take_profit) / entry.p loss = (entry.sl - entry.p) / entry.p if loss != 0 and (gain / loss < 1.0): Terminal.inst().message( "%s %s %s %s %s %s" % (entry.p, entry.sl, take_profit, gain, loss, (gain / loss)), view="debug") continue # not enought potential profit if gain < 0.005: continue entry.tp = take_profit if gain > 0.005 else entry.p * 1.01 entry.set('partial-take-profit', 1.0) # max loss at x% if loss > 0.035: if entry.direction > 0: entry.sl = entry.price * (1 - 0.035) elif entry.direction < 0: entry.sl = entry.price * (1 + 0.035) # or do not do the trade to risky # continue retained_entries.append(entry) # TP 50% entry # entry_50pc = StrategySignal(0, 0) # entry_50pc.dup(entry) # entry_50pc.tp = np.max(self.timeframes[self.sltp_timeframe].pivotpoint.resistances[0])#[-1] # entry_50pc.set('partial-take-profit', 0.25) # retained_entries.append(entry_50pc) # # process eventually exits signals # if self.trades: self.lock() for trade in self.trades: retained_exit = None # important if we dont want to update user controlled trades if it have some operations user_mgmt = trade.is_user_trade() for signal in exits: # @todo how to managed exit region ? # receive an exit signal of the timeframe of the trade if signal.timeframe == trade.timeframe: retained_exit = signal break # exit signal on reference timeframe if signal.timeframe == self.ref_timeframe: retained_exit = signal break # exit from any parent timeframe signal # if signal.timeframe > trade.timeframe: # retained_exit = signal # break # can cancel a non filled trade if exit signal occurs before timeout (timeframe) # if trade.is_entry_timeout(timestamp, trade.timeframe): # trader = self.strategy.trader() # trade.cancel_open(trader) # Terminal.inst().info("Canceled order (exit signal or entry timeout) %s" % (self.instrument.market_id,), view='default') # continue if user_mgmt: retained_exit = None # if trade.is_opened() and not trade.is_valid(timestamp, trade.timeframe): # # @todo re-adjust entry # Terminal.inst().info("Update order %s trade %s TODO" % (trade.id, self.instrument.market_id,), view='default') # continue # only for active and currently not closing trades if not trade.is_active() or trade.is_closing( ) or trade.is_closed(): continue close_exec_price = self.instrument.close_exec_price(trade.dir) # # stop-loss update # # always need a target, even if user trade and a stop order update_tp = not trade.tp or not trade.has_limit_order() update_sl = not trade.sl or not trade.has_stop_order() # current sl/tp stop_loss = trade.sl take_profit = trade.tp # ATR stop-loss (long/short) atr_stop = self.timeframes[self.sltp_timeframe].atr.stop_loss( trade.direction) if trade.direction > 0: # long, greater or initial if atr_stop > stop_loss and atr_stop < close_exec_price * 0.995: stop_loss = atr_stop elif trade.direction < 0: # short, lesser or initial if (atr_stop < stop_loss or stop_loss <= 0 ) and atr_stop > close_exec_price * 1.005: stop_loss = atr_stop # update take-profit if necessary, and trailing stop-loss # new_exit = self.update_exit(trade, close_exec_price, self.timeframes[self.ref_timeframe].price, self.timeframes[self.ref_timeframe].pointpivot) if self.timeframes[ self.ref_timeframe].pivotpoint.last_pivot > 0.0: if trade.direction > 0: # long if close_exec_price > self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[2]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.resistances[2]): update_tp = True if stop_loss < self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[ 1]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_resistances[1] elif close_exec_price > self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[1]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.resistances[1]): update_tp = True if stop_loss < self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[ 0]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_resistances[0] elif close_exec_price > self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[0]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.resistances[0]): update_tp = True if stop_loss < self.timeframes[ self.ref_timeframe].pivotpoint.last_pivot: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_pivot elif close_exec_price > self.timeframes[ self.ref_timeframe].pivotpoint.last_pivot: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[ self.ref_timeframe].pivotpoint.pivot): update_tp = True if stop_loss < self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[0]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[0] elif close_exec_price > self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[0]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.supports[0]): update_tp = True if trade.sl < self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[1]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[1] elif close_exec_price > self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[1]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.supports[1]): update_tp = True if trade.sl < self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[2]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[2] elif close_exec_price > self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[2]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.supports[2]): update_tp = True if close_exec_price < self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[2]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[2] elif trade.direction < 0: # short (could use the sign, but if we want a non symmetrical approch...) if close_exec_price < self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[2]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.supports[2]): update_tp = True if close_exec_price > self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[2]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[2] elif close_exec_price < self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[1]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.supports[1]): update_tp = True if trade.sl > self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[2]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[2] elif close_exec_price < self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[0]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.supports[0]): update_tp = True if trade.sl > self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[1]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[1] elif close_exec_price < self.timeframes[ self.ref_timeframe].pivotpoint.last_pivot: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[ self.ref_timeframe].pivotpoint.pivot): update_tp = True if stop_loss > self.timeframes[ self. ref_timeframe].pivotpoint.last_supports[0]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_supports[0] elif close_exec_price < self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[0]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.resistances[0]): update_tp = True if stop_loss > self.timeframes[ self.ref_timeframe].pivotpoint.last_pivot: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_pivot elif close_exec_price < self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[1]: if utils.crossover( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.resistances[1]): update_tp = True if stop_loss > self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[ 0]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_resistances[0] elif close_exec_price < self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[2]: if utils.crossunder( self.timeframes[ self.ref_timeframe].price.prices, self.timeframes[self.ref_timeframe]. pivotpoint.resistances[2]): update_tp = True if stop_loss > self.timeframes[ self. ref_timeframe].pivotpoint.last_resistances[ 1]: update_sl = True # stop_loss = self.timeframes[self.ref_timeframe].pivotpoint.last_resistances[1] # # target update # # enought potential profit (0.5% min target) if trade.direction > 0: take_profit = self.timeframes[ self.ref_timeframe].pivotpoint.last_resistances[ int(2 * trade.get('partial-take-profit', 0))] # if take_profit <= trade.entry_price: # take_profit = trade.entry_price * 1.05 gain = (take_profit - trade.entry_price) / trade.entry_price loss = (trade.entry_price - trade.sl) / trade.entry_price elif trade.direction < 0: take_profit = self.timeframes[ self.ref_timeframe].pivotpoint.last_supports[int( 2 * trade.get('partial-take-profit', 0))] # if take_profit >= trade.entry_price: # take_profit = trade.entry_price * 0.95 gain = (trade.entry_price - take_profit) / trade.entry_price loss = (trade.sl - trade.entry_price) / trade.entry_price # reevaluate the R:R # @todo # if gain < 0.005 and update_tp: # ... if update_sl and stop_loss > 0: stop_loss = self.instrument.adjust_price(stop_loss) if trade.sl != stop_loss: # logger.info("SL %s %s %s" % (update_sl, stop_loss, trade.sl)) delta_time = timestamp - trade.last_stop_loss[0] num_orders = trade.last_stop_loss[1] # too many stop-loss modifications in the timeframe if not trade.has_stop_order( ) or delta_time > 60.0: #not ((self.sltp_max_rate > num_orders) and (delta_time < self.sltp_max_timeframe)): try: trade.modify_stop_loss(self.strategy.trader(), self.instrument, stop_loss) except Exception as e: logger.error(repr(e)) Terminal.inst().info("%s modify SL" % timestamp, view="debug") else: trade.sl = stop_loss if update_tp and take_profit > 0: take_profit = self.instrument.adjust_price(take_profit) if trade.tp != take_profit: logger.info("TP %s %s %s" % (update_tp, take_profit, trade.tp)) delta_time = timestamp - trade.last_take_profit[0] num_orders = trade.last_take_profit[1] # too many stop-loss modifications in the timeframe if not trade.has_limit_order( ) or delta_time > 60.0: #not ((self.sltp_max_rate > num_orders) and (delta_time < self.sltp_max_timeframe)): try: trade.modify_take_profit( self.strategy.trader(), self.instrument, take_profit) except Exception as e: logger.error(repr(e)) Terminal.inst().info("%s modify TP" % timestamp, view="debug") else: trade.tp = take_profit # # exit trade if an exit signal retained # if retained_exit: self.process_exit(timestamp, trade, retained_exit.price) Terminal.inst().info("Exit trade %s %s" % (self.instrument.symbol, trade.id), view='debug') self.unlock() # update actives trades self.update_trades(timestamp) # retained long entry do the order entry signal for entry in retained_entries: self.process_entry(timestamp, entry.dir, entry.price, entry.tp, entry.sl, entry.timeframe, entry.get('partial-take-profit', 0)) # streaming self.stream()