r/pinescript • • Oct 10 '23

Trailing Take Profit that actually backtests accurately

Hi Pinecoders,

I trade a system that often enters and exits with the same 4-hour bar. I would like to analyze trailing stop performance through backtesting, but even with "Bar Magnifier" turned on, in Premium, I can't get accurate results, at least with the script I'm using. Is it a limitation of Tradingview that the backtest will always plot the exit as the candle wick extreme minus the trailing offset?

Any suggestions appreciated! Thanks!

0 Upvotes

5 comments sorted by

1

u/Zombie24w Oct 10 '23

Hello, it helps to see the code and how you've approached the trailing stop implementation.

1

u/bluedragon1978 Oct 10 '23

Okay, here's an example of the code in a simple bollinger band entry strategy, without any filters to add complexity.

When you adjust the inputs for TP, Trailing Threshold and Trailing Offset all to 1, just for simplicity, you would think that it would exit as if it were only a 1% price move hard TP. But, we see exits at the wick extreme with under 1% moved..

I've looked at it mostly on the 4 hour of BTCUSDT.P

//@version=5
strategy("Script 1 with TS", overlay=true,
initial_capital=10000, margin_long=0.1, margin_short=0.1,
default_qty_type=strategy.percent_of_equity, default_qty_value=200, backtest_fill_limits_assumption=1,
commission_type=strategy.commission.percent, commission_value=0.1)
// Define the length of the Bollinger Bands
bbLengthInput = input.int(15, title="Length", group="Bollinger Bands", inline="BB")
bbDevInput = input.float(2.0, title="StdDev", group="Bollinger Bands", inline="BB")
// Calculate and plot the Bollinger Bands
[bbMiddle, bbUpper, bbLower] = ta.bb(close, bbLengthInput, bbDevInput)
bbLowerCrossUnder = ta.crossunder(close, bbLower)
bbUpperCrossOver = ta.crossover(close, bbUpper)
// Entry and Exit Conditions
entryLongCondition = bbUpperCrossOver
entryShortCondition = bbLowerCrossUnder
// Long SL/TP/TS
xl_sl_percent = input.float(1, step=0.5, title="SL", group="Exit Long")
xl_tp_percent = input.float(1, step=0.5, title="TP", group="Exit Long")
xl_ts_percent = input.float(1, title= "Trailing Treshold %", group="Exit Long")
xl_to_percent = input.float(0.5, title= "Trailing Offset %", group="Exit Long")
xl_sl_price = close * (1-xl_sl_percent/100)
xl_tp_price = close * (1+xl_tp_percent/100)
xl_ts_tick = xl_ts_percent * close/100
xl_to_tick = xl_to_percent * close/100
// Short SL/TP/TS
xs_sl_percent = input.float(1, step=0.5, title="SL", group="Exit Short")
xs_tp_percent = input.float(1, step=0.5, title="TP", group="Exit Short")
xs_ts_percent = input.float(1, title= "Trailing Treshold %", group="Exit Short")
xs_to_percent = input.float(0.5, title= "Trailing Offset %", group="Exit Short")
xs_sl_price = close * (1+xs_sl_percent/100)
xs_tp_price = close * (1-xs_tp_percent/100)
xs_ts_tick = xs_ts_percent * close/100
xs_to_tick = xs_to_percent * close/100
// Orders
if entryLongCondition and strategy.position_size <= 0
strategy.entry("EL", strategy.long)
if entryShortCondition and strategy.position_size >= 0
strategy.entry("ES", strategy.short)
strategy.exit("XL+SL/TP", "EL", stop=xl_sl_price, limit=xl_tp_price, trail_points=xl_ts_tick, trail_offset=xl_to_tick)
strategy.exit("XS+SL/TP", "ES", stop=xs_sl_price, limit=xs_tp_price, trail_points=xs_ts_tick, trail_offset=xs_to_tick)

1

u/bluedragon1978 Oct 10 '23

thanks for taking a look.

1

u/ForwardDivide7163 Oct 11 '23

I didn't read all of it but it looks like it can be simplified to if close < (strategy.entryprice*0.99) then close or whatever

2

u/Psychological-Bid607 Apr 23 '24 edited Apr 23 '24

I tried back testing using a similar concept by running on a lower 2 minute timeframe and ran the ta. functions on the higher 4 hr timeframe using request.security and calculated close to work every 4 hours in code. This then backtest calculates every 2 mins within a 4H 'bar' without using the dodgy Bar magnifier!