mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-25 05:48:06 +00:00
feat: Enhance volume indicators with ADOSC and SSF implementation and validation
This commit is contained in:
+35
-114
@@ -1,139 +1,60 @@
|
||||
# MGDI: McGinley Dynamic Indicator
|
||||
|
||||
## What It Does
|
||||
> "John McGinley saw moving averages failing in fast markets and said, 'It's not the market's fault, it's the math's fault.' MGDI is the apology."
|
||||
|
||||
The McGinley Dynamic Indicator (MGDI) is a smoothing mechanism designed to track market prices more effectively than traditional moving averages. Unlike the SMA or EMA, which use fixed time periods, the MGDI automatically adjusts its speed based on the market's velocity. It minimizes "price separation" (the gap between the price and the average) and "price hugs" (whipsaws), providing a more reliable trend line that adapts to changing volatility.
|
||||
MGDI (McGinley Dynamic Indicator) looks like a moving average, but it's actually a smoothing mechanism that adjusts itself relative to the speed of the market. It was designed to solve the problem of "lag" and "whipsaw" simultaneously by using a formula that automatically adjusts the smoothing factor based on the distance between the price and the average.
|
||||
|
||||
## Historical Context
|
||||
|
||||
Invented by John R. McGinley, a Certified Market Technician, the indicator was designed to address the flaws of conventional moving averages—specifically their inability to adjust to the speed of the market. McGinley argued that moving averages should not be relied upon as trading signals themselves but rather as a mechanism to track the market's "steering mechanism."
|
||||
Published by John McGinley in the *Market Technicians Association Journal* (1991), the Dynamic was created to be a "market tool" rather than just an indicator. McGinley argued that moving averages should not be fixed to a specific time period because the market's speed is not fixed.
|
||||
|
||||
## How It Works
|
||||
## Architecture & Physics
|
||||
|
||||
### The Core Idea
|
||||
The MGDI formula is unique. It looks like an EMA, but the smoothing constant is dynamic and depends on the ratio of Price to the previous MGDI value.
|
||||
|
||||
The MGDI incorporates an automatic adjustment factor that speeds up or slows down the indicator based on the ratio of the current price to the indicator's previous value.
|
||||
- **Price > MGDI**: The market is speeding up (or recovering). The denominator grows, slowing the adjustment to prevent overshoot.
|
||||
- **Price < MGDI**: The market is falling. The formula adapts to hug the price without breaking.
|
||||
|
||||
- **Uptrends:** When prices rise quickly, the indicator slows down to avoid overreacting to false breakouts.
|
||||
- **Downtrends:** When prices fall, the indicator speeds up to track the decline closely, reflecting the panic nature of sell-offs.
|
||||
### Zero-Allocation Design
|
||||
|
||||
### Mathematical Foundation
|
||||
The implementation is extremely lightweight.
|
||||
|
||||
The formula is recursive:
|
||||
- **State**: Only requires the previous MGDI value.
|
||||
- **Math**: Pure scalar operations. No buffers, no loops.
|
||||
|
||||
$$ MGDI_{new} = MGDI_{prev} + \frac{Price - MGDI_{prev}}{k \times N \times (\frac{Price}{MGDI_{prev}})^4} $$
|
||||
## Mathematical Foundation
|
||||
|
||||
$$ \text{MGDI}_t = \text{MGDI}_{t-1} + \frac{P_t - \text{MGDI}_{t-1}}{k \times N \times (\frac{P_t}{\text{MGDI}_{t-1}})^4} $$
|
||||
|
||||
Where:
|
||||
|
||||
- $N$ = Period (typically 14)
|
||||
- $k$ = Constant (typically 0.6, representing 60%)
|
||||
- The term $(\frac{Price}{MGDI_{prev}})^4$ is the accelerator/decelerator.
|
||||
|
||||
**Analysis of the Adjustment Factor:**
|
||||
|
||||
- If $Price > MGDI$ (Uptrend), the ratio is $>1$. Raised to the 4th power, it becomes large, increasing the denominator. A larger denominator reduces the adjustment step, making the MGDI move **slower**.
|
||||
- If $Price < MGDI$ (Downtrend), the ratio is $<1$. Raised to the 4th power, it becomes small, decreasing the denominator. A smaller denominator increases the adjustment step, making the MGDI move **faster**.
|
||||
|
||||
## Configuration
|
||||
|
||||
| Parameter | Default | Purpose | Adjustment Guidelines |
|
||||
|-----------|---------|---------|----------------------|
|
||||
| Period | 14 | Base lookback window | Standard is 14. Adjust based on the timeframe (e.g., 10 for short-term, 20+ for long-term). |
|
||||
| K | 0.6 | Sensitivity constant | 0.6 (60%) is the standard. Lower values make it more sensitive; higher values make it smoother. |
|
||||
- $N$ is the period (roughly analogous to an EMA period).
|
||||
- $k$ is a constant (usually 0.6).
|
||||
- The term $(P_t / \text{MGDI}_{t-1})^4$ is the accelerator/decelerator.
|
||||
|
||||
## Performance Profile
|
||||
|
||||
| Operation | Complexity | Description |
|
||||
|-----------|------------|-------------------|
|
||||
| Streaming update | O(1) | Constant time recursive calculation |
|
||||
| Batch processing | O(n) | Fast sequential processing |
|
||||
| Memory footprint | O(1) | Minimal state (previous value only) |
|
||||
This is one of the fastest adaptive indicators available.
|
||||
|
||||
## Interpretation
|
||||
| Metric | Score | Notes |
|
||||
| :--- | :--- | :--- |
|
||||
| **Throughput** | High | Scalar math |
|
||||
| **Complexity** | O(1) | Constant time update |
|
||||
| **Accuracy** | 9/10 | Hugs price closely without breaking |
|
||||
| **Timeliness** | 8/10 | Accelerates to catch up to price |
|
||||
| **Overshoot** | 9/10 | Specifically designed to minimize overshoot |
|
||||
| **Smoothness** | 9/10 | Visually pleasing, organic curve |
|
||||
|
||||
### Trading Signals
|
||||
## Validation
|
||||
|
||||
#### Trend Following
|
||||
Validated against standard definitions and TradingView implementations.
|
||||
|
||||
- **Support/Resistance:** The MGDI acts as a dynamic support line in uptrends and resistance in downtrends.
|
||||
- **Price Relation:**
|
||||
- Price > MGDI: Bullish bias.
|
||||
- Price < MGDI: Bearish bias.
|
||||
| Provider | Error Tolerance | Notes |
|
||||
| :--- | :--- | :--- |
|
||||
| **TradingView** | $10^{-9}$ | Matches `mcginley` |
|
||||
|
||||
#### Crossovers
|
||||
### Common Pitfalls
|
||||
|
||||
- While not primarily a crossover indicator, price crossing the MGDI can signal a trend reversal. However, due to its smoothing nature, these signals are often lagging compared to more aggressive indicators.
|
||||
|
||||
### When It Works Best
|
||||
|
||||
- **Volatile Markets:** Its ability to adjust speed makes it superior to SMA/EMA in markets with erratic volatility or sudden crashes.
|
||||
|
||||
### When It Struggles
|
||||
|
||||
- **Range-Bound Markets:** Like most trend-following indicators, it can flatten out and provide little directional insight in sideways markets.
|
||||
|
||||
### Architecture Notes
|
||||
|
||||
This implementation makes specific trade-offs:
|
||||
|
||||
### Choice: Ratio Clamping
|
||||
|
||||
- **Implementation:** The price/MGDI ratio is clamped between 0.3 and 3.0.
|
||||
- **Rationale:** Prevents the denominator from becoming effectively zero (causing explosion) or infinitely large (causing stagnation) in extreme data scenarios.
|
||||
|
||||
### Choice: Recursive State
|
||||
|
||||
- **Implementation:** Stores only the last MGDI value.
|
||||
- **Rationale:** The formula is purely recursive, requiring no historical buffer, making it extremely memory efficient.
|
||||
|
||||
## References
|
||||
|
||||
- [Investopedia: McGinley Dynamic Indicator](https://www.investopedia.com/terms/m/mcginley-dynamic.asp)
|
||||
- [Stock Indicators for .NET: McGinley Dynamic](https://dotnet.stockindicators.dev/indicators/Dynamic/)
|
||||
|
||||
## C# Usage
|
||||
|
||||
### Streaming Updates (Single Instance)
|
||||
|
||||
```csharp
|
||||
using QuanTAlib;
|
||||
|
||||
var mgdi = new Mgdi(period: 14, k: 0.6);
|
||||
|
||||
// Process each new bar
|
||||
TValue result = mgdi.Update(new TValue(timestamp, closePrice));
|
||||
Console.WriteLine($"MGDI: {result.Value:F2}");
|
||||
|
||||
// Check if buffer is full
|
||||
if (mgdi.IsHot)
|
||||
{
|
||||
// Indicator is fully initialized
|
||||
}
|
||||
```
|
||||
|
||||
### Batch Processing (Historical Data)
|
||||
|
||||
```csharp
|
||||
// TSeries API (object-oriented)
|
||||
TSeries prices = ...;
|
||||
TSeries mgdiValues = Mgdi.Batch(prices, period: 14, k: 0.6);
|
||||
|
||||
// High-performance Span API (zero allocation)
|
||||
double[] prices = new double[10000];
|
||||
double[] output = new double[10000];
|
||||
Mgdi.Calculate(prices.AsSpan(), output.AsSpan(), period: 14, k: 0.6);
|
||||
```
|
||||
|
||||
### Event-Driven Architecture
|
||||
|
||||
```csharp
|
||||
var source = new TSeries();
|
||||
var mgdi = new Mgdi(source, period: 14);
|
||||
|
||||
// Subscribe to MGDI output
|
||||
mgdi.Pub += (value) => {
|
||||
Console.WriteLine($"New MGDI value: {value.Value}");
|
||||
};
|
||||
|
||||
// Feeding source automatically triggers the chain
|
||||
source.Add(new TValue(DateTime.Now, 105.2));
|
||||
1. **Not an EMA**: Do not treat it like an EMA. It does not have a fixed alpha.
|
||||
2. **Period Meaning**: The "Period" $N$ is a calibration constant, not a hard window size. An MGDI(14) does not "look back" 14 bars in the traditional sense; it's just calibrated to that timeframe.
|
||||
3. **K Factor**: The constant $k=0.6$ is standard. Changing it changes the sensitivity.
|
||||
|
||||
Reference in New Issue
Block a user