Strategy · Pine Script v6 · On the chart

Hierarchical Trading System v6 Fakeout Protected

by rosijay17-cmd

A strategy that uses ADX to decide between two sub-strategies.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code210
Settings19inputs
LicenceGPL-3.0
Last update7 days ago22 Oct 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

210 lines of Pine Script v6 from Hierarchical_Trading_System_v6_Fakeout_Protected.pine, published under GPL-3.0. Keep the author's credit and licence lines when you reuse it.

Hierarchical_Trading_System_v6_Fakeout_Protected.pine
//@version=6
strategy("Hierarchical Trading System v6 (Fakeout Protected)", overlay=true, initial_capital=10000, default_qty_type=strategy.percent_of_equity, default_qty_value=10)

// ==========================================
// --- INPUTS ---
// ==========================================
// 1. Regime Classifier Inputs (Layer 1)
adxLength      = input.int(14, title="ADX Length", group="Layer 1: Regime Classifier")
adxThreshold   = input.int(25, title="ADX Threshold", group="Layer 1: Regime Classifier")
cooldownBars   = input.int(5, title="Cooldown Bars", minval=0, group="Execution Settings")

// 2. Mean Reversion Inputs (Layer 2 - Sub-Strategy A)
bbLength       = input.int(20, title="BB Length", group="Sub-Strategy A: Mean Reversion")
baseMult       = input.float(2.5, title="Base BB Multiplier", group="Sub-Strategy A: Mean Reversion")
asymOffset     = input.float(0.5, title="Asymmetric Offset", group="Sub-Strategy A: Mean Reversion")
emaLength      = input.int(200, title="Trend Filter EMA", group="Sub-Strategy A: Mean Reversion")

// 3. Trend Following Inputs (Layer 2 - Sub-Strategy B)
dcLength       = input.int(20, title="Donchian Breakout Length", group="Sub-Strategy B: Trend Following")
dcExitLength   = input.int(10, title="Donchian Exit Length", group="Sub-Strategy B: Trend Following")

// 4. Fakeout Filters (Sub-Strategy B Additions)
useVolumeFilter = input.bool(true, title="Enable Volume Confirmation?", group="Sub-Strategy B: Breakout Filters", tooltip="Breakout volume must exceed average volume")
volLength       = input.int(20, title="Volume Average Length", group="Sub-Strategy B: Breakout Filters")
volMultiplier   = input.float(1.5, title="Volume Multiplier (x SMA)", group="Sub-Strategy B: Breakout Filters")

useAtrFilter    = input.bool(true, title="Enable Range (ATR) Confirmation?", group="Sub-Strategy B: Breakout Filters", tooltip="Breakout candle range must exceed ATR")
atrLength       = input.int(14, title="ATR Length", group="Sub-Strategy B: Breakout Filters")
atrMultiplier   = input.float(1.0, title="Range Multiplier (x ATR)", group="Sub-Strategy B: Breakout Filters")

// --- NEW DEFENSIVE BREAKOUT FILTERS ---
useWickFilter   = input.bool(true, title="Enable Rejection Wick Filter?", group="Sub-Strategy B: Breakout Filters", tooltip="Breakout candle rejection wick cannot exceed threshold")
maxWickPct      = input.float(35.0, title="Max Rejection Wick %", group="Sub-Strategy B: Breakout Filters", tooltip="Max rejection wick size as a percentage of total candle range")

useAtrPenetration  = input.bool(true, title="Enable ATR Penetration Filter?", group="Sub-Strategy B: Breakout Filters", tooltip="Close must exceed breakout level by a minimum distance")
atrPenetrationMult = input.float(0.5, title="Min ATR Penetration Multiplier", group="Sub-Strategy B: Breakout Filters", tooltip="Multiplier of ATR to determine clearance over breakout level")

// ==========================================
// --- CALCULATIONS & REGIME CLASS ---
// ==========================================
// Layer 1: ADX Regime Calculation
[diPlus, diMinus, adxValue] = ta.dmi(adxLength, adxLength)
bool isTrending = adxValue >= adxThreshold
bool isRanging  = not isTrending

