mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-23 21:18:04 +00:00
Add new moving average implementations: LTMA, MCNMA, NLMA, NMA, NYQMA, RAIN, and TRAMA
- LTMA (Linear Trend Moving Average): Introduces a predictive moving average using dual cascaded EMAs for trend estimation. - MCNMA (McNicholl EMA): Implements a zero-lag TEMA using a cascaded EMA structure for enhanced responsiveness. - NLMA (Non-Lag Moving Average): Utilizes a damped cosine kernel to achieve reduced lag in moving averages. - NMA (Natural Moving Average): Adapts smoothing based on volatility profiles using a square-root kernel. - NYQMA (Nyquist Moving Average): Applies the Nyquist-Shannon theorem to prevent aliasing in cascaded moving averages. - RAIN (Rainbow Moving Average): Combines multiple SMA layers with weighted averages for multi-scale smoothing. - TRAMA (Trend Regularity Adaptive Moving Average): Adapts smoothing based on the frequency of new highs and lows in price data.
This commit is contained in:
+80
-158
@@ -1,195 +1,117 @@
|
||||
# AMAT: Archer Moving Averages Trends
|
||||
|
||||
> "Markets trend about 30% of the time. The trick isn't just finding trends—it's confirming them before your stops get hit."
|
||||
|
||||
AMAT (Archer Moving Averages Trends) is a trend identification system that uses dual EMAs to provide clear directional signals. Unlike simple moving average crossovers that generate signals on any intersection, AMAT requires **alignment** of both fast and slow averages moving in the same direction—reducing false signals during choppy, sideways markets.
|
||||
The Archer Moving Averages Trends indicator is a triple-confirmation trend identification system that uses dual EMAs to produce discrete directional signals (+1 bullish, -1 bearish, 0 neutral). Unlike simple crossover systems that trigger on any intersection, AMAT requires alignment of three conditions: relative position (fast above/below slow), fast EMA direction (rising/falling), and slow EMA direction (rising/falling). This triple gate filters out the whipsaw endemic to single-condition crossover systems in ranging markets. A secondary output quantifies trend strength as the percentage separation between EMAs, providing a conviction metric for position sizing.
|
||||
|
||||
## Historical Context
|
||||
|
||||
AMAT emerged from concepts developed by Mark Whistler (known as "Archer" in trading circles) and was formalized by Tom Joseph in 2009. The indicator addresses a fundamental problem with traditional crossover systems: they generate excessive whipsaws in ranging markets because a crossover only measures relative position, not directional agreement.
|
||||
|
||||
The innovation lies in requiring **three conditions** for a trend signal:
|
||||
|
||||
1. Relative position (fast above/below slow)
|
||||
2. Fast EMA direction (rising/falling)
|
||||
3. Slow EMA direction (rising/falling)
|
||||
|
||||
This triple-confirmation approach filters out the noise inherent in single-condition systems.
|
||||
AMAT emerged from concepts attributed to Mark Whistler ("Archer" in trading circles) and was formalized by Tom Joseph in 2009. The indicator addresses a specific failure mode of traditional MA crossover systems: they generate excessive false signals during sideways markets because a crossover only measures relative position, not directional agreement. A fast EMA can cross above a slow EMA while both are falling — technically a "bullish crossover" but practically meaningless. AMAT's innovation is requiring all three conditions to align before committing to a directional call. The neutral state (output = 0) captures market indecision explicitly: when EMAs disagree on direction or their relative position contradicts their momentum, AMAT stays flat. Markets trend roughly 30% of the time. AMAT is designed to identify that 30% with high confidence and stay silent the other 70%.
|
||||
|
||||
## Architecture & Physics
|
||||
|
||||
AMAT operates on dual EMA calculations with directional analysis. The computational flow:
|
||||
### 1. Dual EMA Computation
|
||||
|
||||
```
|
||||
Input Price
|
||||
│
|
||||
├──► Fast EMA ───► Direction (rising/falling)
|
||||
│ │
|
||||
│ ▼
|
||||
└──► Slow EMA ───► Direction (rising/falling)
|
||||
│
|
||||
▼
|
||||
Trend Logic (+1, -1, 0)
|
||||
│
|
||||
▼
|
||||
Strength = |Fast - Slow| / Slow × 100
|
||||
```
|
||||
Two independent EMAs with bias compensation during warmup:
|
||||
|
||||
### Trend State Machine
|
||||
$$\text{EMA}_t = \alpha \cdot P_t + (1 - \alpha) \cdot \text{EMA}_{t-1}$$
|
||||
|
||||
| State | Fast vs Slow | Fast Direction | Slow Direction |
|
||||
|:------|:------------|:---------------|:---------------|
|
||||
| **Bullish (+1)** | Fast > Slow | Rising | Rising |
|
||||
| **Bearish (-1)** | Fast < Slow | Falling | Falling |
|
||||
| **Neutral (0)** | Any | Mixed | Mixed |
|
||||
where $\alpha = \frac{2}{N + 1}$
|
||||
|
||||
The neutral state captures market indecision: when EMAs disagree on direction or their relative position contradicts their momentum, AMAT stays flat. This is a feature, not a limitation.
|
||||
Bias compensation removes initialization distortion:
|
||||
|
||||
### EMA Bias Compensation
|
||||
|
||||
QuanTAlib's implementation uses bias-compensated EMAs during the warmup phase. Traditional EMA initialization assumes the first price equals the true average—a convenient fiction. The compensator factor `e` decays exponentially:
|
||||
|
||||
$$e_{t} = e_{t-1} \times (1 - \alpha)$$
|
||||
|
||||
Until convergence, the EMA is divided by $(1 - e)$ to remove initialization bias.
|
||||
|
||||
## Mathematical Foundation
|
||||
|
||||
### 1. EMA Calculation
|
||||
|
||||
$$\text{EMA}_t = \alpha \times P_t + (1 - \alpha) \times \text{EMA}_{t-1}$$
|
||||
|
||||
Where $\alpha = \frac{2}{n + 1}$ and $n$ is the period.
|
||||
$$e_t = e_{t-1} \times (1 - \alpha), \quad \text{EMA}_{\text{comp}} = \frac{\text{EMA}_t}{1 - e_t}$$
|
||||
|
||||
### 2. Direction Detection
|
||||
|
||||
$$\text{Direction}_t = \begin{cases} \text{rising} & \text{if } \text{EMA}_t > \text{EMA}_{t-1} \\ \text{falling} & \text{if } \text{EMA}_t < \text{EMA}_{t-1} \\ \text{flat} & \text{otherwise} \end{cases}$$
|
||||
$$\text{Dir}_t = \begin{cases} +1 & \text{if } \text{EMA}_t > \text{EMA}_{t-1} \\ -1 & \text{if } \text{EMA}_t < \text{EMA}_{t-1} \\ 0 & \text{otherwise} \end{cases}$$
|
||||
|
||||
### 3. Trend Signal
|
||||
### 3. Triple-Confirmation Logic
|
||||
|
||||
$$\text{Trend}_t = \begin{cases} +1 & \text{if } \text{FastEMA}_t > \text{SlowEMA}_t \land \text{FastRising} \land \text{SlowRising} \\ -1 & \text{if } \text{FastEMA}_t < \text{SlowEMA}_t \land \text{FastFalling} \land \text{SlowFalling} \\ 0 & \text{otherwise} \end{cases}$$
|
||||
$$\text{Trend}_t = \begin{cases} +1 & \text{if Fast} > \text{Slow} \;\land\; \text{FastDir} = +1 \;\land\; \text{SlowDir} = +1 \\ -1 & \text{if Fast} < \text{Slow} \;\land\; \text{FastDir} = -1 \;\land\; \text{SlowDir} = -1 \\ 0 & \text{otherwise} \end{cases}$$
|
||||
|
||||
### 4. Trend Strength
|
||||
|
||||
$$\text{Strength}_t = \frac{|\text{FastEMA}_t - \text{SlowEMA}_t|}{\text{SlowEMA}_t} \times 100$$
|
||||
$$\text{Strength}_t = \frac{|\text{Fast}_t - \text{Slow}_t|}{\text{Slow}_t} \times 100$$
|
||||
|
||||
Strength quantifies the separation between EMAs as a percentage of the slow EMA—useful for gauging trend conviction or filtering weak signals.
|
||||
### 5. Complexity
|
||||
|
||||
## Usage
|
||||
- **Time:** $O(1)$ per bar — two EMA updates plus comparisons
|
||||
- **Space:** $O(1)$ — scalar state only
|
||||
- **Warmup:** slowPeriod bars
|
||||
|
||||
```csharp
|
||||
// Standard instantiation
|
||||
var amat = new Amat(fastPeriod: 10, slowPeriod: 50);
|
||||
## Mathematical Foundation
|
||||
|
||||
// Process streaming data
|
||||
foreach (var price in prices)
|
||||
{
|
||||
amat.Update(new TValue(DateTime.UtcNow, price));
|
||||
### Parameters
|
||||
|
||||
if (amat.Last.Value == 1.0)
|
||||
Console.WriteLine($"Bullish - Strength: {amat.Strength.Value:F2}%");
|
||||
else if (amat.Last.Value == -1.0)
|
||||
Console.WriteLine($"Bearish - Strength: {amat.Strength.Value:F2}%");
|
||||
else
|
||||
Console.WriteLine("Neutral");
|
||||
}
|
||||
| Symbol | Parameter | Default | Constraint |
|
||||
|--------|-----------|---------|------------|
|
||||
| $N_f$ | fastPeriod | 10 | $N_f \geq 1$ |
|
||||
| $N_s$ | slowPeriod | 50 | $N_s > N_f$ |
|
||||
|
||||
// Access individual EMAs
|
||||
double fastEma = amat.FastEma.Value;
|
||||
double slowEma = amat.SlowEma.Value;
|
||||
### Pseudo-code
|
||||
|
||||
// Batch processing
|
||||
var results = Amat.Batch(priceSeries, fastPeriod: 10, slowPeriod: 50);
|
||||
```
|
||||
Initialize:
|
||||
α_fast = 2 / (fastPeriod + 1)
|
||||
α_slow = 2 / (slowPeriod + 1)
|
||||
ema_fast = ema_slow = 0
|
||||
e_fast = e_slow = 1.0
|
||||
prev_fast = prev_slow = 0
|
||||
bar_count = 0
|
||||
|
||||
// Span-based high-performance
|
||||
double[] trend = new double[prices.Length];
|
||||
double[] strength = new double[prices.Length];
|
||||
Amat.Calculate(prices.AsSpan(), trend, strength, fastPeriod: 10, slowPeriod: 50);
|
||||
On each bar (price, isNew):
|
||||
if !isNew: restore previous state
|
||||
|
||||
// EMA updates
|
||||
ema_fast = FMA(ema_fast, 1 - α_fast, α_fast × price)
|
||||
e_fast = e_fast × (1 - α_fast)
|
||||
fast = ema_fast / (1 - e_fast)
|
||||
|
||||
ema_slow = FMA(ema_slow, 1 - α_slow, α_slow × price)
|
||||
e_slow = e_slow × (1 - α_slow)
|
||||
slow = ema_slow / (1 - e_slow)
|
||||
|
||||
// Direction detection
|
||||
fastDir = fast > prev_fast ? +1 : fast < prev_fast ? -1 : 0
|
||||
slowDir = slow > prev_slow ? +1 : slow < prev_slow ? -1 : 0
|
||||
|
||||
// Triple-confirmation
|
||||
if fast > slow AND fastDir == +1 AND slowDir == +1:
|
||||
trend = +1
|
||||
else if fast < slow AND fastDir == -1 AND slowDir == -1:
|
||||
trend = -1
|
||||
else:
|
||||
trend = 0
|
||||
|
||||
// Strength
|
||||
strength = slow > 0 ? |fast - slow| / slow × 100 : 0
|
||||
|
||||
prev_fast = fast
|
||||
prev_slow = slow
|
||||
|
||||
output:
|
||||
Trend = trend // +1, -1, or 0
|
||||
Strength = strength // percentage
|
||||
```
|
||||
|
||||
### Event-Driven (Chained)
|
||||
### Period Selection Guidelines
|
||||
|
||||
```csharp
|
||||
var source = new TSeries();
|
||||
var amat = new Amat(source, fastPeriod: 10, slowPeriod: 50);
|
||||
| Use Case | Fast | Slow | Ratio |
|
||||
|----------|------|------|-------|
|
||||
| Scalping | 5 | 13 | 1:2.6 |
|
||||
| Swing | 10 | 50 | 1:5 |
|
||||
| Position | 20 | 100 | 1:5 |
|
||||
| Investment | 50 | 200 | 1:4 |
|
||||
|
||||
// AMAT automatically updates when source publishes
|
||||
source.Add(new TValue(DateTime.UtcNow, 100.0));
|
||||
Console.WriteLine($"Trend: {amat.Last.Value}");
|
||||
```
|
||||
Fast periods too close to slow periods produce excessive neutral readings. A ratio of 1:4 to 1:5 provides effective separation.
|
||||
|
||||
## Parameters
|
||||
### Discrete Output Properties
|
||||
|
||||
| Parameter | Type | Default | Description |
|
||||
|:----------|:-----|:--------|:------------|
|
||||
| `fastPeriod` | int | 10 | Fast EMA period (must be > 0) |
|
||||
| `slowPeriod` | int | 50 | Slow EMA period (must be > fastPeriod) |
|
||||
- **+1:** All three conditions align bullish — high-confidence uptrend
|
||||
- **-1:** All three conditions align bearish — high-confidence downtrend
|
||||
- **0:** Any disagreement — indeterminate; no position recommended
|
||||
- **Strength:** Quantifies EMA separation as percentage of slow EMA; useful for position sizing but not directional signal
|
||||
|
||||
### Common Period Combinations
|
||||
## Resources
|
||||
|
||||
| Use Case | Fast | Slow | Notes |
|
||||
|:---------|:-----|:-----|:------|
|
||||
| **Scalping** | 5 | 13 | High responsiveness, more signals |
|
||||
| **Swing** | 10 | 50 | Balanced, classic configuration |
|
||||
| **Position** | 20 | 100 | Filtered for major trends |
|
||||
| **Investment** | 50 | 200 | Long-term directional bias |
|
||||
|
||||
## Output Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
|:---------|:-----|:------------|
|
||||
| `Last` | TValue | Trend direction: +1 (bullish), -1 (bearish), 0 (neutral) |
|
||||
| `Strength` | TValue | Trend strength as percentage |
|
||||
| `FastEma` | TValue | Current fast EMA value |
|
||||
| `SlowEma` | TValue | Current slow EMA value |
|
||||
| `IsHot` | bool | True when both EMAs are fully warmed |
|
||||
| `WarmupPeriod` | int | Equal to slowPeriod |
|
||||
|
||||
## Performance Profile
|
||||
|
||||
| Metric | Score | Notes |
|
||||
|:-------|:------|:------|
|
||||
| **Throughput** | ~15 ns/bar | Dual EMA + direction check |
|
||||
| **Allocations** | 0 | Streaming mode is allocation-free |
|
||||
| **Complexity** | O(1) | Constant time per update |
|
||||
| **Accuracy** | 9/10 | Bias-compensated EMAs match external libs |
|
||||
| **Timeliness** | 7/10 | Triple-confirmation adds slight lag |
|
||||
| **Overshoot** | 8/10 | No overshoot; discrete {-1, 0, +1} output |
|
||||
| **Smoothness** | 6/10 | State transitions can be abrupt |
|
||||
|
||||
## Validation
|
||||
|
||||
AMAT is a custom indicator not present in standard TA libraries. Validation confirms:
|
||||
|
||||
| Component | Library | Status | Notes |
|
||||
|:----------|:--------|:-------|:------|
|
||||
| **Fast EMA** | TA-Lib | ✅ | Matches `TA_EMA` |
|
||||
| **Fast EMA** | Skender | ✅ | Matches `GetEma` |
|
||||
| **Slow EMA** | TA-Lib | ✅ | Matches `TA_EMA` |
|
||||
| **Slow EMA** | Skender | ✅ | Matches `GetEma` |
|
||||
| **Trend Logic** | Manual | ✅ | Verified against known patterns |
|
||||
| **Strength** | Manual | ✅ | Formula verification |
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### 1. Expecting Continuous Signals
|
||||
|
||||
AMAT returns 0 (neutral) frequently. This is intentional—choppy markets produce neutral signals. Trading systems should respect neutral states rather than forcing a directional bias.
|
||||
|
||||
### 2. Period Selection
|
||||
|
||||
Fast periods that are too close to slow periods produce excessive neutral readings. A ratio of 1:5 (e.g., 10/50) provides reasonable separation.
|
||||
|
||||
### 3. Strength Interpretation
|
||||
|
||||
High strength doesn't guarantee trend continuation. It measures current separation, not momentum. A declining strength during a +1 trend may indicate weakening conviction.
|
||||
|
||||
### 4. Initialization Phase
|
||||
|
||||
Until `IsHot` returns true, trend signals may be unreliable. The indicator needs `slowPeriod` bars to stabilize both EMAs.
|
||||
|
||||
## See Also
|
||||
|
||||
- [EMA](../trends/ema/Ema.md) - Exponential Moving Average (AMAT's building block)
|
||||
- [MACD](../momentum/macd/Macd.md) - Another dual-EMA system with different logic
|
||||
- [ADX](../momentum/adx/Adx.md) - Trend strength without directional bias
|
||||
- Joseph, T. — AMAT trend confirmation methodology (2009)
|
||||
- PineScript reference: `amat.pine` in indicator directory
|
||||
|
||||
Reference in New Issue
Block a user