Files
QuanTAlib/lib/channels/stbands/stbands.md
T
Miha Kralj 26280ce80b Add Choppiness Index (CHOP) implementation and tests
- Implemented ChopIndicator for Quantower with configurable period and cold value display.
- Created Chop class for calculating the Choppiness Index with detailed documentation.
- Added comprehensive unit tests for Chop functionality, covering various market conditions and edge cases.
- Developed markdown documentation for CHOP, detailing its historical context, mathematical foundation, and usage examples.
- Established a remediation plan for channel indicators documentation, identifying gaps and prioritizing updates.
2026-02-05 19:42:49 -08:00

252 lines
8.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# STBANDS: Super Trend Bands
> "The best trailing stop is one that only moves when the market agrees with you."
Super Trend Bands provide ATR-based dynamic support and resistance levels that adapt to price action. Unlike static channels, these bands only tighten in the direction of the current trend—upper bands only move down during downtrends, lower bands only move up during uptrends—creating natural trailing stop-loss levels that respect market momentum.
## Historical Context
The SuperTrend indicator emerged from the trading community's need for a volatility-adaptive trend-following tool. Olivier Seban popularized the concept, building on Wilder's ATR foundation to create bands that respect trend direction rather than blindly following price.
Traditional channel indicators like Bollinger Bands expand and contract symmetrically around price. SuperTrend takes a different approach: once a band establishes a level favorable to the trend, it refuses to retreat. This asymmetric behavior creates the "ratchet effect" that makes it useful for trailing stops.
The implementation here follows the canonical PineScript algorithm, using a simple moving average of True Range rather than Wilder's smoothed ATR, which produces slightly more responsive bands.
## 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
### 2. Average True Range (ATR)
The implementation uses a simple moving average of TR over the period:
$$
ATR_t = \frac{1}{n}\sum_{i=0}^{n-1} TR_{t-i}
$$
A ring buffer with running sum provides O(1) updates.
### 3. Basic Band Calculation
Bands center on the HL2 (typical price midpoint):
$$
\text{HL2}_t = \frac{H_t + L_t}{2}
$$
$$
\text{BasicUpper}_t = \text{HL2}_t + (k \times ATR_t)
$$
$$
\text{BasicLower}_t = \text{HL2}_t - (k \times ATR_t)
$$
where $k$ = multiplier (default 3.0)
### 4. Ratchet Logic (Final Bands)
The defining characteristic—bands only move in the favorable direction:
$$
\text{Upper}_t = \begin{cases}
\text{BasicUpper}_t & \text{if } \text{BasicUpper}_t < \text{Upper}_{t-1} \text{ OR } C_{t-1} > \text{Upper}_{t-1} \\
\text{Upper}_{t-1} & \text{otherwise}
\end{cases}
$$
$$
\text{Lower}_t = \begin{cases}
\text{BasicLower}_t & \text{if } \text{BasicLower}_t > \text{Lower}_{t-1} \text{ OR } C_{t-1} < \text{Lower}_{t-1} \\
\text{Lower}_{t-1} & \text{otherwise}
\end{cases}
$$
### 5. Trend Determination
Trend flips when price breaches the opposite band:
$$
\text{Trend}_t = \begin{cases}
+1 & \text{if } C_t \leq \text{Lower}_t \\
-1 & \text{if } C_t \geq \text{Upper}_t \\
\text{Trend}_{t-1} & \text{otherwise}
\end{cases}
$$
## Mathematical Foundation
### ATR Ring Buffer Implementation
The running sum approach avoids O(n) recalculation:
```
On new bar:
if buffer.IsFull:
trSum -= buffer.Oldest
trSum += newTR
buffer.Add(newTR)
ATR = trSum / buffer.Count
```
### Band State Transitions
The ratchet logic creates four possible state transitions per bar:
| Condition | Upper Band Action | Lower Band Action |
|:----------|:------------------|:------------------|
| Uptrend, price rising | Holds | Rises (tightens) |
| Uptrend, price falling | May drop if breaks | Holds |
| Downtrend, price falling | Drops (tightens) | Holds |
| Downtrend, price rising | Holds | May rise if breaks |
## Performance Profile
### Operation Count (Streaming Mode, Scalar)
| Operation | Count | Cost (cycles) | Subtotal |
|:----------|:-----:|:-------------:|:--------:|
| ADD/SUB | 8 | 1 | 8 |
| MUL | 2 | 3 | 6 |
| DIV | 2 | 15 | 30 |
| CMP/MAX | 6 | 1 | 6 |
| ABS | 2 | 1 | 2 |
| **Total** | **20** | — | **~52 cycles** |
The dominant cost is the two divisions (ATR calculation and HL2 normalization).
### Batch Mode (SIMD)
The recursive nature of the ratchet logic limits SIMD vectorization. However, the TR calculation across multiple bars can be parallelized:
| Operation | Scalar Ops | SIMD Ops (AVX2) | Speedup |
|:----------|:----------:|:---------------:|:-------:|
| TR calculation | 3N | 3N/8 | 8× |
| ATR (running sum) | N | N | 1× |
| Band ratchet | 4N | 4N | 1× |
**Per-bar improvement with SIMD:** ~15% for TR calculation only.
### Quality Metrics
| Metric | Score | Notes |
|:------:|:-----:|:------|
| **Accuracy** | 9/10 | Matches PineScript reference exactly |
| **Timeliness** | 8/10 | Responds within ATR period |
| **Overshoot** | 9/10 | Ratchet prevents adverse movement |
| **Smoothness** | 7/10 | ATR averaging provides moderate smoothing |
| **Memory** | 10/10 | O(period) ring buffer only |
## Validation
| Library | Status | Notes |
|:--------|:------:|:------|
| **TA-Lib** | N/A | Not implemented |
| **Skender** | N/A | SuperTrend available but different algorithm |
| **Tulip** | N/A | Not implemented |
| **Ooples** | N/A | Not implemented |
| **TradingView/PineScript** | ✅ | Reference implementation matched |
## Usage & Pitfalls
- **Warmup Period**: The indicator requires `period` bars before ATR stabilizes. During warmup, bands may appear wider than expected as the TR sample size grows.
- **Multiplier Sensitivity**: Default multiplier of 3.0 works well for daily data. Intraday charts often benefit from 2.0-2.5 to avoid bands too far from price.
- **Gap Handling**: Large overnight gaps can cause TR spikes that persist in the ATR for `period` bars, temporarily widening bands.
- **Trend Initialization**: First bar always initializes to trend = +1 (bullish). This matches PineScript behavior but may not reflect actual market state.
- **Bar Correction (isNew=false)**: When updating the same bar multiple times (intra-bar updates), the indicator properly rolls back state. Failing to set `isNew=false` for corrections will advance the indicator incorrectly.
- **NaN/Infinity Handling**: Non-finite OHLC values are replaced with the last valid close. This prevents NaN propagation but may mask data quality issues.
## API
```mermaid
classDiagram
class Stbands {
+string Name
+int WarmupPeriod
+TValue Last
+TValue Upper
+TValue Lower
+TValue Trend
+TValue Width
+bool IsHot
+Stbands(int period, double multiplier)
+TValue Update(TBar input, bool isNew)
+TValue Update(TValue input, bool isNew)
+TSeries Update(TBarSeries source)
+TSeries Update(TSeries source)
+void Reset()
+void Prime(ReadOnlySpan~double~ source, TimeSpan? step)
+static TSeries Calculate(TBarSeries source, int period, double multiplier)
+static void Calculate(ReadOnlySpan~double~ high, ReadOnlySpan~double~ low, ReadOnlySpan~double~ close, Span~double~ upper, Span~double~ lower, Span~double~ trend, int period, double multiplier)
}
```
### Class: `Stbands`
| Parameter | Type | Default | Range | Description |
| :--- | :--- | :--- | :--- | :--- |
| `period` | `int` | `10` | `≥1` | Lookback period for ATR calculation. |
| `multiplier` | `double` | `3.0` | `>0.001` | ATR multiplier for band distance from HL2. |
### Properties
- `Last` (`TValue`): Returns the trend-appropriate band (Lower when bullish, Upper when bearish).
- `Upper` (`TValue`): The upper band (resistance level).
- `Lower` (`TValue`): The lower band (support level).
- `Trend` (`TValue`): Trend direction: +1 = bullish, -1 = bearish.
- `Width` (`TValue`): Band width (Upper - Lower).
- `IsHot` (`bool`): Returns `true` when warmup period is complete.
### Methods
- `Update(TBar input, bool isNew)`: Updates the indicator with a new bar and returns the result.
- `Update(TValue input, bool isNew)`: Updates with a single value (treats as O=H=L=C).
- `Update(TBarSeries source)`: Processes an entire bar series and returns TSeries.
- `Reset()`: Resets the indicator to its initial state.
- `Prime(ReadOnlySpan<double> source, TimeSpan? step)`: Initializes from span data.
- `Calculate(TBarSeries source, int period, double multiplier)`: Static factory method.
- `Calculate(...)`: Static span-based calculation for zero-allocation processing.
## C# Example
```csharp
using QuanTAlib;
// Initialize
var stbands = new Stbands(period: 10, multiplier: 3.0);
// Update Loop
foreach (var bar in quotes)
{
stbands.Update(bar, isNew: true);
// Use valid results
if (stbands.IsHot)
{
double support = stbands.Lower.Value;
double resistance = stbands.Upper.Value;
int trend = (int)stbands.Trend.Value;
// Use trend-appropriate band as trailing stop
double trailingStop = trend > 0 ? support : resistance;
Console.WriteLine($"{bar.Time}: Stop={trailingStop:F2}, Trend={trend}");
}
}
```
## References
- Seban, O. "SuperTrend Indicator." Trading methodology documentation.
- Wilder, J. W. (1978). *New Concepts in Technical Trading Systems*. Trend Research. (ATR foundation)
- TradingView. "SuperTrend." Pine Script Reference. https://www.tradingview.com/wiki/SuperTrend