// Color background based on active regime: Teal for Trending, Orange for Ranging
bgcolor(isTrending ? color.new(color.teal, 98) : color.new(color.orange, 98), title="Regime Background Color")

// Sub-Strategy A: Asymmetric Bollinger Bands
basis     = ta.sma(close, bbLength)
stdDevVal = ta.stdev(close, bbLength)
trendEma  = ta.ema(close, emaLength)
bool isUptrend = close > trendEma

float longMult  = isUptrend ? (baseMult - asymOffset) : (baseMult + asymOffset)
float shortMult = isUptrend ? (baseMult + asymOffset) : (baseMult - asymOffset)

upperBB = basis + (shortMult * stdDevVal)
lowerBB = basis - (longMult * stdDevVal)

// Sub-Strategy B: Donchian Channels
dcUpper = ta.highest(high, dcLength)[1]
dcLower = ta.lowest(low, dcLength)[1]
dcExitUpper = ta.highest(high, dcExitLength)[1]
dcExitLower = ta.lowest(low, dcExitLength)[1]

// ==========================================
// --- FAKEOUT FILTER LOGIC ---
// ==========================================
// 1. Volume Confirmation
volMa = ta.sma(volume, volLength)
bool isVolumeConfirmed = not useVolumeFilter or (volume > (volMa * volMultiplier))

// 2. Range Expansion Confirmation
atrVal = ta.atr(atrLength)
candleRange = high - low
bool isRangeConfirmed = not useAtrFilter or (candleRange > (atrVal * atrMultiplier))

// 3. NEW: Rejection Wick Ratio Filter (Prevents entering on immediate rejections)
upperWick = high - math.max(open, close)
lowerWick = math.min(open, close) - low

bool longWickOK  = not useWickFilter or (candleRange > 0 ? (upperWick / candleRange) * 100 <= maxWickPct : true)
bool shortWickOK = not useWickFilter or (candleRange > 0 ? (lowerWick / candleRange) * 100 <= maxWickPct : true)

// 4. NEW: ATR Penetration Filter (Ensures the close cleanly clears the channel boundary)
bool longAtrPenetration  = not useAtrPenetration or ((close - dcUpper) >= (atrVal * atrPenetrationMult))
bool shortAtrPenetration = not useAtrPenetration or ((dcLower - close) >= (atrVal * atrPenetrationMult))

// Combined Directional Breakout Validation Pipelines
bool isLongBreakoutValid  = isVolumeConfirmed and isRangeConfirmed and longWickOK and longAtrPenetration
bool isShortBreakoutValid = isVolumeConfirmed and isRangeConfirmed and shortWickOK and shortAtrPenetration

// ==========================================
// --- SIGNALS & COOLDOWN ---
// ==========================================
var int lastSignalBar = -99999
bool isCooldownOver   = (bar_index - lastSignalBar) >= cooldownBars

// Raw signals
bool rawMrLong  = ta.crossover(close, lowerBB)
bool rawMrShort = ta.crossunder(close, upperBB)

bool rawTfLong  = ta.crossover(close, dcUpper)
bool rawTfShort = ta.crossunder(close, dcLower)

// Filtered signals based on current Regime State
bool mrLongCondition  = isRanging and rawMrLong and isCooldownOver
bool mrShortCondition = isRanging and rawMrShort and isCooldownOver

// Trend-Following Signals must pass the direction-specific Breakout Validation Filters
bool tfLongCondition  = isTrending and rawTfLong and isCooldownOver and isLongBreakoutValid
bool tfShortCondition = isTrending and rawTfShort and isCooldownOver and isShortBreakoutValid

// Update Cooldown Tracker on any executed signal
if mrLongCondition or mrShortCondition or tfLongCondition or tfShortCondition
    lastSignalBar := bar_index

