Vortex Indicator: formula, crossovers and limits
The Vortex Indicator compares two rolling price-movement ratios, VI+ and VI-. VI+ uses the current high and previous low; VI- uses the current low and previous high. Both are divided by the same sum of true range. Their crossovers describe a change in directional balance, but can reverse repeatedly in a sideways market.
Use the calculation table to check the bar indexes, then copy the adjustable Pine Script example. Its crossover markers wait for the chart candle to close.
Hypothetical result · Length 2 · Bar 3
VI+ = 3 / 6 = 0.500 · VI- = 6 / 6 = 1.000
VI- moves above VI+ after a downward bar. The table below supplies every input; this is an arithmetic demonstration, not a backtest.
Calculate Vortex from adjacent bars
For bar t, use high and low from t, but the previous extremes and close from t-1. Never substitute the current low for the previous low in VM+, or the current high for the previous high in VM-. Those substitutions would turn both numerators into the same high-low range.
VM+(t) = |High(t) - Low(t-1)|
VM-(t) = |Low(t) - High(t-1)|
TR(t) = max(High(t) - Low(t), |High(t) - Close(t-1)|, |Low(t) - Close(t-1)|)
VI+(t) = sum(VM+, n) / sum(TR, n)
VI-(t) = sum(VM-, n) / sum(TR, n)
Each sum includes the current bar and the preceding n-1 movement values. The table uses invented prices in arbitrary price units. Bar 0 only supplies the previous prices; three movements require four price bars.
| Bar | High | Low | Close | VM+ | VM- | TR |
|---|---|---|---|---|---|---|
| 0 | 10 | 8 | 9 | Seed bar | Seed bar | Seed bar |
| 1 | 11 | 9 | 10 | |11 - 8| = 3 | |9 - 10| = 1 | max(2, 2, 0) = 2 |
| 2 | 12 | 10 | 11 | |12 - 9| = 3 | |10 - 11| = 1 | max(2, 2, 0) = 2 |
| 3 | 10 | 7 | 8 | |10 - 10| = 0 | |7 - 12| = 5 | max(3, 1, 4) = 4 |
With n=2 at bar 2, the sums are VM+=6, VM-=2 and TR=4, giving 1.500 and 0.500. At bar 3, bar 1 leaves the window: VM+=3, VM-=6 and TR=6, giving 0.500 and 1.000. VI- has crossed above VI+. Notice that bar 3 has a high-low range of 3 but TR of 4 because its low is 4 below the previous close.
The positive denominator changes each line's magnitude, but it cannot change which line is larger. A line may exceed 1 because its numerator and TR measure different distances. Neither 1 nor a particular line separation is a universal entry threshold.
Pine Script v6 with explicit boundary handling
Paste the complete code into a new TradingView indicator, save it and add it to your chart. Length defaults to 14 and has a minimum of 1. Inspect the two plotted values in the Data Window. Blue upward triangles and magenta downward triangles mark closed-bar crossovers; they are observations, not executed orders.
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Pineify
//@version=6
indicator("Vortex Indicator: confirmed crossovers", overlay=false)
length = input.int(14, "Length", minval=1)
p_ta_vi(simple int length) =>
valid = not na(high) and not na(low) and not na(high[1]) and not na(low[1]) and not na(close[1])
vmPlus = valid ? math.abs(high - low[1]) : 0.0
vmMinus = valid ? math.abs(low - high[1]) : 0.0
trueRange = valid ? math.max(high - low, math.max(math.abs(high - close[1]), math.abs(low - close[1]))) : 0.0
sumPlus = math.sum(vmPlus, length)
sumMinus = math.sum(vmMinus, length)
sumTR = math.sum(trueRange, length)
ready = math.sum(valid ? 1.0 : 0.0, length) == length and sumTR > 0
[ready ? sumPlus / sumTR : na, ready ? sumMinus / sumTR : na]
[viPlus, viMinus] = p_ta_vi(length)
crossUp = ta.crossover(viPlus, viMinus)
crossDown = ta.crossunder(viPlus, viMinus)
confirmedUp = barstate.isconfirmed and crossUp
confirmedDown = barstate.isconfirmed and crossDown
plot(viPlus, "VI+", color=color.blue, linewidth=2)
plot(viMinus, "VI-", color=color.fuchsia, linewidth=2)
hline(1.0, "Reference 1.0", color=color.gray)
plotshape(confirmedUp, "Confirmed VI+ crossover", shape.triangleup, location.bottom, color.blue, size=size.tiny)
plotshape(confirmedDown, "Confirmed VI- crossover", shape.triangledown, location.top, color.fuchsia, size=size.tiny)
alertcondition(confirmedUp, "VI+ crossover", "VI+ crossed above VI- on a closed chart bar.")
alertcondition(confirmedDown, "VI- crossover", "VI- crossed above VI+ on a closed chart bar.")- The validity count requires n consecutive usable movements. Missing required high, low or previous-close data invalidates the window rather than silently shortening it.
- With complete prices, length 14 first produces a value on loaded bar index 14, the fifteenth bar. A crossover also needs a valid prior reading.
- A window with sum(TR)=0 returns na for both lines. Replacing that denominator with a tiny constant would manufacture a reading.
- The lines still update on an open candle. Only the markers and alert conditions wait for barstate.isconfirmed. Configure an alert with Once Per Bar Close.
Length sensitivity and settings
Changing length changes which movements enter the ratio. On the same demonstration bar 3, the values differ even though the current price is identical. These short lengths make the arithmetic visible; they are not recommended trading settings.
| Length | Movement bars | VI+ | VI- | Can bar 3 mark a cross? |
|---|---|---|---|---|
| 1 | 3 | 0 / 4 = 0.000 | 5 / 4 = 1.250 | Yes, after close |
| 2 | 2, 3 | 3 / 6 = 0.500 | 6 / 6 = 1.000 | Yes, after close |
| 3 | 1, 2, 3 | 6 / 8 = 0.750 | 7 / 8 = 0.875 | No prior valid reading |
A shorter window replaces a larger fraction of its observations each bar. A longer window retains older movement for more bars, so it can react later to a reversal. Neither choice removes whipsaws. Length counts chart bars, not calendar days: 14 hourly bars and 14 daily bars describe different histories.
For a settings study, fix the symbol, timeframe, session and trading rules first. Compare a small declared set such as 7, 14 and 21, then reserve another period for validation. Record turnover, drawdown and costs alongside returns. This page has not tested that set or established an optimal length for any asset.
From a confirmed crossover to a testable rule
Confirmation here means the chart candle has closed. It does not confirm a profitable trend. In a range, new highs and lows can alternate the two movement sums and trigger a series of opposing crossovers.
- Reproduce several closed-bar readings against TradingView's Vortex indicator with the same length and chart data. Check startup bars and gaps separately if values differ.
- Specify a complete hypothesis. For example, evaluate a long entry after a confirmed VI+ crossover and an exit after the opposite confirmed crossover. Define whether short positions are permitted, how position size is chosen and what loss limit applies.
- State execution timing before measuring results. A close-confirmed signal and its simulated fill are separate events. TradingView strategies normally fill a new market order at the next available tick, commonly the next bar's open with default bar-close calculation.
- Include commission and slippage, then test another time period. A minimum line gap or price-trend filter changes the strategy; compare its trade count and missed moves as well as any reduction in reversals.
Educational calculation and code only, not investment advice. The indicator has no position sizing, orders, exits or performance results. A successful syntax check does not validate a trading strategy or guarantee future returns.
Continue the implementation in Pineify
Give the Pine Script AI Coding Agent the example, length, desired confirmation timing and boundary rules. Ask it to preserve the two ratios and expose their values before adding strategy orders. Review the generated source, compare closed-bar outputs, and define exits and costs separately.
Open Pine Script AI Coding AgentVortex Indicator questions
Sources and related reading
Official documentation checked October 17, 2026. The worked numbers and implementation guards are this guide's demonstration.
- TradingView: Average Directional Index
- TradingView: Vortex Indicator
- TradingView: Average True Range
- Pine Script: Bar states
- Pine Script: Strategies
Browse TradingView indicator guides or compare the distinct strength measurement in the ADX guide.