ATR TP/SLs producing unexpected results
-
Hi there. I'm working to port over my PineScript strategies to Backtrader and I've gotten mostly everything to work except for the ATR TP/SL brackets.
The code below is intended to grab the ATR values when the buying condition is met. If the buying condition is met and there is no active position, the ATR TP/SL is calculated based on the ATR value at the time and adds/subtracts it from the current price based on whether a long/short order is being entered into. Subsequently while a position is open, a check is made to determine if price touches either the TP/SL levels set and exits accordingly.
from app import buy import backtrader as bt import backtrader.analyzers as btanalyzers import datetime cerebro = bt.Cerebro() cerebro.broker.set_cash(1000000.0) fromdate = datetime.datetime.strptime('2020-06-01', '%Y-%m-%d') todate = datetime.datetime.strptime('2021-03-12', '%Y-%m-%d') class test_strategy(bt.Strategy): params = (#Ichimoku settings ('conversion_len', 16 ), ('base_len', 7 ), ('laggingSpan2_len', 20 ), #ATR settings ('ATR_len', 12 ), ('ATRLTP_multi', 1.5 ), ('ATRLSL_multi', 1.7 ), ('ATRSTP_multi', 2.2 ), ('ATRSSL_multi', 2.1 ), ) def __init__(self): self.ichimoku = bt.indicators.Ichimoku(tenkan=self.p.conversion_len, kijun=self.p.base_len, senkou=self.p.laggingSpan2_len) self.ATR = bt.indicators.AverageTrueRange(self.data, period=self.p.ATR_len) belowCloud = bt.indicators.Min(self.ichimoku.lines.senkou_span_a, self.ichimoku.lines.senkou_span_b) self.buying = self.datas[0].close(0) > self.ichimoku.lines.kijun_sen self.selling = bt.And(self.datas[0].close(0) < belowCloud, self.datas[0].close(0) < self.ichimoku.lines.kijun_sen) def start(self): self.order = None def next(self): curr_close = self.data.close[0] if self.buying and not self.position: self.buy(size=1) self.ATRL_TP = (self.ATR[0] * self.p.ATRLTP_multi) + curr_close self.ATRL_SL = curr_close - (self.ATR[0] * self.p.ATRLSL_multi) if self.selling and not self.position: self.sell(size=1) self.ATRS_TP = (self.ATR[0] * self.p.ATRSTP_multi) + curr_close self.ATRS_SL = curr_close - (self.ATR[0] * self.p.ATRSSL_multi) if self.position.size > 0: if curr_close >= self.ATRL_TP: self.close() self.ATRL_TP = 0.0 elif curr_close <= self.ATRL_SL: self.close() self.ATRL_SL = 0.0 elif self.position.size < 0: if curr_close <= self.ATRS_TP: self.close() self.ATRS_TP = 0.0 elif curr_close >= self.ATRS_SL: self.close() self.ATRS_SL = 0.0 data = bt.feeds.GenericCSVData(dataname='data/BTC2H.csv', dtformat=2, compression=120, timeframe=bt.TimeFrame.Minutes, fromdate=fromdate, todate=todate) cerebro.adddata(data) cerebro.addstrategy(test_strategy) cerebro.addanalyzer(btanalyzers.PositionAnalyzer) cerebro.run() cerebro.plot(style='candle', barup='green', bardown='red')
The TP/SL brackets produced in backtesting don't match up with what I'm expecting though. In the analyzer output below, the ATR value is 1180.28 for when the first order (2021-01-04) is entered which should produce a TP level of 1758.015. However the TP for this order is 1771.78 which doesn't match. My guess is that the ATR is being recalculated somewhere but I can't find when and where.
Thanks for reading. Is there something I'm missing here?
-
@adenosine said in ATR TP/SLs producing unexpected results:
The TP/SL brackets produced in backtesting don't match up with what I'm expecting though. In the analyzer output below, the ATR value is 1180.28 for when the first order (2021-01-04) is entered which should produce a TP level of 1758.015. However the TP for this order is 1771.78 which doesn't match. My guess is that the ATR is being recalculated somewhere but I can't find when and where.
Sorry, wrong TP value here. Instead of 1758.015, it should be 1770.42
-
@adenosine The best way to know if the ATR value match what you expect it to be would be to log its value, along with entry price (as you may know for market orders, it is supposed to be the open of next bar)
I may have made a mistake checking it, but when I ported over to backtrader some strats with ATR-dependant TP & SL, and ATR calculation in backtrader seemed good to me.BTW you can use bracket orders : https://www.backtrader.com/docu/order-creation-execution/bracket/bracket/
BTW2 : Maybe it is by design but just in case : your sell bracket (under "if self.selling and not self.position:") looks like your buy bracket : TP above price, SL under. -
@emr Interesting. After switching to bracketed orders it worked. Still don't really understand why though.
And you're right, the TP/SL was flipped around for the sell order. Thanks for the extra set of eyes.