Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: aider (openrouter/anthropic/claude-sonnet-4) <aider@aider.chat> Co-authored-by: Warp <agent@warp.dev>
7.7 KiB
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.
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:
- Relative position (fast above/below slow)
- Fast EMA direction (rising/falling)
- Slow EMA direction (rising/falling)
This triple-confirmation approach filters out the noise inherent in single-condition systems.
Architecture & Physics
AMAT operates on dual EMA calculations with directional analysis. The computational flow:
Input Price
│
├──► Fast EMA ───► Direction (rising/falling)
│ │
│ ▼
└──► Slow EMA ───► Direction (rising/falling)
│
▼
Trend Logic (+1, -1, 0)
│
▼
Strength = |Fast - Slow| / Slow × 100
Trend State Machine
| 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 |
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.
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.
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}
3. Trend Signal
\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}
4. Trend Strength
\text{Strength}_t = \frac{|\text{FastEMA}_t - \text{SlowEMA}_t|}{\text{SlowEMA}_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.
Usage
// Standard instantiation
var amat = new Amat(fastPeriod: 10, slowPeriod: 50);
// Process streaming data
foreach (var price in prices)
{
amat.Update(new TValue(DateTime.UtcNow, price));
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");
}
// Access individual EMAs
double fastEma = amat.FastEma.Value;
double slowEma = amat.SlowEma.Value;
// Batch processing
var results = Amat.Batch(priceSeries, fastPeriod: 10, slowPeriod: 50);
// 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);
Event-Driven (Chained)
var source = new TSeries();
var amat = new Amat(source, fastPeriod: 10, slowPeriod: 50);
// AMAT automatically updates when source publishes
source.Add(new TValue(DateTime.UtcNow, 100.0));
Console.WriteLine($"Trend: {amat.Last.Value}");
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
fastPeriod |
int | 10 | Fast EMA period (must be > 0) |
slowPeriod |
int | 50 | Slow EMA period (must be > fastPeriod) |
Common Period Combinations
| 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.