I'm very confused as to what could be causing this behavior, as I created as SuperTrend strategy which looks amazing when plotted on chart but breaks down horribly when tried on a live chart or when using the replay tool.
It is a very simple strategy which opens a long trade when SuperTrend says we are in an uptrend and short trade when SuperTrend says we are in a down trend.
To give you something tangible, I tried this side-by-side with my strategy with the exact same settings for SuperTrend (3m chart with SuperTrend's Time Frame set to 30m, ATR length to 1 and Factor also set to 1). I also set RRR to 1.5 and Stop Loss to previous swing high/low for both tests. I have limited both tests to start and end on the same date (4th November).
Here are the results from the first test where I just put the strategy on chart (no realtime calculations are done, as the market is currently closed):
And here is the other test where I go through the replay tool, starting at the beginning of the day (4th November) and ending at the last bar of that day:
You can see that the results are completely different, especially when it comes to win rate and profit. What I saw was that with Replay Tool (and also observed on a live chart), SuperTrend changes its trend more frequently than when calculated from historical values. But why is the result so wastely different and why does this happen at all, I have no idea.
EDIT:
Here is a custom SuperTrend code with which you can actually test this:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © marketcalls_in
// Rajandran - Founder - Marketcalls / Co-Founder - Algomojo
//@version=4
study("Supertrend - Buy or Sell Signal", overlay = true)
//inputs
Periods = input(title="ATR Period", type=input.integer, defval=10)
Source = input(hl2, title="Source")
Multiplier = input(title="ATR Multiplier", type=input.float, step=0.1, defval=3.0)
//Compute ATR Levels
atr= atr(Periods)
//Creating Upper Channel
cclose = security(syminfo.tickerid, "30", close)
up=Source-(Multiplier*atr)
up1 = nz(up[1],up)
up := cclose[1] > up1 ? max(up,up1) : up
//Creating Down Channel
dn=Source+(Multiplier*atr)
dn1 = nz(dn[1], dn)
dn := cclose[1] < dn1 ? min(dn, dn1) : dn
//Compute the Trend Stream +1/-1
trend = 1
trend := nz(trend[1], trend)
trend := trend == -1 and cclose > dn1 ? 1 : trend == 1 and cclose < up1 ? -1 : trend
//Create Stoploss for Longs
upPlot = plot(trend == 1 ? up : na, title="Up Trend", style=plot.style_linebr, linewidth=2, color=color.green)
//Buy Signal
Buy = trend == 1 and trend[1] == -1
plotshape(Buy ? up : na, title="Go Long", location=location.absolute, style=shape.circle, size=size.tiny, color=color.green, transp=0)
plotshape(Buy ? up : na, title="Buy", text="Buy Mode", location=location.absolute, style=shape.labelup, size=size.tiny, color=color.green, textcolor=color.white, transp=0)
dnPlot = plot(trend == 1 ? na : dn, title="Down Trend", style=plot.style_linebr, linewidth=2, color=color.red)
//Sell Signal
Sell = trend == -1 and trend[1] == 1
plotshape(Sell ? dn : na, title="Go Short", location=location.absolute, style=shape.circle, size=size.tiny, color=color.red, transp=0)
plotshape(Sell ? dn : na, title="Sell", text="Sell Mode", location=location.absolute, style=shape.labeldown, size=size.tiny, color=color.red, textcolor=color.white, transp=0)
iPlot = plot(ohlc4, title="", style=plot.style_circles, linewidth=0)
longFillColor = trend == 1 ? color.green : color.white
shortFillColor = trend == -1 ? color.red : color.white
fill(iPlot, upPlot, title="UpTrend Highligter", color=longFillColor)
fill(iPlot, dnPlot, title="DownTrend Highligter", color=shortFillColor)
//Alerts
alertcondition(Buy, title="SuperTrend Buy", message="SuperTrend Buy!")
alertcondition(Sell, title="SuperTrend Sell", message="SuperTrend Sell!")
buycontiue = barssince(Sell) > barssince(Buy)
sellcontinue = barssince(Buy) > barssince(Sell)
color = buycontiue[1] ? color.green : sellcontinue ? color.red : na
barcolor(color)
EDIT 2:
I may have found a partial answer to this.
Some of this behavior is because I was using the request.security() function here with barmerge.lookahead_on, which basically enabled "looking into the future" for calculations in historical bars. Setting this option to barmerge.lookahead_off helped some but there are still some discrepancies in the calculation.
EDIT 3:
There is an interesting writeup by TradingView about request.security() function here: https://www.tradingview.com/script/00jFIl5w-security-revisited-PineCoders/ ... so I guess we're out of luck when it comes to consistent historical data. My only "solution" for this was to introduce a threshold, so the custom SuperTrend implementation does not change trend until it was confirmed by going X percent into the opposite trend.