// ==========================================
// --- ALERT MESSAGE BUILDERS ---
// ==========================================
// FIX: the original script had zero alertcondition()/alert()/alert_message
// calls anywhere -- that is why entries plotted on the chart but no alert
// ever fired. There was nothing wired to trigger one. Every message below
// identifies which of the four entry types (or which exit) fired, plus
// ticker/timeframe/price, so a single "Any alert() function call" alert
// created on this script tells you exactly what happened without opening
// the chart.
//
// STANDARD ALERT FORMAT (apply to every future script's alerts the same
// way): every message leads with an ALL-CAPS type tag stating the
// direction up front -- "BULLISH ENTRY" / "BEARISH ENTRY" for entries,
// "LONG EXIT" / "SHORT EXIT" for exits -- so the notification itself
// (phone lock screen, webhook payload, whatever reads it) says which way
// the signal is without needing to open the chart or parse a strategy-
// specific label. Everything after that tag is context: which
// sub-strategy/kind fired, then ticker, timeframe, and price.
f_alertMsg(string kind, string label, float px) =>
    kind + " | " + label + " | " + syminfo.ticker + " " + timeframe.period + " @ " + str.tostring(px, format.mintick)

// ==========================================
// --- EXECUTION ENGINE ---
// ==========================================
// 1. Mean Reversion Execution (MR)
if mrLongCondition
    string msg = f_alertMsg("BULLISH ENTRY", "MR (mean reversion)", close)
    strategy.entry("MR Long", strategy.long, comment="MR Buy", alert_message=msg)
    alert(msg, alert.freq_once_per_bar_close)

if mrShortCondition
    string msg = f_alertMsg("BEARISH ENTRY", "MR (mean reversion)", close)
    strategy.entry("MR Short", strategy.short, comment="MR Short", alert_message=msg)
    alert(msg, alert.freq_once_per_bar_close)

// 2. Trend Following Execution (TF)
if tfLongCondition
    string msg = f_alertMsg("BULLISH ENTRY", "TF (breakout)", close)
    strategy.entry("TF Long", strategy.long, comment="TF Breakout Buy", alert_message=msg)
    alert(msg, alert.freq_once_per_bar_close)

if tfShortCondition
    string msg = f_alertMsg("BEARISH ENTRY", "TF (breakout)", close)
    strategy.entry("TF Short", strategy.short, comment="TF Breakout Short", alert_message=msg)
    alert(msg, alert.freq_once_per_bar_close)

// ==========================================
// --- EXIT ENGINE ---
// ==========================================
// MR Exits (Reversion to Mean)
if isRanging
    if ta.crossover(close, basis) and (strategy.position_size < 0)
        string msg = f_alertMsg("SHORT EXIT", "MR cover (reverted to mean)", close)
        strategy.close("MR Short", comment="MR Short Cover", alert_message=msg)
        alert(msg, alert.freq_once_per_bar_close)
    if ta.crossunder(close, basis) and (strategy.position_size > 0)
        string msg = f_alertMsg("LONG EXIT", "MR sell (reverted to mean)", close)
        strategy.close("MR Long", comment="MR Long Sell", alert_message=msg)
        alert(msg, alert.freq_once_per_bar_close)

// TF Exits (Trailing Highs/Lows)
if isTrending
    if ta.crossunder(close, dcExitLower) and (strategy.position_size > 0)
        string msg = f_alertMsg("LONG EXIT", "TF trailing stop", close)
        strategy.close("TF Long", comment="TF Trail Exit", alert_message=msg)
        alert(msg, alert.freq_once_per_bar_close)
    if ta.crossover(close, dcExitUpper) and (strategy.position_size < 0)
        string msg = f_alertMsg("SHORT EXIT", "TF trailing stop", close)
        strategy.close("TF Short", comment="TF Trail Exit", alert_message=msg)
        alert(msg, alert.freq_once_per_bar_close)

// ==========================================
// --- VISUALIZATIONS & ALERTS ---
// ==========================================
plot(basis, color=color.new(color.blue, 50), title="BB Basis (Mean)")
plot(trendEma, color=color.orange, linewidth=2, title="Trend Filter EMA")

plotshape(mrLongCondition, title="MR Long Signal", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small, text="MR")
plotshape(mrShortCondition, title="MR Short Signal", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small, text="MR")

plotshape(tfLongCondition, title="TF Long Signal", style=shape.triangleup, location=location.belowbar, color=color.teal, size=size.small, text="TF Breakout")
plotshape(tfShortCondition, title="TF Short Signal", style=shape.triangledown, location=location.abovebar, color=color.maroon, size=size.small, text="TF Breakout")

// alertcondition() gives a second, independent way to pick an alert on
// this script from the "Condition" dropdown (rather than "Any alert()
// function call") -- pick whichever workflow you prefer in the Create
// Alert dialog; both are wired to fire on the same bars.
alertcondition(mrLongCondition, title="MR Long Entry", message="BULLISH ENTRY | MR (mean reversion) | {{ticker}} {{interval}} @ {{close}}")
alertcondition(mrShortCondition, title="MR Short Entry", message="BEARISH ENTRY | MR (mean reversion) | {{ticker}} {{interval}} @ {{close}}")
alertcondition(tfLongCondition, title="TF Long Entry", message="BULLISH ENTRY | TF (breakout) | {{ticker}} {{interval}} @ {{close}}")
alertcondition(tfShortCondition, title="TF Short Entry", message="BEARISH ENTRY | TF (breakout) | {{ticker}} {{interval}} @ {{close}}")

Overview

In ranging conditions it fades asymmetric Bollinger Band extremes with a 200 EMA trend filter. In trending conditions it trades Donchian channel breakouts, protected by optional volume, candle range, rejection wick and ATR penetration filters. Exits use a Donchian exit channel and a cooldown applies after trades. Background colour shows the regime, size is a percent of equity, and no stop loss is set.

Details

Published by

rosijay17-cmd on GitHub

Type

Strategy, Pine Script v6

Draws

On the price chart

Category

Mean reversion, Breakout, Trend

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

  • The strategy enters trades without a stop loss

Settings

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

SettingTypeDefaultVariable
ADX Lengthint14adxLength
ADX Thresholdint25adxThreshold
Cooldown Barsint5cooldownBars
BB Lengthint20bbLength
Base BB Multiplierfloat2.5baseMult
Asymmetric Offsetfloat0.5asymOffset
Trend Filter EMAint200emaLength
Donchian Breakout Lengthint20dcLength
Donchian Exit Lengthint10dcExitLength
Enable Volume Confirmation?booltrueuseVolumeFilter
Volume Average Lengthint20volLength
Volume Multiplier (x SMA)float1.5volMultiplier
Show all 19 settings
SettingTypeDefaultVariable
Enable Range (ATR) Confirmation?booltrueuseAtrFilter
ATR Lengthint14atrLength
Range Multiplier (x ATR)float1.0atrMultiplier
Enable Rejection Wick Filter?booltrueuseWickFilter
Max Rejection Wick %float35.0maxWickPct
Enable ATR Penetration Filter?booltrueuseAtrPenetration
Min ATR Penetration Multiplierfloat0.5atrPenetrationMult
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

Traiversal A001

by ruckard
13 stars

Traiversal A001 is a breakout reversal strategy designed primarily for cryptocurrency trading. It identifies reversal entry opportunities three candles following a breakout and closes positions when a breakout in the opposite direction occurs. The script inclu

Strategy v5 BreakoutMean reversion
Updated 1 year ago · None stated GitHub repository of Traiversal A001
3 stars

Sapphire Fibonacci Strategies is a multi-mode strategy that combines Momentum Breakout, Mean Reversion, and Fibonacci Retracement models built on Fibonacci-period moving averages. It generates long and short trade signals based on price crossovers and moving a

Strategy v5 TrendMoving averages
Updated 1 year ago · None stated GitHub repository of Sapphire Fibonacci Strategies
1 stars

This overlay strategy combines an AlphaTrend core with kinematic, Bayesian, and mean-reversion models, plus harmonic, classical, and candlestick pattern engines. It plots consolidation zones, volume-profile points of control, pattern lines, and forward forecas

Strategy v5 TrendCandlestick patterns Repaints
Updated yesterday · None stated GitHub repository of JAT+BSM Pro Extended

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