mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-04 04:07:42 +00:00
286 lines
10 KiB
Markdown
286 lines
10 KiB
Markdown
# VR: Volatility Ratio
|
||
|
||
> *When today's range dwarfs the average, pay attention—the market is telling you something unusual is happening.*
|
||
|
||
| Property | Value |
|
||
| ---------------- | -------------------------------- |
|
||
| **Category** | Volatility |
|
||
| **Inputs** | OHLCV bar (TBar) |
|
||
| **Parameters** | `period` (default 14) |
|
||
| **Outputs** | Single series (Vr) |
|
||
| **Output range** | $\geq 0$ |
|
||
| **Warmup** | `period` bars |
|
||
| **PineScript** | [vr.pine](vr.pine) |
|
||
|
||
- Volatility Ratio (VR) measures the current bar's True Range relative to its Average True Range (ATR), providing a normalized indicator of short-ter...
|
||
- **Similar:** [HV](../hv/hv.md), [ATR](../atr/atr.md) | **Complementary:** Volatility regimes | **Trading note:** Volatility Ratio; current vs historical for regime detection.
|
||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||
|
||
Volatility Ratio (VR) measures the current bar's True Range relative to its Average True Range (ATR), providing a normalized indicator of short-term volatility expansion or contraction. Values above 1.0 indicate above-average volatility (potential breakouts), while values below 1.0 suggest below-average volatility (consolidation). This simple yet powerful ratio helps traders identify when markets are moving unusually, often preceding significant price moves.
|
||
|
||
## Historical Context
|
||
|
||
The Volatility Ratio emerged from the practical need to normalize volatility readings across different market conditions and timeframes. While ATR (developed by J. Welles Wilder Jr. in 1978) provides an absolute measure of volatility, traders needed a relative measure to answer: "Is today's movement unusual compared to recent history?"
|
||
|
||
The ratio concept is straightforward: divide today's True Range by the average True Range. This normalization allows:
|
||
1. Cross-market comparison (a VR of 2.0 means the same thing whether trading stocks, futures, or forex)
|
||
2. Breakout detection (VR > threshold signals unusual movement)
|
||
3. Volatility regime identification (sustained high/low VR indicates market character)
|
||
|
||
The implementation uses Wilder's RMA (also known as SMMA or modified EMA) with bias correction for accurate ATR calculation from the first bar.
|
||
|
||
## Architecture & Physics
|
||
|
||
### 1. True Range Calculation
|
||
|
||
True Range captures the full extent of price movement including gaps:
|
||
|
||
$$
|
||
TR_t = \max(H_t - L_t, |H_t - C_{t-1}|, |L_t - C_{t-1}|)
|
||
$$
|
||
|
||
where:
|
||
- $H_t$ = Current high
|
||
- $L_t$ = Current low
|
||
- $C_{t-1}$ = Previous close
|
||
|
||
For the first bar (no previous close), TR = High - Low.
|
||
|
||
### 2. Bias-Corrected ATR (RMA)
|
||
|
||
ATR uses Wilder's smoothing (RMA) with bias correction:
|
||
|
||
$$
|
||
\text{RMA}_{raw,t} = \alpha \cdot TR_t + (1 - \alpha) \cdot \text{RMA}_{raw,t-1}
|
||
$$
|
||
|
||
where $\alpha = 1/\text{period}$.
|
||
|
||
**Bias compensator:**
|
||
$$
|
||
e_t = (1 - \alpha)^t
|
||
$$
|
||
|
||
**Corrected ATR:**
|
||
$$
|
||
ATR_t = \frac{\text{RMA}_{raw,t}}{1 - e_t}
|
||
$$
|
||
|
||
This correction eliminates the startup bias that would otherwise cause ATR to be understated during the warmup period.
|
||
|
||
### 3. Volatility Ratio
|
||
|
||
$$
|
||
VR_t = \frac{TR_t}{ATR_t}
|
||
$$
|
||
|
||
When ATR is near zero, VR returns 0 to avoid division by zero.
|
||
|
||
## Mathematical Foundation
|
||
|
||
### True Range Properties
|
||
|
||
True Range has three components to handle gaps:
|
||
1. **H - L**: Intraday range (no gap)
|
||
2. **|H - PrevClose|**: Gap up scenario (high extends above previous close)
|
||
3. **|L - PrevClose|**: Gap down scenario (low extends below previous close)
|
||
|
||
The maximum of these three captures the full extent of price movement.
|
||
|
||
### RMA vs EMA
|
||
|
||
Wilder's RMA uses $\alpha = 1/n$ rather than EMA's $\alpha = 2/(n+1)$:
|
||
|
||
| Period | RMA α | EMA α | RMA Halflife | EMA Halflife |
|
||
| :---: | :---: | :---: | :---: | :---: |
|
||
| 14 | 0.0714 | 0.1333 | 9.6 bars | 4.8 bars |
|
||
| 20 | 0.0500 | 0.0952 | 13.9 bars | 6.9 bars |
|
||
|
||
RMA is slower to respond, providing a more stable reference for the ratio.
|
||
|
||
### Example Calculation
|
||
|
||
Period = 3, Bars with previous close = 100:
|
||
|
||
| Bar | H | L | C | TR | RMA_raw | e | ATR | VR |
|
||
| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
||
| 1 | 102 | 98 | 101 | 4.0 | 4.0 | 0.667 | 12.0 | 0.33 |
|
||
| 2 | 106 | 100 | 105 | 6.0 | 4.67 | 0.444 | 8.40 | 0.71 |
|
||
| 3 | 108 | 103 | 106 | 5.0 | 4.78 | 0.296 | 6.79 | 0.74 |
|
||
| 4 | 115 | 104 | 112 | 9.0 | 6.19 | 0.198 | 7.72 | 1.17 |
|
||
|
||
Note: Bar 4 shows VR > 1.0, indicating above-average volatility.
|
||
|
||
## Performance Profile
|
||
|
||
### Operation Count (Streaming Mode, Scalar)
|
||
|
||
Per-bar operations:
|
||
|
||
| Operation | Count | Cost (cycles) | Subtotal |
|
||
| :--- | :---: | :---: | :---: |
|
||
| SUB | 3 | 1 | 3 |
|
||
| ABS | 2 | 1 | 2 |
|
||
| MAX | 2 | 2 | 4 |
|
||
| MUL | 3 | 3 | 9 |
|
||
| DIV | 2 | 15 | 30 |
|
||
| FMA | 1 | 5 | 5 |
|
||
| **Total** | — | — | **~53 cycles** |
|
||
|
||
Extremely lightweight—dominated by two divisions.
|
||
|
||
### Batch Mode (512 values, SIMD/FMA)
|
||
|
||
| Operation | Scalar Ops | SIMD Ops (AVX2) | Speedup |
|
||
| :--- | :---: | :---: | :---: |
|
||
| TR calculation | 3584 | 448 | 8× |
|
||
| RMA smoothing | 1536 | N/A (recursive) | 1× |
|
||
| Division | 1024 | 128 | 8× |
|
||
|
||
**Batch efficiency:**
|
||
|
||
| Mode | Cycles/bar | Total (512 bars) | Notes |
|
||
| :--- | :---: | :---: | :--- |
|
||
| Scalar streaming | ~53 | ~27k | Baseline |
|
||
| Hybrid SIMD | ~35 | ~18k | TR vectorized, RMA scalar |
|
||
| **Improvement** | **34%** | **9k saved** | Limited by RMA recursion |
|
||
|
||
### Memory Profile
|
||
|
||
- **Per instance:** ~72 bytes (state record + backup)
|
||
- **100 instances:** ~7.2 KB
|
||
- **No ring buffers**: RMA is fully recursive
|
||
|
||
### Quality Metrics
|
||
|
||
| Metric | Score | Notes |
|
||
| :--- | :---: | :--- |
|
||
| **Simplicity** | 10/10 | Single ratio, intuitive interpretation |
|
||
| **Timeliness** | 10/10 | Immediate response to current bar |
|
||
| **Stability** | 8/10 | ATR smoothing provides stable denominator |
|
||
| **Signal Quality** | 8/10 | Clear breakout signals when VR > threshold |
|
||
| **Cross-Market** | 9/10 | Normalized for comparison |
|
||
|
||
## Validation
|
||
|
||
| Library | Status | Notes |
|
||
| :--- | :---: | :--- |
|
||
| **TA-Lib** | N/A | Not implemented |
|
||
| **Skender** | N/A | Not implemented |
|
||
| **Tulip** | N/A | Not implemented |
|
||
| **OoplesFinance** | N/A | Not implemented |
|
||
| **PineScript** | ✅ | Matches vr.pine reference |
|
||
| **Self-consistency** | ✅ | Streaming = Batch modes match |
|
||
|
||
## Common Pitfalls
|
||
|
||
1. **First bar handling**: On the first bar, there's no previous close. TR = H - L for this bar only, and ATR initialization uses bias correction to prevent understating early values.
|
||
|
||
2. **Warmup period**: VR needs approximately `Period` bars for ATR to stabilize. During warmup, bias correction helps but early readings may be less reliable. The implementation tracks warmup via `IsHot`.
|
||
|
||
3. **Threshold interpretation**: VR = 1.0 means "average" volatility. Common breakout thresholds:
|
||
- VR > 1.5: Moderate breakout signal
|
||
- VR > 2.0: Strong breakout signal
|
||
- VR < 0.5: Extremely low volatility (consolidation)
|
||
|
||
4. **Denominator protection**: When ATR ≈ 0 (nearly flat market), the implementation returns 0 rather than causing division errors.
|
||
|
||
5. **Scale is relative**: VR = 2.0 always means "twice normal volatility" regardless of the underlying instrument's absolute price or typical ATR value.
|
||
|
||
6. **Period selection**: Shorter periods (7-10) make ATR more responsive, causing VR to spike less dramatically. Longer periods (20-30) create a more stable baseline, making VR spikes more pronounced.
|
||
|
||
## Trading Applications
|
||
|
||
### Breakout Detection
|
||
|
||
The primary use case—identify unusual volatility expansion:
|
||
|
||
```
|
||
VR > 2.0: Potential breakout in progress
|
||
VR > 1.5 && Volume > 2×Avg: High-conviction breakout
|
||
VR < 0.7 sustained: Building energy for eventual breakout
|
||
```
|
||
|
||
### Position Sizing
|
||
|
||
Scale position size inversely with current VR:
|
||
|
||
```
|
||
Base Position × (Target_VR / Current_VR)
|
||
Example: 1000 shares × (1.0 / 2.0) = 500 shares during high volatility
|
||
```
|
||
|
||
### Stop Loss Adjustment
|
||
|
||
Widen stops when VR is elevated:
|
||
|
||
```
|
||
Stop Distance = ATR × Multiplier × VR
|
||
Higher VR → Wider stops to avoid noise
|
||
```
|
||
|
||
### Volatility Squeeze Detection
|
||
|
||
Identify consolidation before expansion:
|
||
|
||
```
|
||
VR < 0.6 for 5+ bars → Volatility squeeze
|
||
Watch for VR breakout above 1.5 to signal expansion
|
||
```
|
||
|
||
### Regime Classification
|
||
|
||
```
|
||
VR < 0.7: Low volatility (trend following works)
|
||
VR 0.7-1.3: Normal volatility (standard strategies)
|
||
VR > 1.3: High volatility (reduce size, widen stops)
|
||
VR > 2.0: Extreme volatility (defensive positioning)
|
||
```
|
||
|
||
### Entry Timing
|
||
|
||
```
|
||
Breakout entry: Wait for VR > 1.5 to confirm move
|
||
Mean reversion: Enter when VR > 2.0 starts declining
|
||
Trend following: Best when VR 1.0-1.5 (movement with stability)
|
||
```
|
||
|
||
## Relationship to Other Indicators
|
||
|
||
| Indicator | Relationship to VR |
|
||
| :--- | :--- |
|
||
| **ATR** | VR = TR/ATR; VR normalizes ATR for comparison |
|
||
| **NATR** | NATR = ATR/Close×100; VR uses TR ratio instead |
|
||
| **Bollinger Width** | Both measure volatility; VR uses TR, BB uses std dev |
|
||
| **Keltner Width** | KC uses ATR; VR provides ratio view of same data |
|
||
| **ADX** | ADX measures trend strength; VR measures volatility expansion |
|
||
| **NATR** | NATR = ATR/Close×100; VR = TR/ATR |
|
||
|
||
## Implementation Notes
|
||
|
||
### State Management
|
||
|
||
The indicator maintains a compact state record:
|
||
- `RawAtr`: Running RMA value (before bias correction)
|
||
- `ECompensator`: Bias compensator $(1-\alpha)^n$
|
||
- `PrevClose`: Previous bar's close for True Range
|
||
- `LastValidVr`: Last valid output for NaN handling
|
||
- `Count`: Bar count for warmup tracking
|
||
- `HasPrevClose`: Flag for first-bar handling
|
||
|
||
### NaN/Infinity Handling
|
||
|
||
Invalid HLC inputs are detected and the last valid VR is substituted. This prevents NaN propagation through the calculation chain.
|
||
|
||
### Numerical Stability
|
||
|
||
The implementation uses:
|
||
- Epsilon guard (1e-10) for ATR division safety
|
||
- Zero return when ATR < epsilon
|
||
- Last-valid substitution for non-finite results
|
||
|
||
## References
|
||
|
||
- Wilder, J. W. (1978). *New Concepts in Technical Trading Systems*. Trend Research.
|
||
- Kaufman, P. J. (2013). *Trading Systems and Methods* (5th ed.). John Wiley & Sons.
|
||
- Kirkpatrick, C. D., & Dahlquist, J. R. (2010). *Technical Analysis: The Complete Resource for Financial Market Technicians* (2nd ed.). FT Press. |