Vortex Indicator (VI)

Haiyue
10min

I. What is the Vortex Indicator

The Vortex Indicator (VI) was first published in 2010 by Swiss engineer Etienne Botes and market analyst Douglas Siepman in the Technical Analysis of Stocks & Commodities magazine.

The Vortex Indicator belongs to the Trend Direction class of indicators. It identifies the direction and turning points of a trend by comparing Positive Vortex Movement (+VM) and Negative Vortex Movement (-VM). The default period is n=14n = 14.

The indicator draws its inspiration from Austrian naturalist Viktor Schauberger (1885—1958) and his research on vortex movements in water. Schauberger observed that water flow contains both positive and negative vortex forces. Botes and Siepman applied this natural phenomenon as an analogy to financial market price movements: the forces of rising and falling prices behave like two intertwined vortex streams.

Tip

The core idea of the Vortex Indicator is: in a strong uptrend, the distance between the current high and the previous low (positive vortex force) will consistently exceed the distance between the current low and the previous high (negative vortex force), and vice versa.


II. Mathematical Principles and Calculation

2.1 Vortex Movement (VM)

Positive Vortex Movement (+VM):

+VMt=HtLt1+\text{VM}_t = |H_t - L_{t-1}|

Negative Vortex Movement (-VM):

VMt=LtHt1-\text{VM}_t = |L_t - H_{t-1}|

Where HtH_t is the current high, LtL_t is the current low, and Ht1H_{t-1} and Lt1L_{t-1} are the previous bar’s high and low respectively.

2.2 True Range (TR)

TRt=max(HtLt,  HtCt1,  LtCt1)\text{TR}_t = \max\bigl(H_t - L_t,\; |H_t - C_{t-1}|,\; |L_t - C_{t-1}|\bigr)

2.3 Vortex Indicators (+VI / -VI)

Sum +VM, -VM, and TR over nn periods respectively:

+VIt=i=0n1+VMtii=0n1TRti+\text{VI}_t = \frac{\sum_{i=0}^{n-1} +\text{VM}_{t-i}}{\sum_{i=0}^{n-1} \text{TR}_{t-i}} VIt=i=0n1VMtii=0n1TRti-\text{VI}_t = \frac{\sum_{i=0}^{n-1} -\text{VM}_{t-i}}{\sum_{i=0}^{n-1} \text{TR}_{t-i}}
Note

Note that the Vortex Indicator uses rolling sums rather than moving averages. The values of +VI and -VI typically fluctuate between 0.7 and 1.3. Using TR as the denominator provides normalization, making the indicator comparable across instruments with different volatility levels.

2.4 Calculation Steps Summary

  1. Calculate +VM = |current high - previous low| for each bar
  2. Calculate -VM = |current low - previous high| for each bar
  3. Calculate the True Range for each bar
  4. Sum +VM, -VM, and TR over period nn respectively
  5. +VI = Sum(+VM) / Sum(TR)
  6. -VI = Sum(-VM) / Sum(TR)

III. Python Implementation

import numpy as np
import pandas as pd

def vortex(high: pd.Series, low: pd.Series, close: pd.Series,
           period: int = 14) -> pd.DataFrame:
    """
    Calculate the Vortex Indicator.

    Parameters:
        high   : Series of high prices
        low    : Series of low prices
        close  : Series of closing prices
        period : Rolling sum period, default 14

    Returns:
        DataFrame containing plus_vi, minus_vi columns
    """
    # Vortex Movement
    plus_vm = (high - low.shift(1)).abs()
    minus_vm = (low - high.shift(1)).abs()

    # True Range
    prev_close = close.shift(1)
    tr1 = high - low
    tr2 = (high - prev_close).abs()
    tr3 = (low - prev_close).abs()
    tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)

    # Rolling sums
    sum_plus_vm = plus_vm.rolling(window=period).sum()
    sum_minus_vm = minus_vm.rolling(window=period).sum()
    sum_tr = tr.rolling(window=period).sum()

    # Vortex Indicators
    plus_vi = sum_plus_vm / sum_tr
    minus_vi = sum_minus_vm / sum_tr

    return pd.DataFrame({
        'plus_vi': plus_vi,
        'minus_vi': minus_vi
    })


