Skip to content

How to see if a value crossed over or under another in TradingView Pine?

How to see if a value crossed over or under another in TradingView Pine?

Section titled “How to see if a value crossed over or under another in TradingView Pine?”

TL;DR
Call ta.crossover(seriesA, seriesB) for upward crosses, ta.crossunder(seriesA, seriesB) for downward crosses, and ta.cross(seriesA, seriesB) when you only need to know a cross happened.

DifficultyBeginner
Time to implement5-10 min
CategorySignals
//@version=5
indicator("Crossover demo", overlay=false)
fast = ta.ema(close, 12)
slow = ta.ema(close, 26)
longSignal = ta.crossover(fast, slow)
shortSignal = ta.crossunder(fast, slow)
Tip. `ta.crossover` returns `true` only on the bar where the crossover occurs. On subsequent bars it reverts to `false` unless another cross happens.

Crossovers are the backbone of countless strategies—moving averages, oscillator thresholds, price vs. indicators. Pine’s ta.cross* functions encapsulate the logic, saving you from manual state tracking and reducing off-by-one errors.

  • Understand the difference between crossover, crossunder, and generic cross detection.
  • Use cross signals for entries, exits, and alert conditions.
  • Guard against false positives with filters (e.g., minimum separation).
  • Visualise cross points with shapes and labels.
CallPurpose
ta.crossover(series1, series2)Returns true when series1 crosses from below to above series2.
ta.crossunder(series1, series2)Returns true when series1 crosses from above to below series2.
ta.cross(series1, series2)Returns true for any cross (either direction).
plotshape(condition, ...)Highlights the cross on chart.
alertcondition(condition, title, message)Triggers alerts when a cross occurs.
  1. Create the series to compare
    These can be moving averages, price vs. indicator, or any custom calculation.

    basis = ta.sma(close, 50)
    trigger = ta.ema(close, 10)
  2. Detect the cross
    Choose the appropriate helper for the direction you care about.

    bullish = ta.crossover(trigger, basis)
    bearish = ta.crossunder(trigger, basis)
  3. Act on the signal
    Plot shapes, fire alerts, or execute strategy orders when the cross occurs.

    if bullish
    strategy.entry("Long", strategy.long)
    plotshape(bullish, title="Bull cross", location=location.belowbar, shape=shape.triangleup, color=color.new(color.green, 0))
//@version=5
indicator("EMA crossover highlighter", overlay=true, max_labels_count=500)
fastLen = input.int(21, "Fast EMA")
slowLen = input.int(55, "Slow EMA")
fast = ta.ema(close, fastLen)
slow = ta.ema(close, slowLen)
bullish = ta.crossover(fast, slow)
bearish = ta.crossunder(fast, slow)
plot(fast, "Fast", color=color.new(color.green, 0))
plot(slow, "Slow", color=color.new(color.red, 0))
plotshape(bullish, title="Bullish cross", location=location.belowbar, shape=shape.arrowup, color=color.new(color.green, 0), text="Bull")
plotshape(bearish, title="Bearish cross", location=location.abovebar, shape=shape.arrowdown, color=color.new(color.red, 0), text="Bear")
alertcondition(bullish, "Bullish crossover", "Fast EMA crossed above slow EMA")
alertcondition(bearish, "Bearish crossunder", "Fast EMA crossed below slow EMA")
Why this works.
  • Separate variables for bullish and bearish crosses make downstream logic explicit.
  • Shapes and alerts reuse the same booleans, keeping visuals and notifications aligned.
  • Input lengths let traders adjust sensitivity without modifying code.
  • Filter out rapid-fire crosses by requiring minimum bar separation or additional conditions (e.g., trend direction).
  • Combine with ta.barssince to measure time since the last cross.
  • For threshold-based crosses (e.g., RSI crossing 50), compare the oscillator against a constant (ta.crossover(rsi, 50)).
  • Remember that crosses on higher timeframes may repaint slightly until the higher-timeframe bar closes.

Why do I see multiple true values in a row?

Section titled “Why do I see multiple true values in a row?”

ta.cross* returns true once per bar. If you see repeated signals, ensure you’re not storing the boolean in a var and failing to reset it.

The cross fires even when the series just touches

Section titled “The cross fires even when the series just touches”

By definition, a cross triggers when series1 moves from one side to the other—even if it only touches for a split second. Add additional conditions (e.g., series1 > series2 + buffer) to require more separation.

Can I detect crosses on historical bars only?

Section titled “Can I detect crosses on historical bars only?”

Run the logic as-is; it already evaluates on historical bars. Just be mindful that on real-time bars the signal can flip until the bar closes.

  • ta.crossover, ta.crossunder, and ta.cross provide the simplest way to detect directional crosses.
  • Reuse the same boolean for plotting, alerts, and trade logic to keep behaviour consistent.
  • Add filters when you want to reduce noise or confirm crosses with additional criteria.
  • Cross detection is foundational—mastering it unlocks dozens of classic Pine strategies.

Adapted from tradingcode.net, optimised for Algo Trade Analytics users.