StructureX

Home › Guides › Platforms

Pine Script moving average crossover: code it, then see where it lags

The moving average crossover is often the first idea people code. It's short, it's clear, and it teaches a lot. It also shows, very plainly, why a signal that looks neat on a chart needs testing.

Beginner guide · 9-minute read · Updated 2026-10-21

The idea in one line

Draw 2 Moving average lines: a fast one over a few candles, and a slow one over more. When the fast line crosses above the slow line, recent prices are rising faster than older ones. When it crosses below, the opposite.

That's it. It's a simple way to describe direction. It doesn't predict anything. More on the averages themselves in moving averages explained.

New to Pine Script? Start with Pine Script for beginners.

The script

This indicator draws 2 EMA lines (averages that lean toward the newest candles), marks each cross, and skips crosses that go against a longer 200-candle average:

//@version=6
indicator("MA crossover", overlay=true)
fastLen = input.int(20, "Fast length", minval=1)
slowLen = input.int(50, "Slow length", minval=2)
useFilter = input.bool(true, "Only with the 200 average")
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
trendLine = ta.ema(close, 200)
crossUp = ta.crossover(fast, slow)
crossDown = ta.crossunder(fast, slow)
upOK = crossUp and (not useFilter or close > trendLine)
downOK = crossDown and (not useFilter or close < trendLine)
plot(fast, "Fast", color=color.orange)
plot(slow, "Slow", color=color.blue)
plot(useFilter ? trendLine : na, "200 average", color=color.gray)
plotshape(upOK and barstate.isconfirmed, "Cross up", style=shape.triangleup, location=location.belowbar, color=color.green, size=size.small)
plotshape(downOK and barstate.isconfirmed, "Cross down", style=shape.triangledown, location=location.abovebar, color=color.red, size=size.small)
alertcondition(upOK, "Cross up", "{{ticker}}: fast average crossed above slow")
alertcondition(downOK, "Cross down", "{{ticker}}: fast average crossed below slow")

Every line, in plain words

Why the filter?

A cross against the bigger direction is a cross into the wind. The filter is a simple way to follow one of our rules: check the bigger picture first, and trade with it.

A 200-candle average is a blunt tool for that. A more direct read is higher highs and higher lows. Or check a bigger timeframe with Pine Script higher-timeframe trend.

Where crossovers struggle

Every honest page about crossovers needs this part.

1. They're late

An average is built from past candles. So a cross happens after the move has already started. By the time 20 crosses 50, price may have run a long way. Exits come late too.

2. They whipsaw in sideways markets

When price drifts sideways, the 2 lines tangle. They cross up, then down, then up again. Each cross looks like a fresh start. Most of them go nowhere.

Scroll back on almost any chart and you'll find stretches like this. Count the marks there.

3. The settings tempt you

10 and 30? 20 and 50? 50 and 200? On any one chart, some pair will look great in hindsight. That's overfitting: settings tuned to old candles that won't repeat.

ProblemWhy it happensWhat helps
Late entriesAverages use past pricesAccept it, or use shorter lengths (and get more false starts)
WhipsawsSideways price tangles the linesA trend filter, or skip flat markets
OverfittingToo many settings triedPick lengths for a reason, test on other charts

Does it repaint?

The averages don't change once a candle closes. But on a live candle, the close keeps moving. The lines move with it, and a cross can appear, then vanish.

That's why lines 16 and 17 use barstate.isconfirmed. For the alerts, pick Once per bar close when you create them. Then live and history agree.

That matches a rule we use for every level: only a candle body closing past it counts.

A cross isn't a plan

A crossover tells you when something changed. It doesn't tell you:

Test it before you trust it. Turn it into a strategy and read the results honestly, with costs included. Pine Script strategy backtest shows how, and why those results are hypothetical.

Try it today

  1. Paste the script into the Pine Editor on a computer. Save and add it to a daily chart.
  2. Find one trending stretch and one sideways stretch.
  3. Count the marks in each. Note how far price moved before each mark appeared.
  4. Untick the 200 filter. How many extra marks appear? Were they better or worse?
  5. Then step through a few months with bar replay, so the future stays hidden.

Change one thing at a time. Swap EMA for SMA, or 20 for 10, but not both. Otherwise you won't know which change mattered. See EMA vs SMA.

Learning from a real script

A crossover is a fine first script. Reading a bigger one teaches how levels, settings and alerts fit together. Our course includes the full source code of the StructureX chart tool to learn from and customize. It's source code, not a ready-made trading bot.

Common mistakes

Questions

How do I code a moving average crossover in Pine Script?

Work out 2 averages with ta.ema() or ta.sma(), then use ta.crossover(fast, slow) for a cross up and ta.crossunder(fast, slow) for a cross down. Mark them with plotshape().

What is the best moving average crossover?

There isn't one best pair. 20/50 and 50/200 are common, but any pair looks best on some charts in hindsight. Pick lengths for a reason, then test them on many charts.

Why does my crossover signal disappear?

On a live candle the averages move with price, so a cross can undo itself before the close. Add barstate.isconfirmed to only mark closed candles.

Do moving average crossovers work?

They describe direction simply, but they're late and they whipsaw in sideways markets. Results vary by market and period, and losses are part of any rule.

Want the next step? We'll walk you through it.

Four free lessons by email, one every few days — each with a 10-minute exercise on a real chart.

Send Me the Free Lessons 4 short emails · No spam · Unsubscribe anytime

Or see the whole method, step by step:

See What’s Inside the Course Try everything free first. Decide when you're ready. · Open the free chart tool (works in the TradingView phone app)

One chart idea a day, in plain English. Follow along:

Follow on XFollow on TradingView