# ============ Usage Example ============
if __name__ == '__main__':
    np.random.seed(42)
    n_days = 120

    # Generate simulated OHLCV data with alternating trends
    trend = np.concatenate([
        np.linspace(0, 8, 40),     # Uptrend
        np.linspace(8, 3, 40),     # Downtrend
        np.linspace(3, 10, 40)     # Uptrend
    ])
    noise = np.cumsum(np.random.randn(n_days) * 0.2)
    base_price = 50 + trend + noise

    df = pd.DataFrame({
        'open':   base_price + np.random.randn(n_days) * 0.2,
        'high':   base_price + np.abs(np.random.randn(n_days) * 0.5),
        'low':    base_price - np.abs(np.random.randn(n_days) * 0.5),
        'close':  base_price,
        'volume': np.random.randint(1000, 10000, n_days)
    })

    # Calculate Vortex Indicator
    vi = vortex(df['high'], df['low'], df['close'], period=14)
    df = pd.concat([df, vi], axis=1)

    print("=== Vortex Indicator Results (Last 10 Rows) ===")
    print(df[['close', 'plus_vi', 'minus_vi']].tail(10).round(4).to_string())

    # Crossover signal detection
    df['signal'] = np.nan
    valid = df.dropna(subset=['plus_vi', 'minus_vi'])
    for i in range(1, len(valid)):
        idx = valid.index[i]
        prev_idx = valid.index[i - 1]
        if (valid.loc[idx, 'plus_vi'] > valid.loc[idx, 'minus_vi'] and
            valid.loc[prev_idx, 'plus_vi'] <= valid.loc[prev_idx, 'minus_vi']):
            df.loc[idx, 'signal'] = 1   # Bullish crossover
        elif (valid.loc[idx, 'minus_vi'] > valid.loc[idx, 'plus_vi'] and
              valid.loc[prev_idx, 'minus_vi'] <= valid.loc[prev_idx, 'plus_vi']):
            df.loc[idx, 'signal'] = -1  # Bearish crossover

    signals = df.dropna(subset=['signal'])
    print(f"\n=== Crossover Signals (Total: {len(signals)}) ===")
    for _, row in signals.iterrows():
        direction = "Bullish (+VI crosses above -VI)" if row['signal'] == 1 else "Bearish (-VI crosses above +VI)"
        print(f"  Price={row['close']:.2f}  +VI={row['plus_vi']:.4f}  -VI={row['minus_vi']:.4f}  {direction}")

IV. Problems the Indicator Solves

4.1 Trend Direction Identification

The Vortex Indicator directly reflects trend direction through the relative position of +VI and -VI:

  • +VI > -VI: uptrend dominates, positive vortex force is stronger
  • -VI > +VI: downtrend dominates, negative vortex force is stronger
  • +VI approx -VI: market direction is unclear, possibly in consolidation

4.2 Trend Reversal Signals

Crossovers of +VI and -VI provide early signals of trend reversals:

  • +VI crosses above -VI: bullish signal, a potential shift from downtrend to uptrend
  • -VI crosses above +VI: bearish signal, a potential shift from uptrend to downtrend

4.3 Trend Strength Assessment

The wider the gap between +VI and -VI, the more defined the trend:

ConditionInterpretation
+VI and -VI gap is large (> 0.2)Strong and well-defined trend
+VI and -VI gap is small (< 0.1)Weak trend or trend transition in progress
Two lines intertwinedRange-bound market, no clear trend
Warning

In sideways, range-bound markets, +VI and -VI will cross frequently, generating numerous false signals. It is recommended to combine with ADX or other trend strength indicators for filtering: only execute Vortex crossover signals when ADX > 20.

4.4 Typical Trading Strategies

  1. Basic Crossover Strategy: go long when +VI crosses above -VI; go short when -VI crosses above +VI
  2. Threshold Filter Strategy: only confirm a bullish signal when +VI exceeds a threshold (e.g., 1.10)
  3. Multi-Indicator Confirmation Strategy: enter when Vortex crossover + moving average direction agree + ADX > 25
  4. Stop-Loss Strategy: use the swing low/high before the crossover point as the stop-loss level

V. Advantages, Disadvantages, and Use Cases

Advantages

AdvantageDescription
Simple and intuitive calculationOnly requires summation and division; no complex recursive smoothing
Clear signals+VI and -VI crossovers provide unambiguous trend change signals
Captures gapsNormalized through True Range, correctly reflects the impact of price gaps
Good symmetryThe calculation structure of +VI and -VI is perfectly symmetric, treating both bullish and bearish directions equally

Disadvantages

DisadvantageDescription
Many false signals in range-bound marketsFrequent crossovers during sideways action, low signal reliability
Does not quantify trend strengthUnlike ADX, it does not provide a 0—100 strength reading
Period sensitivityToo short a period increases noise; too long reduces responsiveness
Lacks built-in filtering mechanismRequires additional indicators for confirmation

Use Cases

  • Best suited for: capturing trend direction and reversals in clearly trending markets
  • Well suited for: serving as a directional confirmation component in multi-indicator systems
  • Not suited for: low-volatility, range-bound markets

Comparison with Similar Indicators

IndicatorSignal MethodCharacteristics
Vortex Indicator+VI/-VI crossoverSimple calculation; inspired by natural vortex movement
ADX/DMI+DI/-DI crossover + ADX strengthMore comprehensive (direction + strength); but more lagging
AroonAroon Up/Down crossoverBased on position of highs/lows; faster response
MACDSignal line crossoverBased on moving average difference; more momentum-focused
Tip

Parameter Tuning Recommendations: The default 14-period setting is suitable for daily chart analysis. Botes and Siepman suggest adjusting for different time frames: use 21—34 periods for weekly charts, and 7—14 periods for hourly charts. If you encounter too many false signals, consider increasing the period for smoother output. You can also add a simple “signal confirmation” rule — wait 1—2 bars after the crossover to confirm the direction before entering.