What it does
Vortex Trend plots the two lines of the Vortex Indicator, VI+ and VI-, which compare upward and downward price movement against total range. When VI+ is above VI-, upward movement dominates; when VI- is above, downward movement dominates.
Raw vortex crosses can be frequent, so this version adds two filters: optional EMA smoothing of both lines and a minimum separation. The trend state flips only when one line leads the other by more than that margin, and it stays put while the lines tangle inside it.
How it works
Over a length of n bars:
- Positive vortex movement VM+ = sum of |current high − previous low|.
- Negative vortex movement VM- = sum of |current low − previous high|.
- True range sum = sum of the true range.
- VI+ = VM+ ÷ true range sum; VI- = VM- ÷ true range sum.
Both lines are then smoothed with an EMA of the chosen length (1 leaves them unsmoothed). The spread is VI+ − VI-.
Trend state works with hysteresis: it becomes bullish when the spread rises above the minimum separation, bearish when it falls below the negative of it, and otherwise keeps its previous value. A marker prints when the state flips, confirmed on bar close. The spread is visible in the Data Window.
How to use it
- A bullish flip shows that upward movement now clearly outweighs downward movement. Many traders use it as a trend filter rather than a precise entry, looking for entries in the flip direction on pullbacks.
- Increase the minimum separation on noisy instruments to reduce flips; set it to 0 to get every cross of the smoothed lines.
- Lines far apart and widening describe a strong trend; lines converging warn that momentum is fading.
- It suits H1–D1 charts on liquid markets. Pair it with a level-based plan and the risk-reward ratio you intend to use.
Settings
| Input | Default | What it changes |
|---|---|---|
| Vortex length | 14 | Window for movement and range sums. |
| Smoothing (EMA, 1 = off) | 3 | Smoothness of both VI lines. |
| Minimum separation | 0.02 | Size of the no-flip band. Higher = fewer flips. |
| Show trend-flip markers | On | Triangles on state flips. |
| Shade background by state | On | Background tint by state. |
| VI+ / VI- colors | teal / red | Line and marker colors. |
Limitations
- Smoothing and the separation band both add delay; flips come later than raw vortex crosses.
- The default separation is a starting point. The typical spread differs between instruments and timeframes, so tune it on your own chart.
- Large single bars, such as news spikes, distort the sums for the whole lookback window.
- In ranges the lines often hover close together; the filter reduces flips there but cannot tell you when a range will break.
Pine Script source
In TradingView open Pine Editor, paste the code, click Save and then Add to chart.
FXP_VortexTrend.pine
56 lines
// © FXPIPS ONLINE — https://fxpips.online/tradingview-indicators/vortex-trend/
// License: MIT. Educational tool — not financial advice. Trading involves substantial risk.
//@version=6
// Vortex Indicator (VI+ / VI-) with optional EMA smoothing and a minimum-separation filter:
// the trend state only flips when the gap between the lines exceeds the filter, which cuts
// back-and-forth crosses. State flips confirm on bar close.
indicator("FXP Vortex Trend", shorttitle = "FXP Vortex", overlay = false)
// ── Inputs ─────────────────────────────────────────────────────────────
grpV = "Vortex"
len = input.int(14, "Vortex length", minval = 2, group = grpV)
smoothLen = input.int(3, "Smoothing (EMA, 1 = off)", minval = 1, group = grpV)
minGap = input.float(0.02, "Minimum separation", minval = 0.0, step = 0.005, group = grpV, tooltip = "VI+ must lead VI- by this much (or the reverse) before the trend state flips. 0 = flip on every cross.")
grpD = "Display"
showSignals = input.bool(true, "Show trend-flip markers", group = grpD)
showBg = input.bool(true, "Shade background by state", group = grpD)
colPlus = input.color(#26a69a, "VI+ / bullish", group = grpD)
colMinus = input.color(#ef5350, "VI- / bearish", group = grpD)
// ── Calculation ────────────────────────────────────────────────────────
vmPlus = math.sum(math.abs(high - low[1]), len)
vmMinus = math.sum(math.abs(low - high[1]), len)
trSum = math.sum(ta.tr(true), len)
viPlusRaw = trSum > 0 ? vmPlus / trSum : na
viMinusRaw = trSum > 0 ? vmMinus / trSum : na
viPlus = ta.ema(viPlusRaw, smoothLen)
viMinus = ta.ema(viMinusRaw, smoothLen)
spread = viPlus - viMinus
// Hysteresis state: 1 bullish, -1 bearish, holds until the opposite side leads by minGap
var int state = 0
if spread > minGap
state := 1
else if spread < -minGap
state := -1
prevState = nz(state[1])
bullFlip = state == 1 and prevState != 1 and barstate.isconfirmed
bearFlip = state == -1 and prevState != -1 and barstate.isconfirmed
// ── Plots ──────────────────────────────────────────────────────────────
plot(viPlus, "VI+", color = colPlus, linewidth = 2)
plot(viMinus, "VI-", color = colMinus, linewidth = 2)
plot(spread, "VI spread", display = display.data_window)
hline(1.0, "Unity", color = color.new(color.gray, 60), linestyle = hline.style_dotted)
bgcolor(showBg and state == 1 ? color.new(colPlus, 92) : showBg and state == -1 ? color.new(colMinus, 92) : na, title = "Trend state background")
plotshape(showSignals and bullFlip, "Bullish flip", style = shape.triangleup, location = location.bottom, color = colPlus, size = size.small)
plotshape(showSignals and bearFlip, "Bearish flip", style = shape.triangledown, location = location.top, color = colMinus, size = size.small)
// ── Alerts ─────────────────────────────────────────────────────────────
alertcondition(bullFlip, "Vortex bullish flip", "Vortex trend turned bullish on {{ticker}} ({{interval}})")
alertcondition(bearFlip, "Vortex bearish flip", "Vortex trend turned bearish on {{ticker}} ({{interval}})")

