Relative Vigor Index (John Ehlers) — where the bar closed within its
own range, aggregated over period bars:
numerator =SWMA(close − open) SWMA= (1, 2, 2, 1) /6, 4 bars denominator =SWMA(high − low) ${prefix} =Σ numerator over period /Σ denominator over period ${prefix}Signal =SWMA(${prefix})
Appends two columns. The idea is one line long: in an uptrend markets
close near the high of the bar, in a downtrend near the low, so the body
as a fraction of the range is a measure of conviction — vigour. Both
legs are smoothed by Ehlers' 4-bar symmetric average
(symmetricWeightedValues) before being summed, which is what keeps
a single wide-range bar from swinging the ratio.
Read against its signal line: the crossover is the signal, the same
way macd's and trix's are, which is why the signal is a
column here rather than something the caller re-derives.
Reads open, high, low and close, each named by an option defaulting to
its DEFAULT_OHLCV column — the qstick and atr shapes
combined; this is the first study in the package to read all four.
Definition source
TradingView's built-in Relative Vigor Index, which is the form the
corpus describes ("SWMA-weighted (C−O)/(H−L) sums + signal") and the one
every charting vendor publishes. TA-Lib has no RVI, so the oracle is a
pandas replication of the definition above with the analytic first-valid
bar asserted per column, not a vendor cross-check.
Two details that implementations differ on, pinned here:
The smoothing is symmetric (1, 2, 2, 1)/6, not a linear wma(4)
(1, 2, 3, 4). They are different filters — the K2 engine's wma
leans on the newest bar, and this deliberately does not — so
movingAverageValues(..., 4, 'wma') is not a drop-in for it. A test
pins the difference.
The signal line is a fourth SWMA of the index, not an EMA or an
sma(4). TradingView's is swma(rvi); that is what ships.
Edges
Warm-up is per column (the macd rule): the SWMA costs 3
rows and the summation period − 1 more, so ${prefix} first appears
on bar period + 2 (bar 12 at the default 10) and ${prefix}Signal
three bars later, on period + 5. Length-preserving.
Not bounded. On consistent bars |close − open| ≤ high − low, so
the ratio sits inside ±1 and readings cluster far tighter than that —
but it is a ratio of two smoothed sums, not a normalised position, and
nothing clamps it. Do not chart it as if it were −1..1.
A window whose ranges sum to zero → undefined for both columns,
guarded explicitly. On consistent bars that is 0/0 (four bars with no
range have no bodies either); on redirected columns the numerator can
be non-zero over a zero denominator, and ±Infinity in a chart's
y-domain is worse than a gap.
Scale- and shift-invariant: numerator and denominator are both
homogeneous of degree one in price, and both are built from differences
within a bar, so adding a constant to every price changes neither.
Pinned by property tests.
A gap in any of the four inputs blanks that leg for four bars (a
positional weight cannot skip a cell), and the summation then blanks
every window containing one of those — so an interior gap costs
period + 3 bars of ${prefix} and three more of the signal, after
which both recover. Windows and fixed-width filters forget; no
recursion carries the hole to the end of the series.
Relative Vigor Index (John Ehlers) — where the bar closed within its own range, aggregated over
periodbars:Appends two columns. The idea is one line long: in an uptrend markets close near the high of the bar, in a downtrend near the low, so the body as a fraction of the range is a measure of conviction — vigour. Both legs are smoothed by Ehlers' 4-bar symmetric average (symmetricWeightedValues) before being summed, which is what keeps a single wide-range bar from swinging the ratio.
Read against its signal line: the crossover is the signal, the same way macd's and trix's are, which is why the signal is a column here rather than something the caller re-derives.
Reads open, high, low and close, each named by an option defaulting to its
DEFAULT_OHLCVcolumn — the qstick and atr shapes combined; this is the first study in the package to read all four.Definition source
TradingView's built-in
Relative Vigor Index, which is the form the corpus describes ("SWMA-weighted(C−O)/(H−L)sums + signal") and the one every charting vendor publishes. TA-Lib has no RVI, so the oracle is a pandas replication of the definition above with the analytic first-valid bar asserted per column, not a vendor cross-check.Two details that implementations differ on, pinned here:
(1, 2, 2, 1)/6, not a linearwma(4)(1, 2, 3, 4). They are different filters — the K2 engine'swmaleans on the newest bar, and this deliberately does not — somovingAverageValues(..., 4, 'wma')is not a drop-in for it. A test pins the difference.sma(4). TradingView's isswma(rvi); that is what ships.Edges
period − 1more, so${prefix}first appears on barperiod + 2(bar 12 at the default 10) and${prefix}Signalthree bars later, onperiod + 5. Length-preserving.|close − open| ≤ high − low, so the ratio sits inside ±1 and readings cluster far tighter than that — but it is a ratio of two smoothed sums, not a normalised position, and nothing clamps it. Do not chart it as if it were−1..1.undefinedfor both columns, guarded explicitly. On consistent bars that is0/0(four bars with no range have no bodies either); on redirected columns the numerator can be non-zero over a zero denominator, and±Infinityin a chart's y-domain is worse than a gap.period + 3bars of${prefix}and three more of the signal, after which both recover. Windows and fixed-width filters forget; no recursion carries the hole to the end of the series.