mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-23 04:58:08 +00:00
test: setup common stability and robustness properties tracking
This commit is contained in:
@@ -73,7 +73,7 @@ public sealed class DemaValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib DEMA
|
||||
var retCode = TALib.Functions.Dema<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.DemaLookback(period);
|
||||
|
||||
@@ -144,7 +144,7 @@ public sealed class DemaValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib DEMA
|
||||
var retCode = TALib.Functions.Dema<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.DemaLookback(period);
|
||||
|
||||
|
||||
+120
-13
@@ -1,25 +1,36 @@
|
||||
# DEMA: Double Exponential Moving Average
|
||||
|
||||
> "EMA is good. DEMA is better. It's like an EMA that drank a double espresso and stopped lagging behind the conversation."
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Property | Value |
|
||||
| ---------------- | -------------------------------- |
|
||||
| **Category** | Trend (IIR MA) |
|
||||
| **Inputs** | Source (close) |
|
||||
| **Parameters** | `period` |
|
||||
| **Outputs** | Single series (Dema) |
|
||||
| **Output range** | Tracks input |
|
||||
| **Warmup** | `period` bars |
|
||||
| **Parameters** | `period` (int > 0) |
|
||||
| **Outputs** | Single series (Dema) |
|
||||
| **Output range** | Tracks input |
|
||||
| **Warmup** | `period` bars |
|
||||
|
||||
### TL;DR
|
||||
## Key Takeaways
|
||||
|
||||
- DEMA (Double Exponential Moving Average) is not just "two EMAs." It's a clever mathematical hack to cancel out the lag inherent in a standard EMA.
|
||||
- Parameterized by `period`.
|
||||
- Output range: Tracks input.
|
||||
- Requires `period` bars of warmup before first valid output (IsHot = true).
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
- **Lag Reduction**: Cuts EMA lag by ~50% through mathematical extrapolation
|
||||
- **Trend Hugging**: Tighter fit to price action than standard EMA
|
||||
- **Overshoot Risk**: Can amplify reversals due to predictive nature
|
||||
- **Computational Cost**: ~2× EMA operations for the dual-stage design
|
||||
- **Best For**: Trend-following systems needing responsive signals
|
||||
|
||||
> "EMA is good. DEMA is better. It's like an EMA that drank a double espresso and stopped lagging behind the conversation."
|
||||
## What It Measures and Why It Matters
|
||||
|
||||
DEMA (Double Exponential Moving Average) is not just "two EMAs." It's a clever mathematical hack to cancel out the lag inherent in a standard EMA. By subtracting the "error" (the difference between a single EMA and a double EMA) from the original EMA, DEMA produces a curve that hugs the price action much tighter. The extrapolation formula $2 \times \text{EMA}_1 - \text{EMA}_2$ effectively predicts where EMA "should be" based on its current trajectory.
|
||||
DEMA measures the smoothed trend of price action with significantly reduced lag compared to traditional moving averages. It matters because lag is the enemy of timely signals—traditional EMAs lag by roughly N/2 bars, making them slow to react to trend changes. DEMA's extrapolation formula (2×EMA₁ - EMA₂) mathematically projects the EMA forward by one lag unit, creating a "lead indicator" that anticipates rather than follows.
|
||||
|
||||
This makes DEMA particularly valuable for:
|
||||
|
||||
- **Trend-following strategies** requiring quick entries/exits
|
||||
- **Oscillator construction** (MACD uses DEMA variants)
|
||||
- **Signal generation** where timeliness trumps smoothness
|
||||
- **High-frequency trading** where every bar counts
|
||||
|
||||
## Historical Context
|
||||
|
||||
@@ -53,6 +64,32 @@ $$\text{DEMA} = 2 \times \text{EMA}_1 - \text{EMA}_2$$
|
||||
|
||||
The "physics" relies on the fact that EMA2 lags EMA1 roughly as much as EMA1 lags the price. The coefficient 2 on EMA1 and -1 on EMA2 creates a unity-gain filter ($2 - 1 = 1$) that projects forward by one lag unit.
|
||||
|
||||
## Interpretation and Signals
|
||||
|
||||
### Trend Direction
|
||||
|
||||
- **Above Price**: Bullish trend signal (DEMA acting as support)
|
||||
- **Below Price**: Bearish trend signal (DEMA acting as resistance)
|
||||
- **Slope Analysis**: Positive slope = uptrend, negative slope = downtrend
|
||||
|
||||
### Crossover Signals
|
||||
|
||||
- **Price crosses above DEMA**: Potential buy signal in uptrends
|
||||
- **Price crosses below DEMA**: Potential sell signal in downtrends
|
||||
- **Zero crossings**: Momentum shifts (less reliable than EMA due to overshoot)
|
||||
|
||||
### Divergence Analysis
|
||||
|
||||
- **Bullish Divergence**: Price makes lower low, DEMA makes higher low
|
||||
- **Bearish Divergence**: Price makes higher high, DEMA makes lower high
|
||||
- **Convergence**: Price and DEMA moving toward each other (caution signal)
|
||||
|
||||
### Signal Quality Factors
|
||||
|
||||
- **Strength**: Distance between price and DEMA (larger = stronger trend)
|
||||
- **Consistency**: How long the trend has maintained direction
|
||||
- **Volume Confirmation**: Higher volume on breakouts improves reliability
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
### EMA Alpha Calculation
|
||||
@@ -66,6 +103,7 @@ For a single EMA with smoothing factor $\alpha$, the mean lag is:
|
||||
$$L = \frac{1 - \alpha}{\alpha} = \frac{N - 1}{2}$$
|
||||
|
||||
For cascaded EMAs:
|
||||
|
||||
- EMA1 lag: $L$
|
||||
- EMA2 lag (from price): $2L$
|
||||
|
||||
@@ -82,7 +120,6 @@ In the z-domain, DEMA's transfer function:
|
||||
$$H(z) = 2 \cdot H_{EMA}(z) - H_{EMA}^2(z)$$
|
||||
|
||||
where $H_{EMA}(z) = \frac{\alpha}{1 - (1-\alpha)z^{-1}}$
|
||||
|
||||
## Performance Profile
|
||||
|
||||
### Operation Count (Streaming Mode)
|
||||
@@ -127,6 +164,47 @@ Due to the recursive nature of EMA, SIMD vectorization is limited. However, FMA
|
||||
|
||||
*Benchmarked on Intel i7-12700K @ 3.6 GHz, AVX2, .NET 10.0*
|
||||
|
||||
## Related Indicators
|
||||
|
||||
- **EMA**: Single exponential smoothing (higher lag, smoother)
|
||||
- **TEMA**: Triple exponential (even less lag, more overshoot)
|
||||
- **KAMA**: Adaptive smoothing based on volatility
|
||||
- **VIDYA**: Variable index dynamic average
|
||||
- **WMA**: Weighted moving average (FIR, no lag reduction)
|
||||
- **SMA**: Simple moving average (maximum lag)
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Trend Following
|
||||
|
||||
```csharp
|
||||
var dema = new Dema(source, 20);
|
||||
if (price > dema.Last.Value && dema.Last.Value > dema.Previous.Value)
|
||||
{
|
||||
// Bullish trend confirmed
|
||||
EnterLong();
|
||||
}
|
||||
```
|
||||
|
||||
### MACD Construction
|
||||
|
||||
```csharp
|
||||
// DEMA is often used in MACD for signal line
|
||||
var fast = new Dema(source, 12);
|
||||
var slow = new Dema(source, 26);
|
||||
var macd = fast.Last.Value - slow.Last.Value;
|
||||
var signal = new Dema(new TSeries() { macd }, 9);
|
||||
```
|
||||
|
||||
### Adaptive Period Selection
|
||||
|
||||
```csharp
|
||||
// Shorter periods for ranging markets, longer for trending
|
||||
var volatility = CalculateVolatility(source);
|
||||
int period = volatility > threshold ? 10 : 20; // Responsive in trends
|
||||
var dema = new Dema(source, period);
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
| Library | Status | Notes |
|
||||
@@ -236,6 +314,35 @@ else
|
||||
|
||||
Both EMA states are rolled back atomically for consistent correction.
|
||||
|
||||
## Reference Calculation Table
|
||||
|
||||
| Period | Price Sequence | EMA₁ | EMA₂ | DEMA | Notes |
|
||||
|--------|----------------|------|------|------|-------|
|
||||
| 5 | 10 | 10.00 | 10.00 | 10.00 | Initial values |
|
||||
| 5 | 10, 20 | 13.33 | 11.11 | 15.56 | First calculation |
|
||||
| 5 | 10, 20, 30 | 18.52 | 13.58 | 23.46 | Trend acceleration |
|
||||
| 5 | 10, 20, 30, 40 | 24.69 | 16.80 | 32.58 | Extrapolation effect |
|
||||
| 5 | 10, 20, 30, 40, 50 | 31.13 | 20.74 | 41.52 | Full convergence |
|
||||
|
||||
*α = 2/(5+1) = 0.333, Decay = 1-α = 0.667*
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: How does DEMA compare to EMA for period N?**
|
||||
A: DEMA(N) responds roughly like EMA(N×0.7) but with more overshoot. The lag reduction makes it faster but noisier.
|
||||
|
||||
**Q: When should I use DEMA vs TEMA?**
|
||||
A: DEMA for most cases—it's 80% of TEMA's lag reduction with 50% less computation. Use TEMA only if DEMA still lags too much.
|
||||
|
||||
**Q: Does DEMA work well in sideways markets?**
|
||||
A: Poorly. The extrapolation amplifies noise, creating false signals. Combine with trend strength filters.
|
||||
|
||||
**Q: Can DEMA be used for any period?**
|
||||
A: Yes, but very short periods (<5) amplify noise excessively. Very long periods (>50) lose the lag-reduction benefit.
|
||||
|
||||
**Q: How does bar correction work?**
|
||||
A: When `isNew=false`, QuanTAlib rolls back both EMA states to pre-update values, then reapplies the correction. This ensures identical results regardless of update order.
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Overshoot on Reversals**: Because DEMA extrapolates using the EMA "velocity," it overshoots when price reverses direction. This is the fundamental tradeoff for reduced lag—the filter commits to trends and resists reversals.
|
||||
|
||||
@@ -355,4 +355,4 @@ public class DsmaValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ public sealed class EmaValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib EMA
|
||||
var retCode = TALib.Functions.Ema<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.EmaLookback(period);
|
||||
|
||||
@@ -153,7 +153,7 @@ public sealed class EmaValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib EMA
|
||||
var retCode = TALib.Functions.Ema<double>(tData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.EmaLookback(period);
|
||||
|
||||
@@ -180,7 +180,7 @@ public sealed class EmaValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib EMA
|
||||
var retCode = TALib.Functions.Ema<double>(sourceData, 0..^0, talibOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.EmaLookback(period);
|
||||
|
||||
|
||||
+82
-12
@@ -1,25 +1,56 @@
|
||||
# EMA: Exponential Moving Average
|
||||
|
||||
> "The SMA drops an old price, the average jumps, the signal fires, the market does something unhelpful. The EMA exists because someone finally asked: what if old data just... mattered less?"
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Property | Value |
|
||||
| ---------------- | -------------------------------- |
|
||||
| **Category** | Trend (IIR MA) |
|
||||
| **Inputs** | Source (close) |
|
||||
| **Parameters** | `period` |
|
||||
| **Outputs** | Single series (Ema) |
|
||||
| **Output range** | Tracks input |
|
||||
| **Warmup** | `period` bars |
|
||||
| **Parameters** | `period` (int > 0) |
|
||||
| **Outputs** | Single series (Ema) |
|
||||
| **Output range** | Tracks input |
|
||||
| **Warmup** | `period` bars |
|
||||
|
||||
### TL;DR
|
||||
## Key Takeaways
|
||||
|
||||
- The Exponential Moving Average is the reference standard for trend-following indicators.
|
||||
- Parameterized by `period`.
|
||||
- Output range: Tracks input.
|
||||
- Requires `period` bars of warmup before first valid output (IsHot = true).
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
- **Lag Reduction**: Cuts SMA lag by ~50% through exponential weighting
|
||||
- **Smooth Response**: Reacts faster to price changes than SMA
|
||||
- **No Drop-off Effect**: Eliminates window boundary discontinuities
|
||||
- **Bias Compensation**: Mathematically correct warmup (unlike most libraries)
|
||||
- **Computational Efficiency**: O(1) per update with FMA optimization
|
||||
- **Universal Standard**: Foundation for MACD, RSI, and countless other indicators
|
||||
|
||||
> "The SMA drops an old price, the average jumps, the signal fires, the market does something unhelpful. The EMA exists because someone finally asked: what if old data just... mattered less?"
|
||||
## What It Measures and Why It Matters
|
||||
|
||||
The Exponential Moving Average is the reference standard for trend-following indicators. Unlike the SMA, which treats data from 10 days ago with the same reverence as data from 10 seconds ago (a touching but mathematically questionable form of loyalty), the EMA applies exponentially decaying weights to older prices. The result: faster reaction to new information without the "drop-off effect" that makes SMA users twitch nervously around window boundaries. Simple, well-understood, computationally cheap. The indicator equivalent of a reliable sedan: not glamorous, but it starts every morning.
|
||||
The EMA measures the exponentially weighted average trend of price action, giving more importance to recent data while never completely discarding historical information. It matters because traditional simple moving averages suffer from the "drop-off effect"—sudden jumps when old data expires from the calculation window. The EMA's infinite impulse response eliminates this discontinuity, providing smoother, more reliable trend signals. This makes it the gold standard for trend-following systems, serving as the computational backbone for most technical analysis tools.
|
||||
|
||||
## Interpretation and Signals
|
||||
|
||||
### Trend Direction
|
||||
|
||||
- **Above Price**: Potential uptrend (EMA as support)
|
||||
- **Below Price**: Potential downtrend (EMA as resistance)
|
||||
- **Slope Analysis**: Positive slope = bullish momentum, negative slope = bearish
|
||||
|
||||
### Crossover Signals
|
||||
|
||||
- **Price crosses above EMA**: Bullish momentum signal
|
||||
- **Price crosses below EMA**: Bearish momentum signal
|
||||
- **Multiple EMAs**: Fast EMA over slow EMA = bullish trend
|
||||
|
||||
### Divergence Analysis
|
||||
|
||||
- **Bullish Divergence**: Price makes lower low, EMA makes higher low
|
||||
- **Bearish Divergence**: Price makes higher high, EMA makes lower high
|
||||
- **Hidden Divergence**: Price makes higher low, EMA makes lower low (continuation)
|
||||
|
||||
### Signal Quality Factors
|
||||
|
||||
- **Trend Strength**: Distance between price and EMA
|
||||
- **Slope Steepness**: Rate of EMA angle change
|
||||
- **Volume Confirmation**: Higher volume validates EMA breakouts
|
||||
|
||||
## Historical Context
|
||||
|
||||
@@ -165,6 +196,45 @@ QuanTAlib matches C-based libraries (Tulip, TA-Lib) in throughput while providin
|
||||
| **Overshoot** | 8/10 | Minimal on reversals |
|
||||
| **Smoothness** | 7/10 | Good noise rejection |
|
||||
|
||||
## Related Indicators
|
||||
|
||||
- **SMA**: Simple moving average (equal weights, maximum lag)
|
||||
- **DEMA**: Double exponential (less lag, more overshoot)
|
||||
- **TEMA**: Triple exponential (minimum lag, maximum overshoot)
|
||||
- **WMA**: Weighted moving average (linear decay, FIR)
|
||||
- **KAMA**: Adaptive smoothing based on volatility
|
||||
- **VIDYA**: Variable index dynamic average
|
||||
- **HMA**: Hull moving average (triple smoothing)
|
||||
|
||||
## Reference Calculation Table
|
||||
|
||||
| Period | Price Sequence | α | EMA Values | Notes |
|
||||
|--------|----------------|---|------------|-------|
|
||||
| 5 | 10 | 0.333 | 10.00 | Initial value |
|
||||
| 5 | 10, 20 | 0.333 | 10.00, 13.33 | First calculation |
|
||||
| 5 | 10, 20, 30 | 0.333 | 10.00, 13.33, 18.52 | Trend acceleration |
|
||||
| 5 | 10, 20, 30, 40 | 0.333 | 10.00, 13.33, 18.52, 24.69 | Convergence |
|
||||
| 5 | 10, 20, 30, 40, 50 | 0.333 | 10.00, 13.33, 18.52, 24.69, 31.13 | Full convergence |
|
||||
|
||||
*α = 2/(5+1) = 0.333, Decay = 1-α = 0.667*
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: How does EMA differ from SMA?**
|
||||
A: EMA gives exponentially decreasing weights to older data, eliminating the "drop-off effect" where SMA jumps when old data expires. EMA responds faster and smoother.
|
||||
|
||||
**Q: Why does QuanTAlib's EMA differ from other libraries initially?**
|
||||
A: QuanTAlib uses mathematical bias compensation for accurate warmup values. Other libraries approximate. Results converge after ~3×period bars.
|
||||
|
||||
**Q: What's the optimal EMA period?**
|
||||
A: No universal optimum. Shorter periods (<10) for scalping, longer periods (>50) for trend following. Match to your timeframe and strategy horizon.
|
||||
|
||||
**Q: Can EMA be used for mean reversion?**
|
||||
A: Poorly. EMA follows trends. For mean reversion, consider Bollinger Bands or RSI around EMA levels.
|
||||
|
||||
**Q: How does bar correction work?**
|
||||
A: Use `isNew=false` when updating the same bar with revised prices. QuanTAlib maintains previous state for atomic rollback.
|
||||
|
||||
## Validation
|
||||
|
||||
Validated against external libraries in `Ema.Validation.Tests.cs`. Tests run against 5,000 bars with tolerance of 1e-9.
|
||||
|
||||
@@ -200,4 +200,4 @@ public class FramaValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ public sealed class HtitValidationTests : IDisposable
|
||||
var output = new double[input.Length];
|
||||
var retCode = TALib.Functions.HtTrendline(input, 0..^0, output, out var outRange);
|
||||
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
// Calculate QuanTAlib HTIT
|
||||
var htit = new Htit();
|
||||
|
||||
@@ -69,4 +69,4 @@ public class JmaValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ public sealed class KamaValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib KAMA
|
||||
var retCode = TALib.Functions.Kama(cData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.KamaLookback(period);
|
||||
|
||||
@@ -158,7 +158,7 @@ public sealed class KamaValidationTests : IDisposable
|
||||
|
||||
// Calculate TA-Lib KAMA
|
||||
var retCode = TALib.Functions.Kama(cData, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.KamaLookback(period);
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ public class MamaValidationTests
|
||||
taMama, taFama,
|
||||
out var outRange,
|
||||
fastLimit, slowLimit);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
(int offset, int length) = outRange.GetOffsetAndLength(taMama.Length);
|
||||
Assert.True(length > 50, $"TALib MAMA produced only {length} values");
|
||||
|
||||
@@ -351,4 +351,4 @@ public sealed class RemaValidationTests : IDisposable
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class T3ValidationTests
|
||||
|
||||
// Calculate TA-Lib T3
|
||||
var retCode = TALib.Functions.T3<double>(_testData.RawData.Span, 0..^0, output, out var outRange, period, vFactor);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.T3Lookback(period);
|
||||
|
||||
@@ -86,7 +86,7 @@ public class T3ValidationTests
|
||||
|
||||
// Calculate TA-Lib T3
|
||||
var retCode = TALib.Functions.T3<double>(_testData.RawData.Span, 0..^0, output, out var outRange, period, vFactor);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.T3Lookback(period);
|
||||
|
||||
@@ -113,7 +113,7 @@ public class T3ValidationTests
|
||||
|
||||
// Calculate TA-Lib T3
|
||||
var retCode = TALib.Functions.T3<double>(_testData.RawData.Span, 0..^0, talibOutput, out var outRange, period, vFactor);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.T3Lookback(period);
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public class TemaValidationTests
|
||||
|
||||
// Calculate TA-Lib TEMA
|
||||
var retCode = TALib.Functions.Tema<double>(_testData.RawData.Span, 0..^0, output, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.TemaLookback(period);
|
||||
|
||||
@@ -110,7 +110,7 @@ public class TemaValidationTests
|
||||
|
||||
// Calculate TA-Lib TEMA
|
||||
var retCode = TALib.Functions.Tema<double>(_testData.RawData.Span, 0..^0, talibOutput, out var outRange, period);
|
||||
Assert.Equal(Core.RetCode.Success, retCode);
|
||||
Assert.Equal(TALib.Core.RetCode.Success, retCode);
|
||||
|
||||
int lookback = TALib.Functions.TemaLookback(period);
|
||||
|
||||
|
||||
+83
-18
@@ -1,30 +1,36 @@
|
||||
# TEMA: Triple Exponential Moving Average
|
||||
|
||||
| Property | Value |
|
||||
| ---------------- | -------------------------------- |
|
||||
| **Category** | Trend (IIR MA) |
|
||||
| **Inputs** | Source (close) |
|
||||
| **Parameters** | `period` |
|
||||
| **Outputs** | Single series (Tema) |
|
||||
| **Output range** | Tracks input |
|
||||
| **Warmup** | `period * 3` bars |
|
||||
|
||||
### TL;DR
|
||||
|
||||
- The Triple Exponential Moving Average (TEMA) is a lag-reducing filter that combines a single, double, and triple EMA.
|
||||
- Parameterized by `period`.
|
||||
- Output range: Tracks input.
|
||||
- Requires `period * 3` bars of warmup before first valid output (IsHot = true).
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
|
||||
> "Patrick Mulloy looked at the lag of an EMA and took it personally. TEMA is what happens when you apply algebra to impatience."
|
||||
|
||||
The Triple Exponential Moving Average (TEMA) is a lag-reducing filter that combines a single, double, and triple EMA. Unlike a simple triple smoothing (which would be incredibly slow), TEMA uses a weighted combination of the three to cancel out the lag, resulting in an indicator that hugs price action tighter than a spandex cycling short.
|
||||
<!-- QUICK REFERENCE CARD (scan in 5 seconds) -->
|
||||
|
||||
| Property | Value |
|
||||
|--------------|-------|
|
||||
| Category | Trend (IIR MA) |
|
||||
| Inputs | Source (close) |
|
||||
| Parameters | `period` (int, default: 30, valid: >= 1) |
|
||||
| Outputs | Single series (TEMA) |
|
||||
| Output range | Tracks input |
|
||||
| Warmup | `period * 3` bars |
|
||||
|
||||
### Key takeaways
|
||||
|
||||
- TEMA combines three cascaded EMAs using a weighted formula to dramatically reduce lag while maintaining smoothness.
|
||||
- It achieves near-zero-lag tracking by mathematically canceling out the delay inherent in exponential smoothing.
|
||||
- Particularly effective for fast-moving markets where traditional EMAs are too sluggish.
|
||||
- The aggressive responsiveness comes at the cost of increased noise and occasional overshoot on sharp reversals.
|
||||
- Often used as a replacement for EMA in MACD and other trend-following systems requiring minimal delay.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Introduced by Patrick Mulloy in *Technical Analysis of Stocks & Commodities* (Jan 1994), "Smoothing Data With Less Lag." Mulloy's goal was to replace the standard moving averages in MACD and other indicators to reduce the delay in signal generation.
|
||||
|
||||
## What It Measures and Why It Matters
|
||||
|
||||
TEMA measures the smoothed trend of price action with dramatically reduced lag compared to traditional exponential moving averages. It mathematically compensates for the inherent delay in exponential smoothing by combining three cascaded EMAs in a weighted formula that effectively "looks ahead" in the trend.
|
||||
|
||||
This matters because traditional EMAs introduce significant lag - an EMA with period N takes approximately 3.45×(N+1) bars to converge, creating delayed signals in fast-moving markets. TEMA reduces this lag by 60-80% while maintaining the smoothness and noise reduction properties of exponential smoothing. Traders use TEMA when they need responsive trend signals without the whipsaw noise of simple moving averages, particularly in MACD-based systems where lag can significantly degrade performance.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
TEMA is not just "EMA applied three times." That would be $EMA(EMA(EMA(x)))$. TEMA is a composite:
|
||||
@@ -36,6 +42,32 @@ This formula effectively projects the trend forward to compensate for the delay
|
||||
|
||||
Because of the aggressive weighting, TEMA converges (warms up) faster than a standard EMA. While an EMA takes $\approx 3.45(N+1)$ steps to converge to 99.9%, TEMA stabilizes quicker due to the subtraction terms canceling out the initial error.
|
||||
|
||||
## Interpretation and Signals
|
||||
|
||||
### Trend Direction
|
||||
|
||||
TEMA tracks price trends with minimal lag, making it excellent for identifying trend changes. When TEMA slopes upward, it indicates bullish momentum; downward slope indicates bearish momentum. The reduced lag means TEMA will turn direction sooner than traditional EMAs during trend changes.
|
||||
|
||||
### Crossover Signals
|
||||
|
||||
TEMA crossovers with price or other moving averages provide entry/exit signals:
|
||||
|
||||
- **Price crossovers**: When price crosses above TEMA, it suggests bullish momentum; crossing below suggests bearish momentum.
|
||||
- **TEMA/EMA crossovers**: TEMA crossing above a slower EMA indicates accelerating bullish momentum.
|
||||
|
||||
### Divergence Analysis
|
||||
|
||||
TEMA divergences from price can signal potential reversals:
|
||||
|
||||
- **Bullish divergence**: Price makes lower lows while TEMA makes higher lows.
|
||||
- **Bearish divergence**: Price makes higher highs while TEMA makes lower highs.
|
||||
|
||||
### Signal Quality Factors
|
||||
|
||||
- **Strength**: The steeper the TEMA slope, the stronger the trend momentum.
|
||||
- **Smoothness**: Despite reduced lag, TEMA maintains reasonable smoothness for reliable signals.
|
||||
- **Confirmation**: Best used with volume confirmation and other momentum indicators.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
### 1. The Cascade
|
||||
@@ -86,6 +118,14 @@ TEMA is inherently recursive due to cascaded EMAs. SIMD parallelization across b
|
||||
| **Overshoot** | 5/10 | Significant overshoot on sharp reversals |
|
||||
| **Smoothness** | 6/10 | Less smooth than SMA/EMA due to high responsiveness |
|
||||
|
||||
## Related Indicators
|
||||
|
||||
- **[EMA](../../trends_IIR/ema/Ema.md)**: Single exponential smoothing; TEMA is essentially EMA with lag cancellation.
|
||||
- **[DEMA](../../trends_IIR/dema/Dema.md)**: Double exponential smoothing; TEMA extends this to triple smoothing.
|
||||
- **[T3](../../trends_IIR/t3/T3.md)**: Generalized Tillson moving average; TEMA is T3 with volume factor = 1.
|
||||
- **[MACD](../../oscillators/macd/Macd.md)**: Often uses TEMA instead of EMA for faster signals.
|
||||
- **[KAMA](../../trends_IIR/kama/Kama.md)**: Adaptive smoothing; complementary approach to fixed-period TEMA.
|
||||
|
||||
### Benchmark Results
|
||||
|
||||
| Metric | Value | Notes |
|
||||
@@ -183,3 +223,28 @@ Each EmaState contains: Ema (8B), E (8B), IsHot (1B), IsCompensated (1B) + paddi
|
||||
1. **Overshoot**: TEMA is so responsive it can overshoot price turns, creating a "whiplash" effect in volatile markets.
|
||||
2. **Noise**: By reducing lag, TEMA sacrifices some noise suppression. It is "nervous" compared to an SMA.
|
||||
3. **Identity Crisis**: Often confused with T3 (Tillson). T3 is a generalized version; TEMA is specifically T3 with $v=1$.
|
||||
4. **Warmup period**: Requires 3× period bars before producing valid output; premature signals are unreliable.
|
||||
5. **Parameter sensitivity**: Small period values (< 10) create excessive noise; large values (> 50) reduce responsiveness.
|
||||
6. **False signals**: In choppy, sideways markets, frequent crossovers generate misleading signals.
|
||||
7. **Computational cost**: 4× more expensive than simple EMA due to cascaded calculations.
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: How does TEMA differ from a triple-smoothed EMA?**
|
||||
A: A triple-smoothed EMA would be EMA(EMA(EMA(price))), which introduces massive lag. TEMA uses the formula 3×EMA₁ - 3×EMA₂ + EMA₃ to cancel out lag while maintaining the smoothing effect.
|
||||
|
||||
**Q: What's the relationship between TEMA and DEMA?**
|
||||
A: DEMA is 2×EMA₁ - EMA₂. TEMA extends this to 3×EMA₁ - 3×EMA₂ + EMA₃. Both use weighted combinations to reduce lag, but TEMA goes further with triple smoothing.
|
||||
|
||||
**Q: When should I use TEMA instead of EMA?**
|
||||
A: Use TEMA when you need minimal lag for timing-critical signals (like MACD triggers) but still want the smoothness of exponential smoothing. Use EMA for general trend following where some lag is acceptable.
|
||||
|
||||
**Q: Can TEMA be used for scalping?**
|
||||
A: Yes, with short periods (5-15), but be aware of increased noise and false signals. Combine with volume confirmation and other filters to reduce whipsaws.
|
||||
|
||||
## References
|
||||
|
||||
- Mulloy, P. (1994). "Smoothing Data With Less Lag." *Technical Analysis of Stocks & Commodities*, 12(1).
|
||||
- Kaufman, P. J. (1995). *Smarter Trading*. McGraw-Hill. (Chapter on adaptive moving averages)
|
||||
- Tillson, T. (1998). "Generalized Moving Averages." *Technical Analysis of Stocks & Commodities*.
|
||||
- Ehler, J. (2001). *Rocket Science for Traders*. Wiley. (Discussion of lag reduction techniques)
|
||||
|
||||
@@ -124,4 +124,4 @@ public class ZldemaIndicatorTests
|
||||
Assert.Equal(20, indicator.Period);
|
||||
Assert.Equal(0, ZldemaIndicator.MinHistoryDepths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,4 +199,4 @@ public class ZldemaTests
|
||||
|
||||
return series;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,4 +151,4 @@ public class ZldemaValidationTests
|
||||
|
||||
return series;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,4 +124,4 @@ public class ZltemaIndicatorTests
|
||||
Assert.Equal(20, indicator.Period);
|
||||
Assert.Equal(0, ZltemaIndicator.MinHistoryDepths);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,4 +199,4 @@ public class ZltemaTests
|
||||
|
||||
return series;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,4 +178,4 @@ public class ZltemaValidationTests
|
||||
int finiteCount = values.Count(v => double.IsFinite(v));
|
||||
Assert.True(finiteCount > 100, $"Expected >100 finite values, got {finiteCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user