Pine Script Signal Detection

Pine Script Crossover: How to Code ta.crossover() Signals and Rules

In Pine Script, ta.crossover(source1, source2) checks if the first series has crossed over the second series. It returns true if on the current bar source1 is strictly greater than source2, and on the previous bar source1 was less than or equal to source2. It returns false under all other conditions or if either value is na.

Build Crossover Strategies with AI

Understanding ta.crossover syntax and behavior in Pine Script v6

The technical analysis namespace function ta.crossover() is the cornerstone of momentum, trend-following, and breakout systems in TradingView. It accepts series floats, integers, or static numerical levels for either argument.

Function expressionCondition required for truePrimary use caseCommon pitfall
ta.crossover(fastMa, slowMa)fastMa > slowMa and fastMa[1] <= slowMa[1]Golden Cross trend entriesLagging entries during range-bound chop
ta.crossover(rsi, 30)rsi > 30 and rsi[1] <= 30Oversold rebound exits and reversalsPremature long entry before trend exhaustion
ta.crossover(close, upperBand)close > upperBand and close[1] <= upperBand[1]Volatility breakouts (Donchian / Bollinger)Whipsaw fakeouts if volume is thin
ta.crossunder(source1, source2)source1 < source2 and source1[1] >= source2[1]Death Cross exits and short entriesConfusing argument order (x vs y)

Complete Pine Script v6 dual moving average crossover strategy

The following complete strategy script implements an exponential moving average crossover system with visual signal arrows, ATR stop loss protection, and TradingView alerts.

Pine Script v6: Dual EMA crossover trading strategypinescript
//@version=6
strategy("Dual EMA Crossover Strategy [v6]", 
         overlay = true, 
         initial_capital = 10000, 
         default_qty_type = strategy.percent_of_equity, 
         default_qty_value = 10)

// Input parameters
int fastPeriod = input.int(9, "Fast EMA Period", minval = 1)
int slowPeriod = input.int(21, "Slow EMA Period", minval = 1)
float atrMult = input.float(1.5, "ATR Stop Multiplier", minval = 0.5)

// Technical indicators
float fastEma = ta.ema(close, fastPeriod)
float slowEma = ta.ema(close, slowPeriod)
float atrVal = ta.atr(14)

// Crossover condition evaluation
bool longSignal = ta.crossover(fastEma, slowEma)
bool shortSignal = ta.crossunder(fastEma, slowEma)

// Plot indicator lines
plot(fastEma, "Fast EMA", color = color.blue, linewidth = 2)
plot(slowEma, "Slow EMA", color = color.orange, linewidth = 2)

// Visual shape markers
plotshape(longSignal, "Long Signal", shape.triangleup, location.belowbar, color.green, size = size.small)
plotshape(shortSignal, "Short Signal", shape.triangledown, location.abovebar, color.red, size = size.small)

// Strategy execution
if longSignal
    float longStop = close - (atrVal * atrMult)
    float longTarget = close + (atrVal * atrMult * 2.0)
    strategy.entry("Long", strategy.long)
    strategy.exit("Exit Long", from_entry = "Long", stop = longStop, limit = longTarget)

if shortSignal
    float shortStop = close + (atrVal * atrMult)
    float shortTarget = close - (atrVal * atrMult * 2.0)
    strategy.entry("Short", strategy.short)
    strategy.exit("Exit Short", from_entry = "Short", stop = shortStop, limit = shortTarget)

// Webhook alerts
alertcondition(longSignal, "Bullish Crossover", "Fast EMA crossed above Slow EMA on {{ticker}}")
alertcondition(shortSignal, "Bearish Crossunder", "Fast EMA crossed below Slow EMA on {{ticker}}")

How to prevent false signals and repainting with crossovers

Crossovers can appear and disappear multiple times while an unclosed candle is still forming. Apply these rules for reliable execution:

  • Confirm on bar close: For indicators, check barstate.isconfirmed alongside ta.crossover() before emitting alerts to prevent ghost signals.
  • Trend filtering: Combine crossover triggers with a higher-timeframe filter (such as a 200 EMA) to avoid counter-trend trades during consolidations.
  • Multi-timeframe precautions: When evaluating crossovers of data fetched with request.security(), always pass barmerge.lookahead_off to avoid future-leak bias.
  • Handling identical values: If two series touch without crossing, ta.crossover returns false because the current bar must strictly exceed the target series.

Comparing ta.crossover vs manual conditional comparisons

While ta.crossover(x, y) can be written manually as x > y and x[1] <= y[1], using the built-in function provides several advantages:

  • Readability: ta.crossover makes signal intent instantly clear to any collaborator or AI agent inspecting your script.
  • Automatic historical buffering: The built-in function guarantees proper lookback buffer allocation without manual indexing errors.
  • Null safety: Built-in crossover cleanly returns false when encountering historical na values during chart startup.
Where Pineify fits

Pine Script AI Coding Agent

Generate robust crossover indicators, multi-timeframe breakout filters, and automated backtesting strategies in Pine Script v6 with Pineify AI.

Also useful: Strategy Optimizer. Test thousands of moving average period pairs to identify optimal crossover parameters for your assets.

Build Crossover Strategies with AI

Frequently asked questions

Crossover signals depend on historical bar calculation and indicator parameters. Past backtest performance does not guarantee future market behavior. Always combine crossover logic with strict risk management.

Sources and verification