Resampling issues + adding multiple timeframes
-
@dasch
class Trend_Indicator(bt.Indicator): lines = ('Trend', 'ohlc') params = ( ('slowma', 21), ('fastma', 8), ) def __init__(self): # Add Bollinger bands self.BB = bt.indicators.BollingerBands(self.datas[0]) self.ohlc.open = self.datas[0].open[0] self.ohlc.high = self.datas[0].high[0] self.ohlc.low = self.datas[0].low[0] self.ohlc.close = self.datas[0].close[0] self.SlowEMA= bt.indicators.EMA(self.datas[0],period=self.params.slowma) self.FastEMA = bt.indicators.EMA(self.datas[0],period=self.params.fastma) self.Trend.bollinger_touch = "" self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters = {"20BarRule": False, "EMARule": False, "OppositeBollingerTouch": False} self.Trend.EMARule = {"Close1":False, "Close2":False} self.Trend.Position = 0 self.Trend.Test = 0 self.addminperiod(21) def next(self): if self.Trend.bollinger_touch == "Top" and self.data.low[0] > self.BB.lines.bot[0] and self.Trend.Enter == "": # if the upper bollinger band was touched and the candle we have now makes the highest high and highest close, # we enter in an uptrend if self.data.high[0] > self.ohlc.high and self.data.close[0] > self.ohlc.close: self.Trend.Enter = "Uptrend entered" self.ohlc.high = self.data.high[0] self.Trend.Status = "Up" self.Trend.ExitParameters["OppositeBollingerTouch"] = False self.Trend.ExitParameters["20BarRule"] = False self.Trend.ExitParameters["EMARule"] = False self.Trend.Position = len(self.ohlc) self.Trend.Test = len(self.data.high) if self.data.high[0] > self.ohlc.high: self.ohlc.high = self.data.high[0] if self.data.close[0] > self.ohlc.close: self.ohlc.close = self.data.close[0] # we enter in a downtrend elif self.Trend.bollinger_touch == 'Bottom' and self.data.high[0] < self.BB.lines.top[0] and self.Trend.Enter == "": # if the bottom bollinger band was touched and the candle we have now makes the lowest low and lowest close, # we enter in a downtrend if self.data.low[0] < self.ohlc.low and self.data.close[0] < self.ohlc.close: self.Trend.Enter = "Downtrend entered" self.ohlc.low = self.data.low[0] self.Trend.Status = "Down" self.Trend.ExitParameters["OppositeBollingerTouch"] = False self.Trend.ExitParameters["20BarRule"] = False self.Trend.ExitParameters["EMARule"] = False self.Trend.Position = len(self.ohlc) self.Trend.Test = len(self.data.low) if self.data.low[0] < self.ohlc.low: self.ohlc.low = self.data.low[0] if self.data.close[0] < self.ohlc.close: self.ohlc.close = self.data.close[0] elif self.Trend.bollinger_touch == "": # look for a top bollinger touch, then store that bar's data if self.data.high[0] >= self.BB.lines.top[0] and self.data.low[0] > self.BB.lines.bot[0]: self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] self.Trend.bollinger_touch = "Top" elif self.data.low[0] <= self.BB.lines.bot[0] and self.data.high[0] < self.BB.lines.top[0]: self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] self.Trend.bollinger_touch = "Bottom" # if the upper bollinger band was touched but now the lower bollinger band got touched, the upper bollinger touch resets if self.Trend.bollinger_touch == "Top" and self.data.low[0] <= self.BB.lines.bot[0]: self.Trend.bollinger_touch = "Bottom" self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # if the bottom bollinger band was touched but now the top bollinger band got touched, the bottom bollinger touch resets elif self.Trend.bollinger_touch == "Bottom" and self.data.high[0] >= self.BB.lines.top[0]: self.Trend.bollinger_touch = "Top" self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # we are in an uptrend if self.Trend.Status == "Up": # if the opposite bollinger band was touched, we exit the uptrend if self.data.low[0] <= self.BB.lines.bot[0]: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["OppositeBollingerTouch"] = True self.Trend.bollinger_touch = "Bottom" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # if a fresh high is made, keep track of the position if self.data.high[0] > self.ohlc.high: self.ohlc.high = self.data.high[0] self.Trend.Position = len(self.data.high) # after 20 bars (excluding the first) no new high is made, we are not in a trend anymore elif self.data.high[0] < self.ohlc.high: if len(self.data.high) - self.Trend.Position >= 21: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["20BarRule"] = True self.Trend.bollinger_touch = "Bottom" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.ExitParameters['20BarRule'] = True # if the top bollinger band was touched, reset the EMA rule if self.data.high[0] >= self.BB.lines.top[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False if self.data.close[0] < self.SlowEMA[0] and self.data.close[0] < self.FastEMA[0]: self.Trend.EMARule['Close1'] = True if self.Trend.EMARule['Close1'] == True and self.data.close[0] > self.SlowEMA[0] and self.data.close[0] > self.FastEMA[0]: self.Trend.EMARule['Close2'] = True if self.Trend.EMARule['Close1'] == True and self.Trend.EMARule['Close2'] == True and self.data.close[0] < self.SlowEMA[0] and self.data.close[0] < self.FastEMA[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters['EMARule'] = True self.Trend.bollinger_touch = "" if self.Trend.Enter == "Uptrend entered" and True not in self.Trend.ExitParameters.values(): self.Trend[0] = 1 # we are in a downtrend if self.Trend.Status == "Down": # if the opposite bollinger band was touched, we exit the downtrend if self.data.high[0] >= self.BB.lines.top[0]: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["OppositeBollingerTouch"] = True self.Trend.bollinger_touch = "Top" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # if a fresh low is made, keep track of the position if self.data.low[0] < self.ohlc.high: self.ohlc.low = self.data.low[0] self.Trend.Position = len(self.data.low) # after 20 bars (excluding the first) no new low is made, we are not in a trend anymore elif self.data.low[0] > self.ohlc.low: if len(self.data.low) - self.Trend.Position >= 21: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["20BarRule"] = True self.Trend.bollinger_touch = "" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.ExitParameters['20BarRule'] = True # if the bottom bollinger band was touched, reset the EMA rule if self.data.low[0] <= self.BB.lines.bot[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False if self.data.close[0] > self.SlowEMA[0] and self.data.close[0] > self.FastEMA[0]: self.Trend.EMARule['Close1'] = True if self.Trend.EMARule['Close1'] == True and self.data.close[0] < self.SlowEMA[0] and self.data.close[0] < self.FastEMA[0]: self.Trend.EMARule['Close2'] = True if self.Trend.EMARule['Close1'] == True and self.Trend.EMARule['Close2'] == True and self.data.close[0] > self.SlowEMA[0] and self.data.close[0] > self.FastEMA[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters['EMARule'] = True self.Trend.bollinger_touch = "" if self.Trend.Enter == "Downtrend entered" and True not in self.Trend.ExitParameters.values(): self.Trend[0] = -1
-
you have some issues with your code:
self.ohlc.open = self.datas[0].open[0] self.ohlc.high = self.datas[0].high[0] self.ohlc.low = self.datas[0].low[0] self.ohlc.close = self.datas[0].close[0]
so change it to:
self.ohlc.open = None self.ohlc.high = None self.ohlc.low = None self.ohlc.close = None
you also don't need to add a minperiod, since next will be called, when your indicators are filled.
if you want to init the attributes, you assign to the lines (?) ex. this way: self.Trend.Status = "", which works but is confusing, you could also set the inital ohlc values in nextstart:
def nextstart(self): self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0]
-
oh, somehow the way it will not work that way is gone. In init you will not be able to access data that way you do it.
Check out the Stage 1 - Stage 2 difference in this doc:
https://www.backtrader.com/docu/concepts/#stage-1-operators-create-objects
https://www.backtrader.com/docu/concepts/#stage-2-operators-true-to-nature -
So here is your fixed code, but to say it again, the way you set the values is confusing.
You create a indicator line ohlc, then you set attributes to it, you never fill it with any data. Also you set attributes to the Trend line to keep track of the trend state.
Better would be not adding the ohlc line, set all your tracking vars to the indicator.
import backtrader as bt class Trend_Indicator(bt.Indicator): lines = ('Trend', 'ohlc') params = ( ('slowma', 21), ('fastma', 8), ) def __init__(self): # Add Bollinger bands self.BB = bt.indicators.BollingerBands(self.datas[0]) self.SlowEMA = bt.indicators.EMA( self.datas[0], period=self.params.slowma) self.FastEMA = bt.indicators.EMA( self.datas[0], period=self.params.fastma) self.Trend.bollinger_touch = "" self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters = { "20BarRule": False, "EMARule": False, "OppositeBollingerTouch": False} self.Trend.EMARule = {"Close1": False, "Close2": False} self.Trend.Position = 0 self.Trend.Test = 0 def nextstart(self): self.ohlc.open = self.datas[0].open[0] self.ohlc.high = self.datas[0].high[0] self.ohlc.low = self.datas[0].low[0] self.ohlc.close = self.datas[0].close[0] def next(self): if self.Trend.bollinger_touch == "Top" and self.data.low[0] > self.BB.lines.bot[0] and self.Trend.Enter == "": # if the upper bollinger band was touched and the candle we have now makes the highest high and highest close, # we enter in an uptrend if self.data.high[0] > self.ohlc.high and self.data.close[0] > self.ohlc.close: self.Trend.Enter = "Uptrend entered" self.ohlc.high = self.data.high[0] self.Trend.Status = "Up" self.Trend.ExitParameters["OppositeBollingerTouch"] = False self.Trend.ExitParameters["20BarRule"] = False self.Trend.ExitParameters["EMARule"] = False self.Trend.Position = len(self.ohlc) self.Trend.Test = len(self.data.high) if self.data.high[0] > self.ohlc.high: self.ohlc.high = self.data.high[0] if self.data.close[0] > self.ohlc.close: self.ohlc.close = self.data.close[0] # we enter in a downtrend elif self.Trend.bollinger_touch == 'Bottom' and self.data.high[0] < self.BB.lines.top[0] and self.Trend.Enter == "": # if the bottom bollinger band was touched and the candle we have now makes the lowest low and lowest close, # we enter in a downtrend if self.data.low[0] < self.ohlc.low and self.data.close[0] < self.ohlc.close: self.Trend.Enter = "Downtrend entered" self.ohlc.low = self.data.low[0] self.Trend.Status = "Down" self.Trend.ExitParameters["OppositeBollingerTouch"] = False self.Trend.ExitParameters["20BarRule"] = False self.Trend.ExitParameters["EMARule"] = False self.Trend.Position = len(self.ohlc) self.Trend.Test = len(self.data.low) if self.data.low[0] < self.ohlc.low: self.ohlc.low = self.data.low[0] if self.data.close[0] < self.ohlc.close: self.ohlc.close = self.data.close[0] elif self.Trend.bollinger_touch == "": # look for a top bollinger touch, then store that bar's data if self.data.high[0] >= self.BB.lines.top[0] and self.data.low[0] > self.BB.lines.bot[0]: self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] self.Trend.bollinger_touch = "Top" elif self.data.low[0] <= self.BB.lines.bot[0] and self.data.high[0] < self.BB.lines.top[0]: self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] self.Trend.bollinger_touch = "Bottom" # if the upper bollinger band was touched but now the lower bollinger band got touched, the upper bollinger touch resets if self.Trend.bollinger_touch == "Top" and self.data.low[0] <= self.BB.lines.bot[0]: self.Trend.bollinger_touch = "Bottom" self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # if the bottom bollinger band was touched but now the top bollinger band got touched, the bottom bollinger touch resets elif self.Trend.bollinger_touch == "Bottom" and self.data.high[0] >= self.BB.lines.top[0]: self.Trend.bollinger_touch = "Top" self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # we are in an uptrend if self.Trend.Status == "Up": # if the opposite bollinger band was touched, we exit the uptrend if self.data.low[0] <= self.BB.lines.bot[0]: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["OppositeBollingerTouch"] = True self.Trend.bollinger_touch = "Bottom" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # if a fresh high is made, keep track of the position if self.data.high[0] > self.ohlc.high: self.ohlc.high = self.data.high[0] self.Trend.Position = len(self.data.high) # after 20 bars (excluding the first) no new high is made, we are not in a trend anymore elif self.data.high[0] < self.ohlc.high: if len(self.data.high) - self.Trend.Position >= 21: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["20BarRule"] = True self.Trend.bollinger_touch = "Bottom" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.ExitParameters['20BarRule'] = True # if the top bollinger band was touched, reset the EMA rule if self.data.high[0] >= self.BB.lines.top[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False if self.data.close[0] < self.SlowEMA[0] and self.data.close[0] < self.FastEMA[0]: self.Trend.EMARule['Close1'] = True if self.Trend.EMARule['Close1'] == True and self.data.close[0] > self.SlowEMA[0] and self.data.close[0] > self.FastEMA[0]: self.Trend.EMARule['Close2'] = True if self.Trend.EMARule['Close1'] == True and self.Trend.EMARule['Close2'] == True and self.data.close[0] < self.SlowEMA[0] and self.data.close[0] < self.FastEMA[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters['EMARule'] = True self.Trend.bollinger_touch = "" if self.Trend.Enter == "Uptrend entered" and True not in self.Trend.ExitParameters.values(): self.Trend[0] = 1 # we are in a downtrend if self.Trend.Status == "Down": # if the opposite bollinger band was touched, we exit the downtrend if self.data.high[0] >= self.BB.lines.top[0]: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["OppositeBollingerTouch"] = True self.Trend.bollinger_touch = "Top" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.ohlc.open = self.data.open[0] self.ohlc.high = self.data.high[0] self.ohlc.low = self.data.low[0] self.ohlc.close = self.data.close[0] # if a fresh low is made, keep track of the position if self.data.low[0] < self.ohlc.high: self.ohlc.low = self.data.low[0] self.Trend.Position = len(self.data.low) # after 20 bars (excluding the first) no new low is made, we are not in a trend anymore elif self.data.low[0] > self.ohlc.low: if len(self.data.low) - self.Trend.Position >= 21: self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters["20BarRule"] = True self.Trend.bollinger_touch = "" self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.ExitParameters['20BarRule'] = True # if the bottom bollinger band was touched, reset the EMA rule if self.data.low[0] <= self.BB.lines.bot[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False if self.data.close[0] > self.SlowEMA[0] and self.data.close[0] > self.FastEMA[0]: self.Trend.EMARule['Close1'] = True if self.Trend.EMARule['Close1'] == True and self.data.close[0] < self.SlowEMA[0] and self.data.close[0] < self.FastEMA[0]: self.Trend.EMARule['Close2'] = True if self.Trend.EMARule['Close1'] == True and self.Trend.EMARule['Close2'] == True and self.data.close[0] > self.SlowEMA[0] and self.data.close[0] > self.FastEMA[0]: self.Trend.EMARule['Close1'] = False self.Trend.EMARule['Close2'] = False self.Trend.Status = "" self.Trend.Enter = "" self.Trend.ExitParameters['EMARule'] = True self.Trend.bollinger_touch = "" if self.Trend.Enter == "Downtrend entered" and True not in self.Trend.ExitParameters.values(): self.Trend[0] = -1
-
Indicator lines should be calculated as follow
self.lines.Trend = something self.lines.ohlc = something
You may want to read docs on indicator development one more time instead of hitting the wall continuously.
-
@ab_trader it would be good practice, i assume. I prefer also to use self.lines.x . But since backtrader creates these shortcuts, why not use them?
-
here is a cleaned up version of the indicator.
Trend_Indicator(bt.Indicator): lines = ('trend',) params = ( ('slow_ema', 21), ('fast_ema', 8), ) def __init__(self): # Add Bollinger bands self.bb = bt.indicators.BollingerBands() self.slow_ema = bt.indicators.EMA(period=self.params.slow_ema) self.fast_ema = bt.indicators.EMA(period=self.params.fast_ema) self.ohlc = {"o": None, "h": None, "l": None, "c": None} self.trend_bollinger_touch = 0 self.trend_status = 0 self.trend_enter = 0 self.trend_exit_params = { "20BarRule": False, "EMARule": False, "OppositeBollingerTouch": False} self.trend_ema_rule = { "Close1": False, "Close2": False} self.trend_position = 0 self.trend_test = 0 def nextstart(self): self._update_ohlc() def next(self): if (self.trend_bollinger_touch == 1 and self.data.low[0] > self.bb.lines.bot[0] and self.trend_enter == 0): # if the upper bollinger band was touched and the candle # we have now makes the highest high and highest close, # we enter in an uptrend if (self.data.high[0] > self.ohlc["h"] and self.data.close[0] > self.ohlc["c"]): self._update_ohlc(["h"]) self.trend_enter = 1 self.trend_status = 1 self.trend_exit_params["OppositeBollingerTouch"] = False self.trend_exit_params["20BarRule"] = False self.trend_exit_params["EMARule"] = False self.trend_position = len(self.ohlc) self.trend_test = len(self.data.high) if self.data.high[0] > self.ohlc["h"]: self._update_ohlc(["h"]) if self.data.close[0] > self.ohlc["c"]: self._update_ohlc(["c"]) # we enter in a downtrend elif (self.trend_bollinger_touch == -1 and self.data.high[0] < self.bb.lines.top[0] and self.trend_enter == 0): # if the bottom bollinger band was touched and the candle we # have now makes the lowest low and lowest close, we enter # in a downtrend if (self.data.low[0] < self.ohlc["l"] and self.data.close[0] < self.ohlc["c"]): self._update_ohlc(["l"]) self.trend_enter = -1 self.trend_status = -1 self.trend_exit_params["OppositeBollingerTouch"] = False self.trend_exit_params["20BarRule"] = False self.trend_exit_params["EMARule"] = False self.trend_position = len(self.ohlc) self.trend_test = len(self.data.low) if self.data.low[0] < self.ohlc["l"]: self._update_ohlc(["l"]) if self.data.close[0] < self.ohlc["c"]: self._update_ohlc(["c"]) elif self.trend_bollinger_touch == 0: # look for a top bollinger touch, then store that bar's data if (self.data.high[0] >= self.bb.lines.top[0] and self.data.low[0] > self.bb.lines.bot[0]): self._update_ohlc() self.trend_bollinger_touch = 1 elif (self.data.low[0] <= self.bb.lines.bot[0] and self.data.high[0] < self.bb.lines.top[0]): self._update_ohlc() self.trend_bollinger_touch = -1 # if the upper bollinger band was touched but now the lower bollinger # band got touched, the upper bollinger touch resets if (self.trend_bollinger_touch == 1 and self.data.low[0] <= self.bb.lines.bot[0]): self._update_ohlc() self.trend_bollinger_touch = -1 # if the bottom bollinger band was touched but now the top bollinger # band got touched, the bottom bollinger touch resets elif (self.trend_bollinger_touch == -1 and self.data.high[0] >= self.bb.lines.top[0]): self._update_ohlc() self.trend_bollinger_touch = 1 # we are in an uptrend if self.trend_status == 1: # if the opposite bollinger band was touched, we exit the uptrend if self.data.low[0] <= self.bb.lines.bot[0]: self.trend_status = 0 self.trend_enter = 0 self.trend_exit_params["OppositeBollingerTouch"] = True self.trend_bollinger_touch = -1 self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False self._update_ohlc() # if a fresh high is made, keep track of the position if self.data.high[0] > self.ohlc["h"]: self._update_ohlc(["h"]) self.trend_position = len(self.data.high) # after 20 bars (excluding the first) no new high is made, we are # not in a trend anymore elif self.data.high[0] < self.ohlc["h"]: if len(self.data.high) - self.trend_position >= 21: self.trend_status = 0 self.trend_enter = 0 self.trend_bollinger_touch = -1 self.trend_exit_params["20BarRule"] = True self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False self.trend_exit_params['20BarRule'] = True # if the top bollinger band was touched, reset the EMA rule if self.data.high[0] >= self.bb.lines.top[0]: self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False if (self.data.close[0] < self.slow_ema[0] and self.data.close[0] < self.fast_ema[0]): self.trend_ema_rule['Close1'] = True if (self.trend_ema_rule['Close1'] is True and self.data.close[0] > self.slow_ema[0] and self.data.close[0] > self.fast_ema[0]): self.trend_ema_rule['Close2'] = True if (self.trend_ema_rule['Close1'] is True and self.trend_ema_rule['Close2'] is True and self.data.close[0] < self.slow_ema[0] and self.data.close[0] < self.fast_ema[0]): self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False self.trend_exit_params['EMARule'] = True self.trend_enter = 0 self.trend_status = 0 self.trend_bollinger_touch = 0 # we are in a downtrend if self.trend_status == -1: # if the opposite bollinger band was touched, we exit the downtrend if self.data.high[0] >= self.bb.lines.top[0]: self.trend_status = 0 self.trend_enter = 0 self.trend_bollinger_touch = 1 self.trend_exit_params["OppositeBollingerTouch"] = True self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False self._update_ohlc() # if a fresh low is made, keep track of the position if self.data.low[0] < self.ohlc["h"]: self._update_ohlc(["l"]) self.trend_position = len(self.data.low) # after 20 bars (excluding the first) no new low is made, we are # not in a trend anymore elif self.data.low[0] > self.ohlc["l"]: if len(self.data.low) - self.trend_position >= 21: self.trend_status = 0 self.trend_enter = 0 self.trend_bollinger_touch = 0 self.trend_exit_params["20BarRule"] = True self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False self.trend_exit_params['20BarRule'] = True # if the bottom bollinger band was touched, reset the EMA rule if self.data.low[0] <= self.bb.lines.bot[0]: self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False if (self.data.close[0] > self.slow_ema[0] and self.data.close[0] > self.fast_ema[0]): self.trend_ema_rule['Close1'] = True if (self.trend_ema_rule['Close1'] is True and self.data.close[0] < self.slow_ema[0] and self.data.close[0] < self.fast_ema[0]): self.trend_ema_rule['Close2'] = True if (self.trend_ema_rule['Close1'] is True and self.trend_ema_rule['Close2'] is True and self.data.close[0] > self.slow_ema[0] and self.data.close[0] > self.fast_ema[0]): self.trend_status = 0 self.trend_enter = 0 self.trend_bollinger_touch = 0 self.trend_ema_rule['Close1'] = False self.trend_ema_rule['Close2'] = False self.trend_exit_params['EMARule'] = True # update line if (self.trend_enter == -1 and True not in self.trend_exit_params.values()): self.lines.trend[0] = -1 elif (self.trend_enter == 1 and True not in self.trend_exit_params.values()): self.lines.trend[0] = 1 def _update_ohlc(self, values=["o", "h", "l", "c"]): if "o" in values: self.ohlc["o"] = self.data.open[0] if "h" in values: self.ohlc["h"] = self.data.high[0] if "l" in values: self.ohlc["l"] = self.data.low[0] if "c" in values: self.ohlc["c"] = self.data.close[0]
-
@dasch I didn't see indicators made this way in the docs or blog posts. Can you share a link?
-
@ab_trader here: https://www.backtrader.com/docu/inddev/
Let’s recall that self.lines.dummyline is the long notation and that it can be shortened to:
self.l.dummyline
and even to:
self.dummyline
The latter being only possible if the code has not obscured this with a member attribute.
-
@dasch I see, thank you. Looks like I just forgot it since it was not used in the original
bt
scripts I've used as examples. -
@ab_trader there are a lot of shortcuts to different lines, which are not used that much in examples, so it would only make sense to use them, when you know what you are doing.
Thats why your statement is mostly the way to go to use self.lines.x (which also is more readable in code)
-
@dasch thanks a lot. much appreciated
Yes it probably could be a lot better than I have created it. I'm still quite new to backtrader so learning bit by bit.
what was then actually the problem which caused the error? -
@Jens-Halsberghe the actual problem was just the assignment of ohlc values in init:
self.ohlc.open = self.datas[0].open[0] self.ohlc.high = self.datas[0].high[0] self.ohlc.low = self.datas[0].low[0] self.ohlc.close = self.datas[0].close[0]
-
@dasch said in Resampling issues + adding multiple timeframes:
there are a lot of shortcuts to different lines, which are not used that much in examples, so it would only make sense to use them, when you know what you are doing.
I totally agree.