Strategy · Pine Script v5 · On the chart

SCDTM Strategy

by GreyssonEnterprises

A strategy built on a multi-step checklist.

View on GitHub

Repaints

GitHub stars1on the repository
Pine versionv5runs as is
Lines of code408
Settings17inputs
LicenceMIT
Last update2 months ago1 Aug 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

408 lines of Pine Script v5 from strategies/scdtm/pinescript/strategy.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.

strategy.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// SCDTM (Stone Cold DA MAN) Strategy - Production Implementation
// Original concept: Brian Beamish (TRI)
// Pine Script implementation: Daveatt & JoshuaMcGowan
// Updated and optimized version

//@version=5
strategy(title="SCDTM Strategy", shorttitle="SCDTM", overlay=true, 
         pyramiding=0, default_qty_value=100, precision=7, currency=currency.USD,
         commission_value=0.2, commission_type=strategy.commission.percent, 
         initial_capital=10000, max_bars_back=5000)

// Input Parameters
src = input.source(close, title="Strategy Source")
n = input.int(title="Fractal Periods", defval=2, minval=2)
fractalBars = input.string(title="Fractal Type", defval="5", options=["3", "5"])

// Risk Management Inputs
rr = input.float(defval=2.25, minval=1.0, title="Risk to Reward Ratio")
USDRiskPerTrade = input.int(defval=50, title="USD Risk Per Trade", minval=1)
usePercentRisk = input.bool(defval=false, title="Use Percent Risk Instead")
percentRisk = input.float(defval=1.0, minval=0.1, maxval=10.0, title="Risk Percent of Capital")

// Bollinger Band %B Inputs
length_bbr = input.int(20, minval=1, title="BB% Length")
mult_bbr = input.float(2.0, minval=0.001, maxval=50, title="BB% Std Dev")
upper_thresh = input.float(1.00, minval=0.001, maxval=2, title="BB% Upper Threshold")
lower_thresh = input.float(0.00, minval=0.001, maxval=2, title="BB% Lower Threshold")

// Stochastic RSI Inputs
smoothK = input.int(3, minval=1, title="Stoch RSI %K Smooth")
smoothD = input.int(3, minval=1, title="Stoch RSI %D Smooth")
lengthRSI = input.int(14, minval=1, title="RSI Length")
lengthStoch = input.int(14, minval=1, title="Stochastic Length")

// Backtesting Period
startDate = input.time(title="Start Date", defval=timestamp("01 Jan 2020 00:00"))
endDate = input.time(title="End Date", defval=timestamp("31 Dec 2025 23:59"))
inDateRange = time >= startDate and time <= endDate

//==============================================================================
// STATE MANAGEMENT
//==============================================================================

// Global state variables
var int tradeState = 0  // 0=No trade, 1=Setup pending, 2=Long active, 3=Short active
var int cp1 = 0, var int cp2 = 0, var int cp3 = 0, var int cp4 = 0, var int cp5 = 0

// Trade level tracking
var float bull_breakout_price = na, var float bull_fractal_sl = na
var float bear_breakout_price = na, var float bear_fractal_sl = na
var float fractal_dist = na, var float fractal_tgt = na
var float entry_price = na

// Position sizing
var float positionSize = na
var float riskAmount = na

//==============================================================================
// CHECKPOINT 1: Multi-Timeframe EMA Alignment
//==============================================================================

// EMA Calculations
ema9 = ta.ema(src, 9)
ema18 = ta.ema(src, 18)

// Multi-timeframe EMA analysis
ema9_D = request.security(syminfo.tickerid, 'D', ema9, lookahead=barmerge.lookahead_on)
ema18_D = request.security(syminfo.tickerid, 'D', ema18, lookahead=barmerge.lookahead_on)

ema9_H4 = request.security(syminfo.tickerid, '240', ema9, lookahead=barmerge.lookahead_on)
ema18_H4 = request.security(syminfo.tickerid, '240', ema18, lookahead=barmerge.lookahead_on)

ema9_H1 = request.security(syminfo.tickerid, '60', ema9, lookahead=barmerge.lookahead_on)
ema18_H1 = request.security(syminfo.tickerid, '60', ema18, lookahead=barmerge.lookahead_on)

// Individual timeframe bias
bull_ema_daily = ema9_D >= ema18_D ? 1 : 0
bear_ema_daily = ema9_D < ema18_D ? 1 : 0

