Trading Strategy

Moving Average Crossover

A classic trend-following strategy that uses two moving averages of different speeds to identify trend changes and potential entry points.

The Lagging Advantage

While crossovers are known for their lag, the 50/100 EMA pairing on the 4h timeframe is a favorite among intermediate traders for its ability to filter out "noise" while capturing the meat of a macro trend. This implementation has been completely reconstructed to ensure precision in signal detection and risk calculation.

Trend Type
4h Chart Timeframe
Beginner Complexity
Trending Best Market

Signal Logic

Golden Cross (Buy)

Triggered when the 50 EMA (Fast) crosses above the 100 EMA (Slow).

Death Cross (Sell)

Triggered when the 50 EMA (Fast) crosses below the 100 EMA (Slow).

Implementation

//@version=6
strategy("MA Crossover Strategy", shorttitle="MA Cross", overlay=true, initial_capital=1000000, default_qty_type=strategy.percent_of_equity, default_qty_value=100)

// ==========================================
// 🔹 INPUTS
// ==========================================

// Moving Average Settings
grp_ma = "Moving Average Settings"
fastLength = input.int(50, "Fast MA Length", minval=1, group=grp_ma)
slowLength = input.int(100, "Slow MA Length", minval=1, group=grp_ma)
src = input.source(close, "Source", group=grp_ma)
maType = input.string("EMA", "MA Type", options=["SMA", "EMA"], group=grp_ma)

// Risk Management Settings
grp_risk = "Risk Management"
useTP = input.bool(true, "Use Take Profit?", group=grp_risk)
tpPerc = input.float(33.0, "Take Profit (%)", step=0.1, group=grp_risk) / 100
useSL = input.bool(true, "Use Stop Loss?", group=grp_risk)
slPerc = input.float(5, "Stop Loss (%)", step=0.1, group=grp_risk) / 100

// Backtest Date Range
grp_time = "Backtest Window"
startDate = input.time(timestamp("2000-01-01 00:00"), "Start Date", group=grp_time)
endDate = input.time(timestamp("2030-01-01 00:00"), "End Date", group=grp_time)

// --- Calculations ---
// Function to get MA based on user selection
getMA(source, length, type) =>
    type == "SMA" ? ta.sma(source, length) : ta.ema(source, length)

fastMA = getMA(src, fastLength, maType)
slowMA = getMA(src, slowLength, maType)

// Check if we are in the backtest time window
inDateRange = time >= startDate and time <= endDate

// --- Strategy Logic ---
// Long Condition: Fast MA crosses OVER Slow MA
longCondition = ta.crossover(fastMA, slowMA) and inDateRange

// Short Condition: Fast MA crosses UNDER Slow MA
shortCondition = ta.crossunder(fastMA, slowMA) and inDateRange

// --- Execution ---
// Entry Logic
if longCondition
    strategy.entry("Long", strategy.long)

if shortCondition
    strategy.entry("Short", strategy.short)

// Exit Logic (Stop Loss / Take Profit)
// We calculate the TP/SL price based on the Entry Price of the position
if strategy.position_size > 0
    longStop = strategy.position_avg_price * (1 - slPerc)
    longTP = strategy.position_avg_price * (1 + tpPerc)
    strategy.exit("Exit Long", "Long", stop=useSL ? longStop : na, limit=useTP ? longTP : na)

if strategy.position_size < 0
    shortStop = strategy.position_avg_price * (1 + slPerc)
    shortTP = strategy.position_avg_price * (1 - tpPerc)
    strategy.exit("Exit Short", "Short", stop=useSL ? shortStop : na, limit=useTP ? shortTP : na)

// --- Visuals ---
plot(fastMA, color=color.rgb(0, 255, 0), title="Fast MA", linewidth=2)
plot(slowMA, color=color.rgb(255, 0, 0), title="Slow MA", linewidth=2)

// Visual signals on the chart
plotshape(longCondition, title="Long Signal", location=location.belowbar, color=color.green, style=shape.triangleup, size=size.small)
plotshape(shortCondition, title="Short Signal", location=location.abovebar, color=color.red, style=shape.triangledown, size=size.small)