Strategy · Pine Script v6 · On the chart

Forex EMA Trend with ATR Risk

by PETERSAMUELOPS12· code credited to Gotrade

A forex strategy that follows a fast and slow EMA crossover, filtered by a 200-period EMA so longs trade only above it and shorts only below.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code226
Settings17inputs
LicenceNone statedfile: MPL-2.0
Last update5 months ago25 May 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

226 lines of Pine Script v6 from pinescript/forex_trading.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

forex_trading.pine
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Gotrade

//@version=6
strategy("Forex – EMA Trend + ATR Risk", overlay=true, fill_orders_on_standard_ohlc=true,
         default_qty_type=strategy.cash, default_qty_value=1000,
         initial_capital=10000, margin_long=2.0, margin_short=2.0,
         commission_type=strategy.commission.cash_per_order, commission_value=0.0002,
         calc_on_every_tick=false)

// ═══════════════════════════════════════════════════════════════════════════════
// INPUTS
// ═══════════════════════════════════════════════════════════════════════════════
grp0 = "EMA Trend"
fastLen   = input.int(20,  "Fast EMA",         minval=1,  group=grp0)
slowLen   = input.int(50,  "Slow EMA",         minval=1,  group=grp0)
trendLen  = input.int(200, "Trend EMA (filter)",minval=1, group=grp0,
               tooltip="Only longs above this EMA, only shorts below it.")

grp1 = "Entry Filters"
useRsi      = input.bool(true,  "RSI Filter",              group=grp1)
rsiLen      = input.int(14,     "RSI Period",              group=grp1, minval=2)
rsiOBLevel  = input.int(65,     "RSI Overbought (no long)", group=grp1)
rsiOSLevel  = input.int(35,     "RSI Oversold (no short)",  group=grp1)
useSession  = input.bool(true,  "Session Filter",           group=grp1,
               tooltip="Only trade during London + New York sessions (highest liquidity).")
sessionStr  = input.session("0700-2100", "Allowed Session (exchange time)", group=grp1)

grp2 = "Risk Management"
riskPct     = input.float(1.0,  "Risk % per trade",         minval=0.1, step=0.1, group=grp2,
               tooltip="Position is sized so that hitting the stop = losing X% of equity.")
atrLen      = input.int(14,     "ATR Period",               minval=1,  group=grp2)
slAtr       = input.float(1.5,  "Stop Loss (× ATR)",        minval=0.1, step=0.1, group=grp2)
tpAtr       = input.float(2.5,  "Take Profit (× ATR)",      minval=0.1, step=0.1, group=grp2,
               tooltip="R:R = TP ATR / SL ATR. Default 2.5/1.5 ≈ 1:1.67.")
useTrail    = input.bool(true,  "Use trailing stop after TP1", group=grp2,
               tooltip="Once price reaches TP zone, switch to trailing stop to let winners run.")
trailAtr    = input.float(1.0,  "Trail stop (× ATR)",       minval=0.1, step=0.1, group=grp2)

grp3 = "Trade Direction"
allowLong   = input.bool(true,  "Allow Long  (buy)",  group=grp3)
allowShort  = input.bool(true,  "Allow Short (sell)", group=grp3)

// ═══════════════════════════════════════════════════════════════════════════════
// INDICATORS
// ═══════════════════════════════════════════════════════════════════════════════
fastEMA  = ta.ema(close, fastLen)
slowEMA  = ta.ema(close, slowLen)
trendEMA = ta.ema(close, trendLen)
atr      = ta.atr(atrLen)
rsi      = ta.rsi(close, rsiLen)

inSession = not useSession or time(timeframe.period, sessionStr) != 0

// ═══════════════════════════════════════════════════════════════════════════════
// SIGNALS
// ═══════════════════════════════════════════════════════════════════════════════
// Trend direction
uptrend   = close > trendEMA
downtrend = close < trendEMA

// EMA crossover
bullCross = ta.crossover(fastEMA, slowEMA)
bearCross = ta.crossunder(fastEMA, slowEMA)

// RSI filter
rsiOkLong  = not useRsi or rsi < rsiOBLevel
rsiOkShort = not useRsi or rsi > rsiOSLevel

// Final entry signals
longSig  = bullCross and uptrend   and rsiOkLong  and inSession and allowLong
shortSig = bearCross and downtrend and rsiOkShort and inSession and allowShort

// ═══════════════════════════════════════════════════════════════════════════════
// POSITION SIZING  (risk-based)
// ═══════════════════════════════════════════════════════════════════════════════
// stopDist = distance in price units from entry to stop
// positionSize (in cash) = (equity × riskPct%) / stopDist × close
// → so that a stopDist move = exactly riskPct% of equity lost
stopDist     = atr * slAtr
riskAmount   = strategy.equity * riskPct / 100
// qty in base currency units
posQty       = riskAmount / stopDist

// ═══════════════════════════════════════════════════════════════════════════════
// STOP & TARGET LEVELS  (calculated on entry bar, stored in vars)
// ═══════════════════════════════════════════════════════════════════════════════
var float longSL  = na
var float longTP  = na
var float shortSL = na
var float shortTP = na
var bool  trailOn = false

inLong  = strategy.position_size > 0
inShort = strategy.position_size < 0

// Reset trail flag when flat
if not inLong and not inShort
    trailOn := false

// ═══════════════════════════════════════════════════════════════════════════════
// ORDERS
// ═══════════════════════════════════════════════════════════════════════════════
if longSig and not inLong and not inShort
    longSL := close - stopDist
    longTP := close + atr * tpAtr
    strategy.entry("Long", strategy.long, qty=posQty,
                   comment="▲ L rsi=" + str.tostring(math.round(rsi, 0)))

if shortSig and not inShort and not inLong
    shortSL := close + stopDist
    shortTP := close - atr * tpAtr
    strategy.entry("Short", strategy.short, qty=posQty,
                   comment="▼ S rsi=" + str.tostring(math.round(rsi, 0)))

// ── Long exit ──────────────────────────────────────────────────────────────────
if inLong
    if useTrail and high >= longTP
        trailOn := true
    if trailOn
        // Trailing stop: trail below the highest high since TP was reached
        var float trailPeak = na
        trailPeak := math.max(nz(trailPeak, high), high)
        trailPrice = trailPeak - atr * trailAtr
        if close <= trailPrice
            strategy.close("Long", comment="TRAIL")
            trailPeak := na
    else
        strategy.exit("Long Exit", from_entry="Long",
                      stop=longSL, limit=longTP,
                      comment_loss="SL", comment_profit="TP")

// ── Short exit ─────────────────────────────────────────────────────────────────
if inShort
    if useTrail and low <= shortTP
        trailOn := true
    if trailOn
        var float trailTrough = na
        trailTrough := math.min(nz(trailTrough, low), low)
        trailPrice  = trailTrough + atr * trailAtr
        if close >= trailPrice
            strategy.close("Short", comment="TRAIL")
            trailTrough := na
    else
        strategy.exit("Short Exit", from_entry="Short",
                      stop=shortSL, limit=shortTP,
                      comment_loss="SL", comment_profit="TP")

// ═══════════════════════════════════════════════════════════════════════════════
// PLOTS
// ═══════════════════════════════════════════════════════════════════════════════
plot(fastEMA,  "Fast EMA",  color=color.new(color.green, 20),  linewidth=1)
plot(slowEMA,  "Slow EMA",  color=color.new(color.orange, 20), linewidth=1)
plot(trendEMA, "Trend EMA", color=color.new(color.blue,  20),  linewidth=2)

// Stop / TP lines while in trade
plot(inLong  ? longSL  : na, "Long SL",  color=color.red,   linewidth=1, style=plot.style_linebr)
plot(inLong  ? longTP  : na, "Long TP",  color=color.green, linewidth=1, style=plot.style_linebr)
plot(inShort ? shortSL : na, "Short SL", color=color.red,   linewidth=1, style=plot.style_linebr)
plot(inShort ? shortTP : na, "Short TP", color=color.green, linewidth=1, style=plot.style_linebr)

// Session highlight
bgcolor(useSession and not inSession ? color.new(color.gray, 92) : na, title="Outside Session")

plotshape(longSig,  "Long Signal",  shape.triangleup,   location.belowbar, color.green, size=size.small)
plotshape(shortSig, "Short Signal", shape.triangledown, location.abovebar, color.red,   size=size.small)

// ═══════════════════════════════════════════════════════════════════════════════
// DASHBOARD
// ═══════════════════════════════════════════════════════════════════════════════
var table dash = table.new(position.top_right, 2, 11,
     bgcolor=color.new(color.black, 55), border_width=1, border_color=color.new(color.gray, 60))

if barstate.islast
    rrRatio  = tpAtr / slAtr
    pnlCol   = strategy.openprofit >= 0 ? color.lime : color.red
    netCol   = strategy.netprofit  >= 0 ? color.lime : color.red
    trendCol = uptrend ? color.lime : (downtrend ? color.red : color.gray)
    na_str   = "–"

    table.cell(dash, 0, 0, "Forex EMA Strategy",  text_color=color.white,
               text_size=size.small, bgcolor=color.new(color.navy, 30))
    table.cell(dash, 1, 0, "",                     text_color=color.white,
               text_size=size.small, bgcolor=color.new(color.navy, 30))

    table.cell(dash, 0, 1, "Trend",          text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 1, uptrend ? "▲ Bullish" : (downtrend ? "▼ Bearish" : "─ Neutral"),
               text_color=trendCol, text_size=size.small)

    table.cell(dash, 0, 2, "Fast/Slow EMA",  text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 2, str.tostring(math.round(fastEMA, 5)) + " / " + str.tostring(math.round(slowEMA, 5)),
               text_color=color.white, text_size=size.small)

    table.cell(dash, 0, 3, "RSI",            text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 3, str.tostring(math.round(rsi, 1)),
               text_color=rsi > rsiOBLevel ? color.red : (rsi < rsiOSLevel ? color.lime : color.white), text_size=size.small)

    table.cell(dash, 0, 4, "ATR",            text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 4, str.tostring(math.round(atr, 5)),
               text_color=color.white, text_size=size.small)

    table.cell(dash, 0, 5, "SL / TP (ATR)",  text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 5, str.tostring(slAtr) + "× / " + str.tostring(tpAtr) + "×  R:R 1:" + str.tostring(math.round(rrRatio, 2)),
               text_color=color.yellow, text_size=size.small)

    table.cell(dash, 0, 6, "Risk / trade",   text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 6, str.tostring(riskPct) + "% = $" + str.tostring(math.round(strategy.equity * riskPct / 100, 2)),
               text_color=color.orange, text_size=size.small)

    table.cell(dash, 0, 7, "Position",       text_color=color.silver, text_size=size.small)
    posStr = inLong ? "LONG " + str.tostring(math.round(strategy.position_size, 2)) : (inShort ? "SHORT " + str.tostring(math.abs(math.round(strategy.position_size, 2))) : "FLAT")
    posCol = inLong ? color.lime : (inShort ? color.red : color.gray)
    table.cell(dash, 1, 7, posStr, text_color=posCol, text_size=size.small)

    table.cell(dash, 0, 8, "Session",        text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 8, inSession ? "✓ Active" : "✗ Closed",
               text_color=inSession ? color.lime : color.gray, text_size=size.small)

    table.cell(dash, 0, 9, "Open P&L",       text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 9, "$" + str.tostring(math.round(strategy.openprofit, 2)),
               text_color=pnlCol, text_size=size.small)

    table.cell(dash, 0, 10, "Net Profit",    text_color=color.silver, text_size=size.small)
    table.cell(dash, 1, 10, "$" + str.tostring(math.round(strategy.netprofit, 2)) +
               "  (" + str.tostring(strategy.closedtrades) + " trades)",
               text_color=netCol, text_size=size.small)

Overview

An RSI filter blocks longs when overbought and shorts when oversold, and a session filter limits trading to a chosen window. Stops and targets are ATR multiples, size is set from a risk percentage of equity, and an optional ATR trailing stop takes over after the first target.

Details

Published by

PETERSAMUELOPS12 on GitHub

Code credit

Gotrade, as written in the script's header

Type

Strategy, Pine Script v6

Draws

On the price chart

Category

Trend, Moving averages, Sessions & time

Markets

Forex

Timeframes

M15-H1

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
Fast EMAint20fastLen
Slow EMAint50slowLen
Trend EMA (filter)int200trendLen
RSI FilterbooltrueuseRsi
RSI Periodint14rsiLen
RSI Overbought (no long)int65rsiOBLevel
RSI Oversold (no short)int35rsiOSLevel
Session FilterbooltrueuseSession
Allowed Session (exchange time)session0700-2100sessionStr
Risk % per tradefloat1.0riskPct
ATR Periodint14atrLen
Stop Loss (× ATR)float1.5slAtr
Show all 17 settings
SettingTypeDefaultVariable
Take Profit (× ATR)float2.5tpAtr
Use trailing stop after TP1booltrueuseTrail
Trail stop (× ATR)float1.0trailAtr
Allow Long (buy)booltrueallowLong
Allow Short (sell)booltrueallowShort
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

Donald - Test Logic Futures is an overlay strategy designed for intraday futures trading. It combines kernel regression functions with exponential moving averages to evaluate price retracements and entry timing. Trades are filtered by session execution windows

Strategy v5 TrendMoving averages Repaints
Updated 6 weeks ago · None stated GitHub repository of Donald - Test Logic Futures

Andean Scalping

by hasnocool
106 stars

Andean Scalping is a Pine Script v5 strategy template designed for backtesting trading signals. It features session and date-range filtering, directional trade toggles for long and short entries, and optional trend filtering tools including higher-timeframe EM

Strategy v5 TrendMoving averages
Updated 2 years ago · GPL-3.0 GitHub repository of Andean Scalping

This strategy plots a 90-period simple moving average from the daily and four-hour charts plus a daily session VWAP on the price chart. It enters long when VWAP is above the daily average and the four-hour VWAP crosses above its average, and short in the oppos

Strategy v5 TrendMoving averages Repaints
Updated 3 years ago · MIT GitHub repository of 1D Bullish Buy 4H Bearish Sell Session
4 stars

This strategy trades directional momentum breakouts for crude oil on the price chart. It enters long or short positions when a fast exponential moving average crosses a slow exponential moving average, provided that current Average True Range exceeds its movin

Strategy v6 TrendMoving averages
Updated 2 months ago · MIT GitHub repository of CL Crude Oil Momentum [trugurpala]

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