bull_ema_H4 = ema9_H4 >= ema18_H4 ? 1 : 0
bear_ema_H4 = ema9_H4 < ema18_H4 ? 1 : 0

bull_ema_H1 = ema9_H1 >= ema18_H1 ? 1 : 0
bear_ema_H1 = ema9_H1 < ema18_H1 ? 1 : 0

// Consolidated EMA alignment
bull_ema_index = bull_ema_daily + bull_ema_H4 + bull_ema_H1
bear_ema_index = bear_ema_daily + bear_ema_H4 + bear_ema_H1

// Checkpoint 1 validation
if (bull_ema_index == 3) or (bear_ema_index == 3)
    cp1 := 1
else
    cp1 := 0

//==============================================================================
// CHECKPOINT 2: Bollinger Band %B and Stochastic RSI
//==============================================================================

// Bollinger Band %B calculation
basis_bbr = ta.sma(src, length_bbr)
dev_bbr = mult_bbr * ta.stdev(src, length_bbr)
upper_bbr = basis_bbr + dev_bbr
lower_bbr = basis_bbr - dev_bbr
bbr = (src - lower_bbr) / (upper_bbr - lower_bbr)

// %B signal tracking with persistence
var long_bbr = 0
var short_bbr = 0

if bbr <= lower_thresh
    long_bbr := 1
if bbr >= 0.55 and long_bbr == 1
    long_bbr := 0

if bbr >= upper_thresh
    short_bbr := 1
if bbr <= 0.45 and short_bbr == 1
    short_bbr := 0

// Stochastic RSI calculation
rsi1 = ta.rsi(src, lengthRSI)
k = ta.sma(ta.stoch(rsi1, rsi1, rsi1, lengthStoch), smoothK)
d = ta.sma(k, smoothD)

// Stochastic RSI signals
var long_rsi = 0
var short_rsi = 0

if k >= d
    long_rsi := 1
else
    long_rsi := 0

if d >= k
    short_rsi := 1
else
    short_rsi := 0

// Checkpoint 2 validation
if ((bear_ema_index == 3) and (short_bbr == 1) and (short_rsi == 1)) or 
   ((bull_ema_index == 3) and (long_bbr == 1) and (long_rsi == 1))
    cp2 := 1
else
    cp2 := 0

//==============================================================================
// CHECKPOINT 3: Fractal Pattern Recognition
//==============================================================================

// Fractal detection logic
dnFractal = fractalBars == "5" ? 
    (high[n-2] < high[n] and high[n-1] < high[n] and high[n+1] < high[n] and high[n+2] < high[n]) :
    fractalBars == "3" ? 
    (high[n-1] < high[n] and high[n+1] < high[n]) : false

upFractal = fractalBars == "5" ? 
    (low[n-2] > low[n] and low[n-1] > low[n] and low[n+1] > low[n] and low[n+2] > low[n]) :
    fractalBars == "3" ? 
    (low[n-1] > low[n] and low[n+1] > low[n]) : false

// Valid fractal conditions
bull_fractal_valid = upFractal and (bull_ema_index == 3) and (tradeState == 0)
bear_fractal_valid = dnFractal and (bear_ema_index == 3) and (tradeState == 0)

// Checkpoint 3 validation
if (cp2 == 1) and (bull_fractal_valid or bear_fractal_valid)
    cp3 := 1
    cp4 := 1  // Set persistent signal for breakout detection
else
    cp3 := 0

//==============================================================================
// CHECKPOINT 4: Breakout Level Calculation
//==============================================================================

// Calculate risk amount
currentRiskAmount = usePercentRisk ? (strategy.equity * percentRisk / 100) : USDRiskPerTrade

// Bull fractal setup levels
if ta.change(cp4) and cp4 == 1 and bull_ema_index == 3
    bull_fractal_sl := ta.valuewhen(upFractal, low[2], 0) - syminfo.mintick
    bull_breakout_price := ta.valuewhen(upFractal, high, 0) + syminfo.mintick
    
    fractal_dist := bull_breakout_price - bull_fractal_sl
    fractal_tgt := bull_breakout_price + (fractal_dist * rr)
    entry_price := bull_breakout_price
    
    tradeState := 1  // Setup pending breakout
    riskAmount := currentRiskAmount
    positionSize := riskAmount / fractal_dist

