Skip to content

Instantly share code, notes, and snippets.

@davidsaccavino
Last active May 18, 2025 02:46
Show Gist options
  • Save davidsaccavino/e5414d7280e2b9c6d0cc7234cf4eb0a4 to your computer and use it in GitHub Desktop.
Save davidsaccavino/e5414d7280e2b9c6d0cc7234cf4eb0a4 to your computer and use it in GitHub Desktop.
//@version=5
// Author: David Saccavino
// Last Update: November 25th, 2022
// Saccavino Venture Capital, LLC - All Rights Reserved.
strategy("Stochastic/OBV-Weighted SuperTrend Strategy", overlay = true)
// backtesting boilerplate
startDate = timestamp("1950-01-01T00:00:00")
finishDate = timestamp("2023-01-01T00:00:00")
time_cond = time >= startDate and time <= finishDate
PL = strategy.opentrades.profit(strategy.opentrades - 1)
// *
// Start of: Initalize the Indicators
//
// Moving Average
smaWeightingToggle = input(false, "Enable short-term SMA weighting:")
shortSMALength = input(8, "Short SMA Length:")
shortSMA = ta.sma(close, shortSMALength)
// Average True Range
atrSrc = input(hl2, "ATR Source:")
atrMultiplier = input(3, "ATR Multiplier:")
atrPeriod = input(10, "ATR Period:")
atr = ta.sma(ta.tr, atrPeriod)
atrUp = atrSrc - (atrMultiplier * atr)
atrUpInit = nz(atrUp[1],atrUp)
atrUp := close[1] > atrUpInit ? math.max(atrUp,atrUpInit) : atrUp
atrDown = atrSrc + (atrMultiplier * atr)
atrDownInit = nz(atrDown[1], atrDown)
atrDown := close[1] < atrDownInit ? math.min(atrDown, atrDownInit) : atrDown
// SuperTrend
superTrend = 1
superTrend := nz(superTrend[1], superTrend)
superTrend := superTrend == -1 and close > atrDownInit ? 1 : superTrend == 1 and close < atrUpInit ? -1 : superTrend
// Stochastic
stochSrc = input(close, "Stochastic Source:")
stochLen = input(14, "Stochastic Length:")
stochK = ta.stoch(stochSrc, high, low, stochLen)
stochD = ta.rma(stochK, 3)
// MACD
macdSrc = input(close, "MACD Source:")
[macdLine, signalLine, histLine] = ta.macd(macdSrc, 12, 26, 9)
// On-Balance-Volume
smma = 0.0
obvSrc = input(close, "OBV Source:")
obvLen = input(8, "OBV Length:")
obv = ta.cum(math.sign(ta.change(obvSrc)) * volume)
obvMA = ta.sma(obv, obvLen)
smma := na(smma[1]) ? obvMA : (smma[1] * (obvLen - 1) + obv) / obvLen
//
// End of: Initalize the Indicators
// *
// *
// Start of: Logic gates for determining bullish or bearish sentiment
//
// OBV Bullish/Bearish logic gates
bullishOBV = ta.crossover(obv, smma) or obv > smma
bearishOBV = ta.crossunder(smma, obv) or obv < smma
// MACD Bullish/Bearish logic gates
bullishMACD = (ta.crossover(macdLine, signalLine) or (macdLine > signalLine + 0.25))
bearishMACD = (ta.crossunder(macdLine, signalLine) or (macdLine < signalLine))
// Stochastic Bullish/Bearish logic gates
bearishStochastic = (stochK < 60 and stochD > (stochK + 1.5)) or stochK < 40
bullishStochastic = stochK > 60 and stochK > (stochD + 1.5)
// Aggregated Oscillator Bullish/Bearish logic gates
bullishOscillators = bullishOBV and bullishStochastic and bullishMACD and close > shortSMA
bearishOscillators = bearishOBV and bearishStochastic and bearishMACD
// Volume-Oscillator-weighted SuperTrend buy and sell signals
VOSTbuySignal = superTrend == 1 and superTrend[1] == -1 and bullishOscillators and (close[2] > shortSMA or smaWeightingToggle == true)
VOSTsellSignal = superTrend == -1 and superTrend[1] == 1 and bearishOscillators and (close[1] < shortSMA or smaWeightingToggle == true)
// Determine if currently in a "De-Risk Zone"
deRisk = (not VOSTsellSignal) and PL > 50 and (stochK < 55 or ((ta.crossunder(close[1], shortSMA) and close < shortSMA) and smaWeightingToggle == true))
//
// End of: Logic gates for determining bullish or bearish sentiment
// *
// *
// Start of: Plot the Volume/Oscillator-weighted SuperTrend
//
plot(shortSMA, color = color.from_gradient((stochK + stochD) / 2, 0, 100, color.rgb(255, 0, 0), color.rgb(0, 200, 0)))
atrUpPlot = plot(superTrend == 1 ? atrUp : na, title="Up Trend", style=plot.style_linebr, linewidth=2, color=color.rgb(0, 255, 0, transp = 75))
atrDownPlot = plot(superTrend == -1 ? atrDown : na, title="Down Trend", style=plot.style_linebr, linewidth=2, color=color.rgb(255, 0, 0, transp = 75))
basePlot = plot(ohlc4, title="", style=plot.style_circles, linewidth=0)
plotshape(VOSTbuySignal ? atrUp : na, title="UpTrend Begins", location=location.absolute, style=shape.circle, size=size.tiny, color=color.rgb(0, 255, 0, transp = 75))
plotshape(VOSTbuySignal ? atrUp : na, title="Buy", text="Buy", location=location.absolute, style=shape.labelup, size=size.tiny, color=color.rgb(0, 255, 0, transp = 75), textcolor=color.white)
plotshape(VOSTsellSignal ? atrDown : na, title="DownTrend Begins", location=location.absolute, style=shape.circle, size=size.tiny, color=color.rgb(255, 0, 0, transp = 75))
plotshape(VOSTsellSignal ? atrDown : na, title="Sell", text="Sell", location=location.absolute, style=shape.labeldown, size=size.tiny, color=color.rgb(255, 0, 0, transp = 75), textcolor=color.white)
longFillColor = color.rgb(0, 255, 0, transp = 90)
shortFillColor = color.rgb(255, 0, 0, transp = 90)
fill(basePlot, atrUpPlot, title = "UpTrend Highligter", color = longFillColor)
fill(basePlot, atrDownPlot, title = "DownTrend Highligter", color = shortFillColor)
// Plot "De-Risk-Zones"
plotshape(deRisk ? atrDown : na, title="De-Risk Zone Notice", text="De-Risk Zone", location=location.absolute, style=shape.labeldown, size=size.tiny, color=color.rgb(255, 0, 0, transp = 75), textcolor=color.white)
//
// End of: Plot the Volume/Oscillator-weighted SuperTrend
// *
// Trading strategy logic gates for performance numbers in the Strategy Tester
if PL > 50 and stochK < 55
strategy.close("Entry")
if VOSTbuySignal == true and time_cond
strategy.entry("Entry", strategy.long, 50000)
if VOSTsellSignal == true and time_cond
strategy.close("Entry")
strategy.exit("Exit", "Entry", profit = 10000000, loss = 75000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment