Strategy · Pine Script v6 · On the chart

EMA Channel Reversal

by rubbermetal· code credited to claygrace74

EMA Channel Reversal is a strategy that plots a 200-period EMA channel built from highs, closes and lows, plus fast and slow momentum EMAs with an optional glow.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code261
Settings9inputs
LicenceMPL-2.0
Last update4 months ago10 Jun 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

261 lines of Pine Script v6 from EMA Channel Reversal.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

EMA Channel Reversal.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © claygrace74
// Technical spec: 5-EMA Reversal Strategy
// Visual spec: EMA Channel Reversal Design Document

//@version=6
strategy("EMA Channel Reversal", shorttitle="EMA Ch Rev", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=10, max_lines_count=500, max_boxes_count=500, max_labels_count=500)

// ==================================================================================
// PHASE 1: INPUTS & CONFIGURATION
// ==================================================================================
grp_ma    = "Moving Averages"
len_long  = input.int(200, "Long Term EMA Length", group=grp_ma)
len_fast  = input.int(5, "Fast Momentum EMA (White)", group=grp_ma)
len_slow  = input.int(8, "Slow Momentum EMA (Green)", group=grp_ma)

grp_strat = "Strategy Rules"
use_alt_entry = input.bool(false, "Use Alternative Entry (Price Action)", group=grp_strat)
rr_ratio      = input.float(2.0, "Risk/Reward Ratio", minval=0.5, step=0.5, group=grp_strat)

grp_vis = "Visual Design"
i_showHUD     = input.bool(true, "Show Status HUD", group=grp_vis)
i_showRR      = input.bool(true, "Show R:R Overlay", group=grp_vis)
i_showGlow    = input.bool(true, "Show Neon Glow on Momentum Lines", group=grp_vis)
i_showPullback = input.bool(true, "Show Pullback Diamonds", group=grp_vis)

// ==================================================================================
// COLOR PALETTE (from Visual Design Spec)
// ==================================================================================
color C_SLATE     = #708090     // 200 EMA Channel
color C_WHITE     = #FFFFFF     // Fast EMA (5)
color C_MINT      = #00FFAB     // Slow EMA (8)
color C_GOLD      = #FFD700     // Pullback warning
color C_SIG_GREEN = #39FF14     // Bullish entry / TP
color C_SIG_RED   = #FF3131     // Bearish entry / SL

// ==================================================================================
// PHASE 2: INDICATOR CALCULATIONS
// ==================================================================================
ema200_high  = ta.ema(high, len_long)
ema200_close = ta.ema(close, len_long)
ema200_low   = ta.ema(low, len_long)

ema_fast = ta.ema(close, len_fast)
ema_slow = ta.ema(close, len_slow)

// ==================================================================================
// PHASE 3: PLOTTING & VISUALIZATION
// ==================================================================================

// --- 200 EMA Channel ---
p_high = plot(ema200_high, color=color.new(C_SLATE, 30), linewidth=1, title="EMA 200 High")
p_low  = plot(ema200_low,  color=color.new(C_SLATE, 30), linewidth=1, title="EMA 200 Low")
plot(ema200_close, color=color.new(C_SLATE, 50), linewidth=1, style=plot.style_line, title="EMA 200 Close")

// --- Momentum Ribbon with Neon Glow ---
plot(i_showGlow ? ema_fast : na, "Fast Glow", color=color.new(C_WHITE, 70), linewidth=5)
plot(ema_fast, "EMA 5 (Fast)", color=C_WHITE, linewidth=2)

plot(i_showGlow ? ema_slow : na, "Slow Glow", color=color.new(C_MINT, 70), linewidth=5)
plot(ema_slow, "EMA 8 (Slow)", color=C_MINT, linewidth=2)

// ==================================================================================
// PHASE 4: STATE MANAGEMENT (CRITICAL LOGIC)
// Combined breakout + momentum confirmation into single state check.
// Uses var persistence to track the sequence: Confirm -> Pullback -> Entry.
// ==================================================================================

// State Tracking Variables
var int   trend_state     = 0      // 1 = Bullish, -1 = Bearish, 0 = Neutral
var bool  pullback_active = false
var float swing_high      = na     // Tracked for Price Action entry mode
var float swing_low       = na

// 1. Initial Signal & Confirmation (Phase 1+2 combined)
// Both price AND momentum EMAs must be outside the channel
price_above_channel = close > ema200_high
emas_above_channel  = ema_fast > ema200_high and ema_slow > ema200_high

price_below_channel = close < ema200_low
emas_below_channel  = ema_fast < ema200_low and ema_slow < ema200_low

// Set or update trend state
if price_above_channel and emas_above_channel
    trend_state := 1
    if not pullback_active
        swing_high := high
    pullback_active := false
else if price_below_channel and emas_below_channel
    trend_state := -1
    if not pullback_active
        swing_low := low
    pullback_active := false

// Update swing extremes while waiting for pullback
if trend_state == 1 and not pullback_active
    swing_high := math.max(nz(swing_high, high), high)
if trend_state == -1 and not pullback_active
    swing_low := math.min(nz(swing_low, low), low)

// 2. Pullback Detection
// Bullish pullback: price low touches or enters the channel from above
if trend_state == 1 and low <= ema200_high
    pullback_active := true

// Bearish pullback: price high touches or enters the channel from below
if trend_state == -1 and high >= ema200_low
    pullback_active := true

// Dynamic channel fill — changes color with bias
chanFillColor = trend_state == 1 ? color.new(C_SIG_GREEN, 90) : trend_state == -1 ? color.new(C_SIG_RED, 90) : color.new(C_SLATE, 90)
fill(p_high, p_low, color=chanFillColor, title="EMA 200 Channel")

// ==================================================================================
// PHASE 5: ENTRY TRIGGERS
// ==================================================================================
bool long_entry  = false
bool short_entry = false

if use_alt_entry
    // Alternative: Breakout of swing high/low after pullback
    if trend_state == 1 and pullback_active and close > swing_high
        long_entry := true
    if trend_state == -1 and pullback_active and close < swing_low
        short_entry := true
else
    // Standard: EMA crossover after pullback
    if trend_state == 1 and pullback_active and ta.crossover(ema_fast, ema_slow)
        long_entry := true
    if trend_state == -1 and pullback_active and ta.crossunder(ema_fast, ema_slow)
        short_entry := true

// ==================================================================================
// PHASE 6: EXECUTION & RISK MANAGEMENT
// ==================================================================================
var float sl_level = na
var float tp_level = na

if long_entry and strategy.position_size == 0
    sl_level := ema200_low
    float risk = close - sl_level
    tp_level := close + (risk * rr_ratio)
    strategy.entry("Long", strategy.long)
    // Reset state to prevent re-entry on same setup
    trend_state     := 0
    pullback_active := false

if short_entry and strategy.position_size == 0
    sl_level := ema200_high
    float risk = sl_level - close
    tp_level := close - (risk * rr_ratio)
    strategy.entry("Short", strategy.short)
    trend_state     := 0
    pullback_active := false

// Exit orders
if strategy.position_size > 0
    strategy.exit("Exit Long", "Long", stop=sl_level, limit=tp_level)
if strategy.position_size < 0
    strategy.exit("Exit Short", "Short", stop=sl_level, limit=tp_level)

// ==================================================================================
// SIGNAL SHAPES
// ==================================================================================

// Pullback diamond (gold, inside channel)
bool newPullback = pullback_active and not pullback_active[1]
plotshape(i_showPullback and newPullback, style=shape.diamond, location=location.absolute, color=C_GOLD, size=size.small, title="Pullback Diamond")

// Entry arrows
plotshape(long_entry and strategy.position_size == 0,  style=shape.triangleup,   location=location.belowbar, color=C_SIG_GREEN, text="LONG",  textcolor=C_SIG_GREEN, size=size.small, title="Long Entry")
plotshape(short_entry and strategy.position_size == 0, style=shape.triangledown, location=location.abovebar, color=C_SIG_RED,   text="SHORT", textcolor=C_SIG_RED,   size=size.small, title="Short Entry")

// ==================================================================================
// R:R OVERLAY (Visual Design Spec Section 5)
// ==================================================================================
var line  slLine    = na
var line  tpLine    = na
var line  entLine   = na
var box   profitBox = na
var box   lossBox   = na
var label slLabel   = na
var label tpLabel   = na

// Clean previous frame
line.delete(slLine)
line.delete(tpLine)
line.delete(entLine)
box.delete(profitBox)
box.delete(lossBox)
label.delete(slLabel)
label.delete(tpLabel)

if i_showRR and strategy.position_size != 0 and not na(sl_level) and not na(tp_level)
    float ep     = strategy.position_avg_price
    int startBar = bar_index - 1
    int endBar   = bar_index + 20

    // Entry line
    entLine := line.new(startBar, ep, endBar, ep, color=color.new(color.white, 50), width=1, style=line.style_dotted)

    // SL line
    slLine := line.new(startBar, sl_level, endBar, sl_level, color=C_SIG_RED, width=1, style=line.style_solid)

    // TP line
    tpLine := line.new(startBar, tp_level, endBar, tp_level, color=C_SIG_GREEN, width=1, style=line.style_solid)

    // Profit/loss zone boxes
    if strategy.position_size > 0
        profitBox := box.new(startBar, tp_level, endBar, ep, bgcolor=color.new(C_SIG_GREEN, 85), border_color=color(na))
        lossBox   := box.new(startBar, ep, endBar, sl_level, bgcolor=color.new(C_SIG_RED, 85), border_color=color(na))
    else
        profitBox := box.new(startBar, ep, endBar, tp_level, bgcolor=color.new(C_SIG_GREEN, 85), border_color=color(na))
        lossBox   := box.new(startBar, sl_level, endBar, ep, bgcolor=color.new(C_SIG_RED, 85), border_color=color(na))

    // Labels
    slLabel := label.new(endBar + 2, sl_level, "SL", style=label.style_none, textcolor=C_SIG_RED, size=size.small)
    tpLabel := label.new(endBar + 2, tp_level, "TP", style=label.style_none, textcolor=C_SIG_GREEN, size=size.small)

// ==================================================================================
// STATUS HUD (Visual Design Spec Section 6)
// ==================================================================================
var table hud = table.new(position.top_right, 2, 5, bgcolor=color.new(#000000, 60), border_width=1, border_color=color.new(color.gray, 60))

if i_showHUD and barstate.islast
    // Bias
    string biasText  = trend_state == 1 ? "BULLISH" : trend_state == -1 ? "BEARISH" : "NEUTRAL"
    color  biasColor = trend_state == 1 ? C_SIG_GREEN : trend_state == -1 ? C_SIG_RED : color.gray
    table.cell(hud, 0, 0, "BIAS",     text_color=color.gray, text_size=size.small)
    table.cell(hud, 1, 0, biasText,   text_color=biasColor, text_size=size.small)

    // Momentum alignment
    bool aligned = (trend_state == 1 and emas_above_channel) or (trend_state == -1 and emas_below_channel)
    table.cell(hud, 0, 1, "MOMENTUM", text_color=color.gray, text_size=size.small)
    table.cell(hud, 1, 1, aligned ? "ALIGNED" : "DISALIGNED", text_color=aligned ? C_SIG_GREEN : color.new(C_SIG_RED, 30), text_size=size.small)

    // Current step
    string stepText = trend_state == 0 ? "IDLE" : pullback_active ? "3. Pullback" : (trend_state == 1 and emas_above_channel) or (trend_state == -1 and emas_below_channel) ? "2. Confirmed" : "1. Breakout"
    color  stepClr  = pullback_active ? C_GOLD : trend_state != 0 ? color.white : color.gray
    table.cell(hud, 0, 2, "STEP",     text_color=color.gray, text_size=size.small)
    table.cell(hud, 1, 2, stepText,   text_color=stepClr, text_size=size.small)

    // Position status
    string posText = strategy.position_size > 0 ? "LONG" : strategy.position_size < 0 ? "SHORT" : "FLAT"
    color  posClr  = strategy.position_size > 0 ? C_SIG_GREEN : strategy.position_size < 0 ? C_SIG_RED : color.gray
    table.cell(hud, 0, 3, "POSITION", text_color=color.gray, text_size=size.small)
    table.cell(hud, 1, 3, posText,    text_color=posClr, text_size=size.small)

    // Entry mode
    table.cell(hud, 0, 4, "MODE",     text_color=color.gray, text_size=size.small)
    table.cell(hud, 1, 4, use_alt_entry ? "Price Action" : "Crossover", text_color=color.white, text_size=size.small)

// ==================================================================================
// ALERT CONDITIONS
// ==================================================================================
alertcondition(trend_state == 1 and trend_state[1] != 1,   "Bullish Bias Confirmed", "Price and EMAs confirmed above 200 EMA channel")
alertcondition(trend_state == -1 and trend_state[1] != -1,  "Bearish Bias Confirmed", "Price and EMAs confirmed below 200 EMA channel")
alertcondition(newPullback and trend_state == 1,             "Bullish Pullback Active", "Price pulled back to 200 EMA channel — watch for long entry")
alertcondition(newPullback and trend_state == -1,            "Bearish Pullback Active", "Price pulled back to 200 EMA channel — watch for short entry")
alertcondition(long_entry and strategy.position_size == 0,   "Long Entry Triggered",   "All conditions met — long entry executed")
alertcondition(short_entry and strategy.position_size == 0,  "Short Entry Triggered",  "All conditions met — short entry executed")

Overview

Entries follow a tracked sequence of breakout, momentum confirmation and pullback, with an alternative price-action entry option. Exits use a configurable risk-to-reward ratio, and position size defaults to a percentage of equity. A status panel and pullback markers can be shown. It draws on the price chart.

Details

Published by

rubbermetal on GitHub

Code credit

claygrace74, as written in the script's header

Draws

On the price chart

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

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

SettingTypeDefaultVariable
Long Term EMA Lengthint200len_long
Fast Momentum EMA (White)int5len_fast
Slow Momentum EMA (Green)int8len_slow
Use Alternative Entry (Price Action)boolfalseuse_alt_entry
Risk/Reward Ratiofloat2.0rr_ratio
Show Status HUDbooltruei_showHUD
Show R:R Overlaybooltruei_showRR
Show Neon Glow on Momentum Linesbooltruei_showGlow
Show Pullback Diamondsbooltruei_showPullback
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

257 stars

This strategy plots running pivot highs as red R circles and pivot lows as blue S circles directly on the price chart. It computes an EMA 3 and a Cto trend line from close prices, then generates long signals on upward EMA-Cto crossovers combined with price pos

Strategy v6 TrendMoving averages Repaints
Updated 6 weeks ago · None stated GitHub repository of Best Chart 1m Strategy Candle Bar

12/26-IT Strategy

by hasnocool
106 stars

This strategy executes trades based on crossovers between a 12-period and a 26-period exponential moving average (EMA). Long positions can be filtered by pivot resistance breakouts and RSI boundary ranges. For trade management, it provides two configurable par

Strategy v5 TrendMoving averages
Updated 2 years ago · GPL-3.0 GitHub repository of 12/26-IT Strategy

均线突破交易系统

by tangly1024
76 stars

This strategy trades long breakouts of a fast and a slow moving average on the price chart. It opens a long position when price crosses above either average, using a percentage of equity as size. It reduces the position by a set share when the high reaches the

Strategy v5 TrendMoving averages
Updated 5 months ago · None stated GitHub repository of 均线突破交易系统
43 stars

This strategy executes trades on short-term cryptocurrency charts using a combination of pivot support and resistance levels and a multi-pole smoothed trend filter. Entries trigger when price crosses the smoothed trend line and confirms above or below a short-

Strategy v5 TrendBreakout Repaints
Updated 2 years ago · None stated GitHub repository of SOL 1m - Strategy Candle Bar

ADA4H Optuna Strategy

by skywalker0803r
42 stars

This strategy trades longs and shorts on the price chart. Long entries require a close above the prior Donchian high, a close above a long-term SMA, and RSI above a threshold, with size set as a percentage of equity. Long exits use a stop at the prior Donchian

Strategy v5 TrendOscillators & momentum
Updated 2 months ago · None stated GitHub repository of ADA4H Optuna Strategy
16 stars

This strategy plots Donchian channels, trailing stops, and profit targets directly on the price chart. It enters breakout trades using a 55-bar Donchian channel and sizes positions according to an ATR-based risk percentage per unit. The system adds units as pr

Strategy v6 TrendBreakout
Updated 12 months ago · None stated GitHub repository of Seykota Alt 10: Profit Targets

More Trend scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

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

Compare brokers