// Bear fractal setup levels
if ta.change(cp4) and cp4 == 1 and bear_ema_index == 3
    bear_fractal_sl := ta.valuewhen(dnFractal, high[2], 0) + syminfo.mintick
    bear_breakout_price := ta.valuewhen(dnFractal, low, 0) - syminfo.mintick
    
    fractal_dist := bear_fractal_sl - bear_breakout_price
    fractal_tgt := bear_breakout_price - (fractal_dist * rr)
    entry_price := bear_breakout_price
    
    tradeState := 1  // Setup pending breakout
    riskAmount := currentRiskAmount
    positionSize := riskAmount / fractal_dist

//==============================================================================
// SETUP INVALIDATION
//==============================================================================

// Reset function
resetSetup() =>
    bull_fractal_sl := na
    bear_fractal_sl := na
    bull_breakout_price := na
    bear_breakout_price := na
    fractal_dist := na
    fractal_tgt := na
    entry_price := na
    cp2 := 0
    cp3 := 0
    cp4 := 0
    cp5 := 0
    tradeState := 0

// Bull setup invalidation
if (low < bull_fractal_sl) and (tradeState == 1) and not na(bull_fractal_sl)
    resetSetup()

// Bear setup invalidation  
if (high > bear_fractal_sl) and (tradeState == 1) and not na(bear_fractal_sl)
    resetSetup()

//==============================================================================
// CHECKPOINT 5: Breakout Confirmation and Entry
//==============================================================================

// Bull breakout confirmation
if cp4 == 1 and (high >= bull_breakout_price) and (bull_ema_index >= 2) and (tradeState == 1) and inDateRange
    strategy.entry("Long", strategy.long, qty=positionSize, stop=bull_breakout_price)
    tradeState := 2
    cp5 := 1

// Bear breakout confirmation
if cp4 == 1 and (low <= bear_breakout_price) and (bear_ema_index >= 2) and (tradeState == 1) and inDateRange
    strategy.entry("Short", strategy.short, qty=positionSize, stop=bear_breakout_price)
    tradeState := 3
    cp5 := 1

//==============================================================================
// TRADE MANAGEMENT
//==============================================================================

// Exit conditions for long trades
if tradeState == 2
    strategy.exit("Exit Long", "Long", stop=bull_fractal_sl, limit=fractal_tgt)
    
    // Check if trade was closed
    if strategy.position_size == 0 and strategy.position_size[1] > 0
        resetSetup()

// Exit conditions for short trades
if tradeState == 3
    strategy.exit("Exit Short", "Short", stop=bear_fractal_sl, limit=fractal_tgt)
    
    // Check if trade was closed
    if strategy.position_size == 0 and strategy.position_size[1] < 0
        resetSetup()

//==============================================================================
// VISUAL COMPONENTS
//==============================================================================

// Fractal plots
plotshape(bear_ema_index == 3 and cp2 and dnFractal, "Down Fractal", 
          style=shape.triangledown, location=location.abovebar, 
          size=size.tiny, offset=-2, color=color.red)

plotshape(bull_ema_index == 3 and cp2 and upFractal, "Up Fractal", 
          style=shape.triangleup, location=location.belowbar, 
          size=size.tiny, offset=-2, color=color.green)

// Entry signals
plotshape(ta.change(cp5) and cp5 == 1 and bull_ema_index >= 2, title="Long Entry", 
          color=color.green, textcolor=color.white, style=shape.triangleup, 
          location=location.belowbar, size=size.normal, text="LONG")

plotshape(ta.change(cp5) and cp5 == 1 and bear_ema_index >= 2, title="Short Entry", 
          color=color.red, textcolor=color.white, style=shape.triangledown, 
          location=location.abovebar, size=size.normal, text="SHORT")

// Level plots
plot(bull_fractal_sl, "Bull Stop Loss", color=color.red, linewidth=2, style=plot.style_circles)
plot(bear_fractal_sl, "Bear Stop Loss", color=color.red, linewidth=2, style=plot.style_circles)
plot(bull_breakout_price, "Bull Breakout", color=color.yellow, linewidth=2, style=plot.style_circles)
plot(bear_breakout_price, "Bear Breakout", color=color.yellow, linewidth=2, style=plot.style_circles)
plot(fractal_tgt, "Target", color=color.green, linewidth=2, style=plot.style_circles)

