Pivot Breakouts With a Momentum Filter: Rules and Limits

Video: Your Trading Indicators Are Lying To You (Until You Add This)
Creator: TradeGenius
Original Video: Watch the original video
Difficulty: Intermediate

The Big Idea

TradeGenius combines a pivot-level breakout with a separate momentum histogram. A break upward is considered only when the histogram shows strong bullish momentum. A break downward requires strong bearish momentum. Conflicting or weak readings are skipped.

The filter is intended to reduce trades, not generate an additional entry on its own. A selected winner after several skipped signals demonstrates the process, but does not establish that filtering improves net performance.

If You Remember Only One Thing

A momentum filter is useful only if its avoided losses exceed the missed opportunities and execution costs it creates.

60-Second Summary

  • Use pivot levels only after their confirmation time.
  • Read histogram direction and strength together.
  • Weak white bars may still carry a bullish or bearish direction.
  • Verify the exact custom indicator and its input labels.
  • Compare filtered and unfiltered signals on the same original sample.

What the Pivot Lines Represent

The first indicator draws horizontal references from prior pivot highs and lows. The transcript identifies it as “Pivot High Low Line” by a creator transcribed as Dizer. Confirm the author and study in TradingView before assuming a similarly named indicator is equivalent.

A pivot high is a local turning point; a pivot low is its opposite. Many pivot formulas require bars on both sides. Such a pivot is confirmed later than the candle where its marker appears. A line drawn back to that candle can make historical breakouts look easier to trade than they actually were.

Read the Histogram Before Acting

BreakoutHistogram state describedSource decision
Above a pivot highStrong green bullish stateConsider a long
Below a pivot lowStrong red bearish stateConsider a short
Either directionWeak white state or opposing directionSkip

White should not automatically be read as neutral. In the walkthrough, white bars can represent weak bullish momentum, which still conflicts with a bearish breakout. Read the study’s direction and strength together.

Settings Are Part of the Experiment

The second study is named in the transcript as “EMA Difference Histogram and Stochastic.” Settings are EMA 1 at 200, EMA 2 at 300, stochastic length 14, and the two smoothing values transcribed as percent/K at 6 and D at 3. Verify the exact input labels in the original indicator.

The transcript does not supply the histogram’s full formula, state thresholds, or author details. These numbers alone are insufficient to recreate it faithfully. Replacing it with an ordinary EMA difference would be an original proxy, not the same filter.

Define Execution and Protection

The source places short protection at a swing high and long protection below a relevant low, with a target twice planned risk. Decide whether the breakout needs a completed close or whether an intrabar crossing qualifies. Then ensure the histogram state is evaluated at the same decision time.

For a hypothetical long at 50 with a stop at 49, a 2R target is 52 before costs. A fill at 50.50 with the original stop and target produces only 1R. Planned reward changes when actual execution differs from the signal price.

A Filter Can Help and Still Miss Winners

The video notes that a skipped breakout can later move in the intended direction. That is normal for a selective rule. Evaluate whether avoided losses outweigh missed profits and any cost from later entries.

Compare the unfiltered and filtered versions across the same complete date range. Record every eligible breakout, the momentum state available at that moment, the actual fill assumptions, and the net result. A reduction in losing trades does not automatically imply higher total return or lower drawdown.

Check the Historical Display

Confirm when pivot levels became available and whether histogram colors change before the bar closes. Use replay and forward observation to compare the live sequence with the finished chart. TradingView’s repainting documentation (paid link) explains why confirmation timing matters.

The indicator below supplies explicit original pivot and momentum definitions for a transparent approximation. It should be evaluated separately from the source’s custom indicator combination.

Work Through a Filter Decision

In an original hypothetical example, price closes below a confirmed pivot low at 100. The histogram is white but remains on its bullish side. Under the source’s rule, the short is skipped. The filter has done its job even if price later falls; its job is to apply the declared selection rule, not predict every outcome.

Later, another confirmed low breaks while the histogram shows its strong bearish state. That is a new eligible short. It still requires a valid stop, an executable entry, and enough target distance. A matching histogram cannot rescue a trade whose reward is already consumed by the move.

Research Lab: Test the Filter’s Incremental Value

Save every breakout from one frozen pivot configuration over a contiguous date range. On each signal, record the histogram state that was available at the decision time. Treat the unfiltered breakout model as the baseline and the source’s strong-state-only rule as the comparison.

Keep entry timing, swing-stop selection, target calculation, instrument, timeframe, and costs identical. The filter should be the only change. Mark skipped trades so that their hypothetical baseline outcome remains visible, without pretending those trades were actually executed by the filtered model.

For example, imagine 20 baseline opportunities produce 4R net. A filter selects eight and produces 3R net. The selected trades average 0.375R versus the baseline’s 0.2R per trade, yet total contribution per eligible opportunity is lower: 0.15R versus 0.2R. Neither statistic alone decides the issue; drawdown, exposure, and capacity also matter. These are fictional figures showing the selection effect.

Three Comparisons Worth Making

ComparisonChangeQuestion
Strength requirementDirection agreement versus strong direction agreementDoes requiring strength add value beyond direction?
Decision timingCompleted-close breakout versus a separately recorded live crossingWhat delay and false-signal tradeoff does confirmation introduce?
Pivot confirmationTwo predeclared left/right-bar settingsDoes performance survive a modest change in level sensitivity?

The second comparison needs suitable live or intrabar records; a finished candle’s final histogram color is not evidence of its earlier state. The third must keep each level unavailable until its required right-hand bars have completed. Use later data to evaluate any setting selected during development.

Check the Meaning of “Momentum”

The histogram is a calculation from its inputs. It is not a direct count of buyers and sellers or proof that one side was absent. A failed sell with weak bullish readings can have many causes. The test asks whether the calculated state is useful for selecting trades, not whether the indicator can identify every participant’s intentions.

Before recording results, explain in your own words when a pivot becomes known, what white means in this particular study, why a matching filter is still not an entry price, how a skipped winner affects the comparison, and which later data will be reserved for evaluation.

Pine Script Indicator: Confirmed Pivots and Momentum

Show Pine Script v6 – Pivot Breakout Momentum Indicator

//@version=6
// https://candlechasers.com/pivot-breakout-momentum-filter/
// Original CandleChasers approximation, not the custom studies' source code.
// The histogram is in its own pane; pivots and signals are on the price chart.
indicator("CandleChasers - Pivot Breakout Momentum", overlay=false, max_lines_count=200)
left = input.int(3, "Pivot left bars", minval=1, maxval=30)
right = input.int(3, "Pivot confirmation bars", minval=1, maxval=30)
fastLen = input.int(200, "EMA 1", minval=1, maxval=1000)
slowLen = input.int(300, "EMA 2", minval=2, maxval=1500)
stochLen = input.int(14, "Stochastic length", minval=2, maxval=100)
smoothK = input.int(6, "K smoothing", minval=1, maxval=50)
smoothD = input.int(3, "D smoothing", minval=1, maxval=50)
bullThreshold = input.float(50.0, "Bullish K threshold; bearish = 100 minus this",
 minval=50.0, maxval=95.0, step=5.0)
keep = input.int(80, "Maximum retained pivot lines", minval=10, maxval=180)
showSkipped = input.bool(true, "Show skipped breakouts")
showEMAs = input.bool(false, "Show EMAs on price chart")
if not chart.is_standard
    runtime.error("Use standard price candles.")
if fastLen >= slowLen
    runtime.error("EMA 1 must be shorter than EMA 2.")
float fast = ta.ema(close, fastLen)
float slow = ta.ema(close, slowLen)
float difference = fast - slow
float histogram = slow != 0 ? 100.0 * difference / math.abs(slow) : na
float rawK = ta.stoch(close, high, low, stochLen)
float k = ta.sma(rawK, smoothK)
float d = ta.sma(k, smoothD)
int warmup = slowLen + stochLen + smoothK + smoothD
bool ready = bar_index + 1 >= warmup and not na(k) and not na(d) and not na(histogram)
// These strength rules are original experimental definitions.
bool strongBull = ready and difference > 0 and k > d and k >= bullThreshold
bool strongBear = ready and difference < 0 and k < d and k <= 100.0 - bullThreshold
color shade = not ready ? color.gray :
 strongBull ? color.lime : strongBear ? color.red : color.white
plot(barstate.isconfirmed ? histogram : histogram[1],
 "EMA spread (% of EMA 2)", color=barstate.isconfirmed ? shade : shade[1],
 style=plot.style_histogram, linewidth=3)
hline(0, "Zero", color=color.gray, linestyle=hline.style_dashed)
plot(k, "Stochastic K (Data Window only)", display=display.data_window)
plot(d, "Stochastic D (Data Window only)", display=display.data_window)
plot(showEMAs ? fast : na, "EMA 1", color=color.aqua, force_overlay=true)
plot(showEMAs ? slow : na, "EMA 2", color=color.orange, force_overlay=true)
float ph = ta.pivothigh(high, left, right)
float pl = ta.pivotlow(low, left, right)
var array<line> lines = array.new<line>()
var array<float> levels = array.new<float>()
var array<int> types = array.new<int>()
var array<bool> active = array.new<bool>()
var int upwardBreaks = 0
var int downwardBreaks = 0
var int acceptedLongBars = 0
var int acceptedShortBars = 0
var string momentum = "Warming up"
bool longSignal = false
bool shortSignal = false
bool skippedUp = false
bool skippedDown = false
if barstate.isconfirmed
    momentum := not ready ? "Warming up / waiting for valid Stochastic" :
     strongBull ? "Strong bullish" : strongBear ? "Strong bearish" :
     difference > 0 ? "Weak bullish" : difference < 0 ? "Weak bearish" : "Neutral"
    int n = array.size(lines)
    // Process only levels that existed before this candle's close.
    if n > 0
        for i = 0 to n - 1
            if array.get(active, i)
                float level = array.get(levels, i)
                int kind = array.get(types, i)
                bool upBreak = kind == 1 and close > level and close[1] <= level
                bool downBreak = kind == -1 and close < level and close[1] >= level
                if upBreak or downBreak
                    line ln = array.get(lines, i)
                    line.set_extend(ln, extend.none)
                    line.set_x2(ln, bar_index)
                    line.set_style(ln, line.style_dotted)
                    array.set(active, i, false)
                    // Consume a level on its first close-break even if skipped.
                    if upBreak
                        upwardBreaks += 1
                        longSignal := longSignal or strongBull
                        skippedUp := skippedUp or (ready and not strongBull)
                    if downBreak
                        downwardBreaks += 1
                        shortSignal := shortSignal or strongBear
                        skippedDown := skippedDown or (ready and not strongBear)
    if longSignal
        acceptedLongBars += 1
    if shortSignal
        acceptedShortBars += 1
    // A new pivot starts at confirmation time, not at its earlier extreme.
    if not na(ph)
        line ln = line.new(x1=bar_index, y1=ph, x2=bar_index + 1, y2=ph,
         extend=extend.right, color=color.red, width=1, force_overlay=true)
        array.push(lines, ln)
        array.push(levels, ph)
        array.push(types, 1)
        array.push(active, true)
    if not na(pl)
        line ln = line.new(x1=bar_index, y1=pl, x2=bar_index + 1, y2=pl,
         extend=extend.right, color=color.lime, width=1, force_overlay=true)
        array.push(lines, ln)
        array.push(levels, pl)
        array.push(types, -1)
        array.push(active, true)
    while array.size(lines) > keep
        line.delete(array.shift(lines))
        array.shift(levels)
        array.shift(types)
        array.shift(active)
plotshape(longSignal, title="Filtered bullish breakout", text="BUY",
 style=shape.triangleup, location=location.belowbar, color=color.lime,
 textcolor=color.lime, size=size.small, force_overlay=true)
plotshape(shortSignal, title="Filtered bearish breakout", text="SELL",
 style=shape.triangledown, location=location.abovebar, color=color.red,
 textcolor=color.red, size=size.small, force_overlay=true)
plotshape(showSkipped and skippedUp, title="Skipped bullish breakout",
 style=shape.xcross, location=location.belowbar, color=color.gray,
 size=size.tiny, force_overlay=true)
plotshape(showSkipped and skippedDown, title="Skipped bearish breakout",
 style=shape.xcross, location=location.abovebar, color=color.gray,
 size=size.tiny, force_overlay=true)
alertcondition(longSignal, "Filtered bullish pivot breakout",
 "Confirmed pivot high broken with the CandleChasers bullish momentum filter.")
alertcondition(shortSignal, "Filtered bearish pivot breakout",
 "Confirmed pivot low broken with the CandleChasers bearish momentum filter.")
var table info = table.new(position.top_right, 1, 3, border_width=1)
if barstate.islast
    table.cell(info, 0, 0, "Confirmed momentum: " + momentum,
     text_color=color.white, bgcolor=color.rgb(25, 35, 50))
    table.cell(info, 0, 1, "Warmup minimum: " + str.tostring(warmup) +
     " bars | retained pivots: " + str.tostring(array.size(lines)),
     text_color=color.white, bgcolor=color.rgb(25, 35, 50))
    table.cell(info, 0, 2, "Level breaks up/down: " + str.tostring(upwardBreaks) +
     "/" + str.tostring(downwardBreaks) + " | accepted signal bars: " +
     str.tostring(acceptedLongBars) + "/" + str.tostring(acceptedShortBars),
     text_color=color.white, bgcolor=color.rgb(25, 35, 50))

The complete Pine Script v6 indicator below combines confirmed pivot levels with an original EMA/Stochastic momentum filter. It uses the source’s reported EMA lengths of 200 and 300 and Stochastic settings of 14, 6, and 3. Its pivot configuration and exact strength-color rules are our explicit approximation, not a claim to reproduce the two custom studies exactly.

What This Code Actually Shows

The lower pane displays the percentage spread between EMA 1 and EMA 2: 100 × (EMA 1 − EMA 2) / absolute EMA 2. Normalizing the spread makes its scale easier to read across different price levels; it does not create a probability or a universal momentum threshold.

The Stochastic begins with its conventional close-within-recent-high/low-range calculation, smooths K over six bars, and smooths D over three. Our color rules require both components to agree:

StateExact rule in this indicator
Strong bullish, greenEMA 1 above EMA 2, K above D, and K at or above the bullish threshold
Strong bearish, redEMA 1 below EMA 2, K below D, and K at or below 100 minus that threshold
Weak, whiteValid warmed-up readings that do not satisfy either strong rule; histogram sign still shows EMA-spread direction
Warming up, grayInsufficient loaded bars or unavailable Stochastic values

The threshold defaults to 50 for each direction. Setting the bullish threshold to 60 makes the bearish threshold 40. These are adjustable research definitions. A green bar means the stated calculations agree, not that buyers have been directly identified or a trade is guaranteed to win.

Pivot Lines Without Backdated Decisions

A pivot high or low requires the selected left and right bars, defaulting to three each. The line begins on the confirmation bar, three bars after the candidate extreme with default settings. It is not drawn back onto the earlier pivot candle. Breakouts are checked against lines that already existed before the confirming breakout close.

A close crossing above an active high level creates a bullish candidate; a close crossing below an active low creates a bearish candidate. A wick alone or a close exactly at the level does not qualify. The first qualifying close-break consumes that line whether the filter accepts or skips it. The line then stops extending and becomes dotted. A skipped breakout does not become a late entry simply because momentum changes several bars later.

The script keeps up to 80 pivot lines by default, including broken lines. When this limit is exceeded, the oldest line is removed, even if it remains unbroken. This bounds chart objects but also limits how many older levels remain eligible. Change the limit deliberately when comparing samples. Multiple levels broken on one bar produce one directional marker; the table distinguishes level-break counts from accepted signal-bar counts.

Add It to TradingView

  1. Use standard price candles, paste the entire code into Pine Editor, save, and add it to the chart.
  2. Load comfortably more than 323 bars with the default settings. The script’s minimum warmup is EMA 2 length plus Stochastic length and both smoothing lengths; EMA initialization can still affect early values.
  3. Look for the histogram and status table in the lower pane. Pivot lines and BUY/SELL markers are drawn on the main price chart using Pine’s overlay controls.
  4. Enable “Show skipped breakouts” to inspect gray crosses. Enable the EMA display if you want those averages visible on the main chart.
  5. Create an alert for the desired filtered breakout and use Once Per Bar Close. Recreate alerts after changing code or inputs because existing alerts retain their original configuration.

If no lines appear, allow enough bars for a confirmed pivot or try a smaller pivot setting as a deliberate sensitivity check. If lines appear but no BUY/SELL markers do, inspect the warmup message, whether price actually closed across a retained active level, and whether the histogram was strong in that direction. A quiet sample can legitimately have no qualifying signals.

What This Code Does Not Test

This is an indicator, not a strategy. It places no orders, does not draw a guaranteed fill price, and produces no Strategy Tester trades. BUY and SELL identify filtered chart events rather than personalized instructions. The script does not implement the source’s swing stop, 2R target, position sizing, spread, commissions, or a performance estimate.

It also does not reconstruct the custom studies’ undisclosed formulas. A similarly named histogram may classify strength differently, and different pivot settings can materially change the signal population. Use this transparent combination as a separately defined study.

Confirmation and Validation

New levels, marker decisions, and alert conditions are committed only on completed bars. The open candle displays the previous confirmed histogram reading and color. The code makes no higher-timeframe requests and does not backdate pivot availability. Previously confirmed signals are not removed because later prices invalidate the trade idea. Data-feed revisions or a change in loaded history and inputs can still change calculations.

Offline checks covered bullish, bearish, weak, equal-K/D, and warmup states; crossing versus equality; skipped-level consumption; and confirmation delay. The code has not been compiled or run in TradingView here. Inspect replay examples and the displayed levels on your intended market before relying on notifications. TradingView’s visuals documentation (paid link) explains how a lower-pane script can draw selected elements on the main chart.

For follow-up study, change the pivot left/right settings, the K threshold, or the EMA lengths one component at a time. Keep the comparison interval and remaining rules constant, and record skipped signals as well as accepted ones. A stricter filter should be judged by the complete opportunity set rather than only the best remaining examples.

Final Takeaway

Require price direction and momentum state to agree, but test the filter as a complete rule. The line break supplies a candidate; confirmed data, risk, and execution determine whether it is a trade.

Risk Disclosure

This article is for educational purposes only and is not financial advice or a recommendation to buy or sell any security. Trading involves substantial risk, including loss of capital. Leverage can magnify losses, and stop orders do not guarantee an execution price. Examples and historical results do not predict future performance. Account for fees, spread, slippage, and your own financial circumstances before trading.

CandleChasers is independent of the video creator. This article provides educational analysis of the source material; it does not verify the creator’s earnings or endorse paid products.

As an Amazon Associate I earn from qualifying purchases.