mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-21 03:58:04 +00:00
153 lines
5.5 KiB
Markdown
153 lines
5.5 KiB
Markdown
# DWMA: Double Weighted Moving Average
|
|
|
|
## What It Does
|
|
|
|
The Double Weighted Moving Average (DWMA) is a smoothing indicator that applies a Weighted Moving Average (WMA) twice. By smoothing the data once and then smoothing the result again, DWMA produces an exceptionally clean curve that filters out significant market noise. The trade-off is increased lag compared to a single WMA, making it more suitable for identifying major trends rather than short-term scalping.
|
|
|
|
## Historical Context
|
|
|
|
While the concept of double smoothing dates back to the early days of technical analysis (with the Triangular Moving Average being a close cousin), the DWMA gained utility as computing power allowed traders to easily chain indicators. It represents a logical extension of the WMA for traders who found the standard WMA too jittery but appreciated its linear weighting scheme.
|
|
|
|
## How It Works
|
|
|
|
### The Core Idea
|
|
|
|
Think of DWMA as a "filter of a filter."
|
|
|
|
1. First, you calculate a standard WMA of the price. This removes high-frequency noise but leaves some jaggedness.
|
|
2. Then, you calculate a WMA of that *first* WMA. This polishes the curve, resulting in a very smooth line that clearly defines the underlying trend direction.
|
|
|
|
### Mathematical Foundation
|
|
|
|
1. Calculate the first WMA: $WMA_1 = WMA(Price, n)$
|
|
2. Calculate the second WMA: $DWMA = WMA(WMA_1, n)$
|
|
|
|
Where $n$ is the period length.
|
|
|
|
Because WMA uses linear weighting (triangle weights), applying it twice creates a weighting structure that resembles a bell curve (Gaussian-like), giving the most weight to the center of the lookback window and tapering off smoothly at both ends.
|
|
|
|
### Implementation Details
|
|
|
|
Our implementation wraps two instances of the `Wma` class.
|
|
|
|
- **Complexity:** O(1) per update (since WMA is O(1)).
|
|
- **Memory:** O(period) to store the buffers for both internal WMAs.
|
|
- **Warmup:** Requires roughly $2 \times period$ bars to fully stabilize.
|
|
|
|
## Configuration
|
|
|
|
| Parameter | Default | Purpose | Adjustment Guidelines |
|
|
|-----------|---------|---------|----------------------|
|
|
| Period | 14 | Lookback window | Shorter = Faster trend detection; Longer = Major trend identification |
|
|
|
|
**Configuration note:** A DWMA(10) will have roughly the same lag as a WMA(15-20) but will be significantly smoother.
|
|
|
|
## Performance Profile
|
|
|
|
| Operation | Complexity | Description |
|
|
|-----------|------------|-------------------|
|
|
| Streaming update | O(1) | Two O(1) WMA updates |
|
|
| Bar correction | O(1) | Efficient state rollback |
|
|
| Batch processing | O(N) | Two passes over the data |
|
|
| Memory footprint | O(period) | Two RingBuffers |
|
|
|
|
## Interpretation
|
|
|
|
### Trading Signals
|
|
|
|
#### Trend Identification
|
|
|
|
- **Major Trend:** DWMA is excellent for defining the "background" trend. If price is above DWMA, the bias is bullish.
|
|
- **Support/Resistance:** Due to its smoothness, DWMA often acts as dynamic support in uptrends and resistance in downtrends.
|
|
|
|
#### Crossovers
|
|
|
|
- **Price Crossover:** Price crossing DWMA signals a major trend change.
|
|
- **DWMA/WMA Crossover:** Using a WMA(14) crossing a DWMA(14) creates a signal similar to MACD but directly on the price chart.
|
|
|
|
### When It Works Best
|
|
|
|
- **Long-Term Trends:** DWMA filters out the "noise" of daily volatility, letting you stay in a trade during minor pullbacks.
|
|
- **Visual Clarity:** It produces a very clean line on the chart, reducing visual clutter.
|
|
|
|
### When It Struggles
|
|
|
|
- **Scalping:** The double smoothing introduces too much lag for very short-term trading.
|
|
- **Reversals:** DWMA will be slow to recognize a sharp V-bottom or V-top reversal.
|
|
|
|
## Comparison: DWMA vs WMA vs SMA
|
|
|
|
| Aspect | WMA | DWMA | SMA |
|
|
|--------|-----|------|-----|
|
|
| **Lag** | Moderate | High | High |
|
|
| **Smoothness** | Moderate | Very High | High |
|
|
| **Responsiveness** | Moderate | Low | Low |
|
|
| **Weighting** | Linear | Bell-curve-like | Equal |
|
|
|
|
**Summary:** Use DWMA when smoothness is your priority and you are willing to accept some lag to avoid false signals.
|
|
|
|
## Architecture Notes
|
|
|
|
This implementation makes specific trade-offs:
|
|
|
|
### Choice: Composition
|
|
|
|
- **Alternative:** Implement a single "Double Weighted" formula.
|
|
- **Trade-off:** Slight function call overhead.
|
|
- **Rationale:** Reusing the optimized `Wma` class ensures correctness and benefits from any future optimizations to the base WMA (like SIMD).
|
|
|
|
### Choice: Temporary Buffer for Batch
|
|
|
|
- **Alternative:** Single pass calculation.
|
|
- **Trade-off:** Memory allocation for intermediate results.
|
|
- **Rationale:** Calculating DWMA in a single pass is mathematically complex and hard to vectorize. Two optimized WMA passes are faster and easier to maintain.
|
|
|
|
## References
|
|
|
|
- Kaufman, Perry J. "Trading Systems and Methods." Wiley, 2013.
|
|
|
|
## C# Usage
|
|
|
|
### Streaming Updates (Single Instance)
|
|
|
|
```csharp
|
|
using QuanTAlib;
|
|
|
|
var dwma = new Dwma(period: 14);
|
|
|
|
// Process each new bar
|
|
TValue result = dwma.Update(new TValue(timestamp, closePrice));
|
|
Console.WriteLine($"DWMA: {result.Value:F2}");
|
|
|
|
// Check if buffer is full
|
|
if (dwma.IsHot)
|
|
{
|
|
// Indicator is fully initialized
|
|
}
|
|
```
|
|
|
|
### Batch Processing (Historical Data)
|
|
|
|
```csharp
|
|
// TSeries API
|
|
TSeries prices = ...;
|
|
TSeries dwmaValues = Dwma.Batch(prices, period: 14);
|
|
|
|
// Span API (High Performance)
|
|
double[] prices = new double[1000];
|
|
double[] output = new double[1000];
|
|
Dwma.Calculate(prices.AsSpan(), output.AsSpan(), period: 14);
|
|
```
|
|
|
|
### Bar Correction (isNew Parameter)
|
|
|
|
```csharp
|
|
var dwma = new Dwma(14);
|
|
|
|
// New bar
|
|
dwma.Update(new TValue(time, 100), isNew: true);
|
|
|
|
// Intra-bar update
|
|
dwma.Update(new TValue(time, 101), isNew: false); // Replaces 100 with 101
|
|
```
|