// Trend background
bgcolor(bull_ema_index == 3 ? color.new(color.green, 95) : 
        bear_ema_index == 3 ? color.new(color.red, 95) : na)

//==============================================================================
// PERFORMANCE METRICS
//==============================================================================

// Calculate performance metrics
var int totalTrades = 0
var int winningTrades = 0
var float totalProfit = 0.0
var float totalLoss = 0.0

if strategy.closedtrades > strategy.closedtrades[1]
    totalTrades := strategy.closedtrades
    if strategy.closedtrades.profit(strategy.closedtrades - 1) > 0
        winningTrades := winningTrades + 1
        totalProfit := totalProfit + strategy.closedtrades.profit(strategy.closedtrades - 1)
    else
        totalLoss := totalLoss + math.abs(strategy.closedtrades.profit(strategy.closedtrades - 1))

winRate = totalTrades > 0 ? (winningTrades / totalTrades) * 100 : 0
profitFactor = totalLoss > 0 ? totalProfit / totalLoss : 0
avgWin = winningTrades > 0 ? totalProfit / winningTrades : 0
avgLoss = (totalTrades - winningTrades) > 0 ? totalLoss / (totalTrades - winningTrades) : 0

//==============================================================================
// INFORMATION PANEL
//==============================================================================

var table infoTable = table.new(position.top_right, 2, 12, bgcolor=color.white, border_width=1)

if barstate.islast
    table.cell(infoTable, 0, 0, "SCDTM Strategy", text_color=color.black, text_size=size.normal, bgcolor=color.gray)
    table.cell(infoTable, 1, 0, "Status", text_color=color.black, text_size=size.normal, bgcolor=color.gray)
    
    table.cell(infoTable, 0, 1, "EMA Alignment", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 1, cp1 ? "✓" : "✗", 
              text_color=cp1 ? color.green : color.red, text_size=size.small)
    
    table.cell(infoTable, 0, 2, "%B + Stoch RSI", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 2, cp2 ? "✓" : "✗", 
              text_color=cp2 ? color.green : color.red, text_size=size.small)
    
    table.cell(infoTable, 0, 3, "Fractal Pattern", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 3, cp3 ? "✓" : "✗", 
              text_color=cp3 ? color.green : color.red, text_size=size.small)
    
    table.cell(infoTable, 0, 4, "Trade State", text_color=color.black, text_size=size.small)
    stateText = tradeState == 0 ? "No Trade" : 
                tradeState == 1 ? "Setup" : 
                tradeState == 2 ? "Long" : "Short"
    table.cell(infoTable, 1, 4, stateText, text_color=color.black, text_size=size.small)
    
    table.cell(infoTable, 0, 5, "Risk Amount", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 5, "$" + str.tostring(math.round(riskAmount, 2)), 
              text_color=color.black, text_size=size.small)
    
    table.cell(infoTable, 0, 6, "Position Size", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 6, str.tostring(math.round(positionSize, 4)), 
              text_color=color.black, text_size=size.small)
    
    table.cell(infoTable, 0, 7, "Total Trades", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 7, str.tostring(totalTrades), text_color=color.black, text_size=size.small)
    
    table.cell(infoTable, 0, 8, "Win Rate", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 8, str.tostring(math.round(winRate, 1)) + "%", 
              text_color=color.black, text_size=size.small)
    
    table.cell(infoTable, 0, 9, "Profit Factor", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 9, str.tostring(math.round(profitFactor, 2)), 
              text_color=color.black, text_size=size.small)
    
    table.cell(infoTable, 0, 10, "Avg Win", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 10, "$" + str.tostring(math.round(avgWin, 2)), 
              text_color=color.green, text_size=size.small)
    
    table.cell(infoTable, 0, 11, "Avg Loss", text_color=color.black, text_size=size.small)
    table.cell(infoTable, 1, 11, "$" + str.tostring(math.round(avgLoss, 2)), 
              text_color=color.red, text_size=size.small)

//==============================================================================
// ALERTS FOR AUTOVIEW INTEGRATION
//==============================================================================

// Entry alerts with position sizing
longAlert = ta.change(cp5) and cp5 == 1 and bull_ema_index >= 2
shortAlert = ta.change(cp5) and cp5 == 1 and bear_ema_index >= 2

alertcondition(longAlert, title="SCDTM Long Entry", 
               message="LONG {{ticker}} sl={{bull_fractal_sl}} tp={{fractal_tgt}} risk={{riskAmount}}")

alertcondition(shortAlert, title="SCDTM Short Entry", 
               message="SHORT {{ticker}} sl={{bear_fractal_sl}} tp={{fractal_tgt}} risk={{riskAmount}}")

// Exit alerts
alertcondition(strategy.position_size == 0 and strategy.position_size[1] != 0, title="SCDTM Position Closed", 
               message="Position closed on {{ticker}} - P&L: {{strategy.netprofit}}")

//==============================================================================
// DEBUG PLOTS
//==============================================================================

plot(bull_ema_index, title="Bull EMA Index", display=display.data_window)
plot(bear_ema_index, title="Bear EMA Index", display=display.data_window)
plot(tradeState, title="Trade State", display=display.data_window)
plot(bbr, title="BB%", display=display.data_window)
plot(k, title="Stoch RSI %K", display=display.data_window)
plot(d, title="Stoch RSI %D", display=display.data_window)

Overview

SCDTM Strategy compares 9 and 18 EMA alignment across daily, 4-hour and 1-hour data, then combines Bollinger Band %B and Stochastic RSI conditions with fractal breakout levels. Stops sit at the fractal, take profit is set by a risk to reward ratio, and size comes from a fixed USD amount or a percent of capital. A date range limits testing. The higher-timeframe requests use lookahead, so backtests can look better than live results. It draws on the price chart.

Details

Published by

GreyssonEnterprises on GitHub

Type

Strategy, Pine Script v5

Draws

On the price chart

Category

Trend, Oscillators & momentum, Volatility & bands, Breakout

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

  • Reads higher-timeframe data with lookahead on, so the history can show signals that were not there in real time

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Strategy Sourcesourceclosesrc
Fractal Periodsint2n
Fractal Typestring5fractalBars
Risk to Reward Ratiofloat2.25rr
USD Risk Per Tradeint50USDRiskPerTrade
Use Percent Risk InsteadboolfalseusePercentRisk
Risk Percent of Capitalfloat1.0percentRisk
BB% Lengthint20length_bbr
BB% Std Devfloat2.0mult_bbr
BB% Upper Thresholdfloat1.00upper_thresh
BB% Lower Thresholdfloat0.00lower_thresh
Stoch RSI %K Smoothint3smoothK
Show all 17 settings
SettingTypeDefaultVariable
Stoch RSI %D Smoothint3smoothD
RSI Lengthint14lengthRSI
Stochastic Lengthint14lengthStoch
Start Datetimetimestamp("01 Jan 2020 00:00")startDate
End Datetimetimestamp("31 Dec 2025 23:59")endDate
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

16 stars

This strategy trades Donchian channel breakouts on the price chart and exits on a shorter Donchian channel. It sizes each unit from a percentage of equity and an ATR-based initial stop, then adds units as price moves a set ATR distance, up to a maximum unit co

Strategy v6 TrendBreakout
Updated 12 months ago · None stated GitHub repository of Seykota Alt 16: Anti-Chop Filters

GEO P Momentum Strategy

by newsfriend
2 stars

Implements a rule-based momentum trading strategy that detects Bollinger Band challenges followed by synchronized trendline or range breakouts on the price chart. Entries trigger under configurable strictness modes using multi-timeframe Tide and Wave alignment

Strategy v6 Oscillators & momentumVolatility & bands
Updated 8 weeks ago · None stated GitHub repository of GEO P Momentum Strategy

This strategy evaluates multi-factor breakout confluence using a customized scoring system on the price chart. It checks Minervini-style Volatility Contraction Pattern trend templates, TTM squeeze volatility compression, volume dry-up with OBV accumulation, mo

Strategy v6 BreakoutVolatility & bands
Updated 2 months ago · None stated GitHub repository of TnSovereign Breakout Confluence V6

Volume Breakout Strategy

by kanylbullen
1 stars

This strategy identifies breakouts using Keltner Channels combined with volume spike filters, ADX trend strength, RSI thresholds, and an optional EMA trend direction filter. It triggers long entries when price crosses above the upper channel and short entries

Strategy v5 BreakoutTrend Repaints
Updated 7 days ago · None stated GitHub repository of Volume Breakout Strategy

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers