McGinley Dynamic
I. What is McGinley Dynamic
The McGinley Dynamic (MD) is an adaptive moving average that automatically adjusts its tracking speed based on market velocity. It was invented in 1990 by American technical analyst John R. McGinley and published in the Journal of Technical Analysis.
Historical Background
Through extensive research on moving averages, McGinley identified a core problem: no matter which fixed-period moving average you choose, it is always too fast or too slow under certain market conditions. Market speed (volatility and trend strength) is dynamic, but traditional moving average parameters are fixed.
To address this, McGinley designed a moving average that can “sense” market speed and adjust automatically. When the market moves rapidly, MD accelerates tracking; when the market moves slowly or consolidates, MD decelerates to avoid false signals. This adaptive behavior is achieved through the term in the formula.
Indicator Classification
- Type: Overlay indicator, plotted on the price chart
- Category: Moving Averages, adaptive subcategory
- Default Parameters: Period , adjustment coefficient , data source is closing price (Close)
McGinley himself described his indicator as “a smoothing mechanism that happens to track prices far more closely than any moving average.” He argued that MD should not be viewed as a moving average, but rather as a “price smoothing tool.”
II. Mathematical Principles and Calculation
Core Formula
The recursive formula for McGinley Dynamic is:
Where:
- : Price at period (closing price)
- : McGinley Dynamic value from the previous period
- : Period parameter (default 14)
- : Adjustment constant (default 0.6, as recommended by McGinley in his paper)
The initial value is typically set to the first price: .
Adaptive Mechanism Explained
The key to the formula lies in the denominator’s term. Let us analyze its behavior:
When price rises rapidly ():
- , and this ratio raised to the 4th power is large
- The denominator increases
- The update step decreases relatively
- But since the numerator is also large, the net effect is that MD accelerates upward
When price drops rapidly ():
- , and this ratio raised to the 4th power is small
- The denominator decreases
- The update step increases relatively
- The negative numerator combined with the small denominator causes MD to drop rapidly
When price is near MD ():
- , the 4th power term is approximately 1
- The denominator is approximately
- Behavior resembles an EMA with period
McGinley determined through experimentation that the 4th power provides the optimal adaptive effect. Lower powers (such as squared) provide insufficient adjustment, while higher powers (such as 6th power) overreact. The 4th power is the empirically selected optimum.
Role of Parameter
is McGinley’s recommended value:
- Smaller -> MD responds faster
- Larger -> MD responds slower
- provides a good balance in most market environments
Comparison with EMA
Writing EMA in a similar recursive form:
Compare with MD:
The difference is that MD’s “effective period” is dynamic, while EMA’s effective period is fixed.
III. Python Implementation
import numpy as np
import pandas as pd
def mcginley_dynamic(close: pd.Series, period: int = 14,
k: float = 0.6) -> pd.Series:
"""
Calculate the McGinley Dynamic indicator
Parameters
----------
close : pd.Series
Closing price series
period : int
Period parameter, default is 14
k : float
Adjustment coefficient, default is 0.6
Returns
-------
pd.Series
McGinley Dynamic value series
"""
values = close.values.astype(float)
n = len(values)
result = np.full(n, np.nan)
# Initial value
result[0] = values[0]
for i in range(1, n):
md_prev = result[i - 1]
p = values[i]
if md_prev == 0 or np.isnan(md_prev):
result[i] = p
continue
ratio = p / md_prev
denominator = k * period * (ratio ** 4)
if denominator == 0:
result[i] = p
else:
result[i] = md_prev + (p - md_prev) / denominator
return pd.Series(result, index=close.index, name=f"MD_{period}")
def mcginley_dynamic_numpy(close: np.ndarray, period: int = 14,
k: float = 0.6) -> np.ndarray:
"""
McGinley Dynamic implementation using numpy (low-level version)
"""
n = len(close)
result = np.full(n, np.nan)
result[0] = close[0]
for i in range(1, n):
md = result[i - 1]
p = close[i]
if md <= 0 or np.isnan(md):
result[i] = p
continue
ratio = p / md
denom = k * period * (ratio ** 4)
result[i] = md + (p - md) / max(denom, 1e-10)
return result
# ========== Usage Example ==========
if __name__ == "__main__":
np.random.seed(42)
dates = pd.date_range("2024-01-01", periods=150, freq="D")
# Construct a price series with trends and consolidation
trend = np.concatenate([
np.linspace(0, 10, 50), # Uptrend
np.linspace(10, 8, 30), # Slow pullback
np.random.randn(30) * 0.3, # Consolidation
np.linspace(0, -8, 40), # Downtrend
])
price = 100 + trend + np.random.randn(150) * 0.5
df = pd.DataFrame({
"date": dates,
"open": price + np.random.randn(150) * 0.2,
"high": price + np.abs(np.random.randn(150) * 0.5),
"low": price - np.abs(np.random.randn(150) * 0.5),
"close": price,
"volume": np.random.randint(1000, 10000, size=150),
})
df.set_index("date", inplace=True)
# MD compared with EMA/SMA
df["SMA_14"] = df["close"].rolling(14).mean()
df["EMA_14"] = df["close"].ewm(span=14, adjust=False).mean()
df["MD_14"] = mcginley_dynamic(df["close"], period=14, k=0.6)
print("=== SMA vs EMA vs McGinley Dynamic Comparison ===")
print(df[["close", "SMA_14", "EMA_14", "MD_14"]].tail(15))
# Compare different k values
df["MD_k04"] = mcginley_dynamic(df["close"], 14, k=0.4)
df["MD_k06"] = mcginley_dynamic(df["close"], 14, k=0.6)
df["MD_k10"] = mcginley_dynamic(df["close"], 14, k=1.0)
print("\n=== McGinley Dynamic with Different k Values ===")
print(df[["close", "MD_k04", "MD_k06", "MD_k10"]].tail(10))
# Trend signal
df["md_signal"] = np.where(df["close"] > df["MD_14"], "LONG", "SHORT")
print("\n=== MD Trend Signal ===")
print(df[["close", "MD_14", "md_signal"]].tail(10))
IV. Problems the Indicator Solves
1. Fundamental Flaw of Fixed-Period Moving Averages
The core dilemma faced by traditional moving averages:
- Short period -> Performs well in trends, but generates many false signals during consolidation
- Long period -> Fewer false signals during consolidation, but lags significantly in trends
MD simultaneously addresses both problems through its adaptive mechanism: automatically accelerating in trends (effectively shorter period) and automatically decelerating during consolidation (effectively longer period).
2. Eliminating Whipsaws
In ranging markets, price frequently crosses moving averages, creating whipsaw signals. Since MD automatically slows down during consolidation and stays close to price, it dramatically reduces these false crossovers.
3. Adaptive Trailing Stop
MD serves as an excellent trailing stop-loss line:
- Closely follows price during trending moves
- Remains stable during price consolidation
- No manual parameter adjustment needed
4. Trend Filter
Using MD as a trend filter:
- Price above MD -> Long only
- Price below MD -> Short only
Due to MD’s adaptive nature, this filtering is more reliable than a fixed EMA.
MD’s greatest advantage is “set it and forget it.” Traditional moving averages often require period parameter adjustments across different market environments, whereas MD’s adaptive mechanism automatically handles this adjustment.
V. Advantages, Disadvantages, and Use Cases
Advantages
| Advantage | Description |
|---|---|
| Adaptive speed | Automatically adjusts tracking speed based on market conditions |
| Reduced whipsaws | Produces very few false crossover signals in ranging markets |
| Tight price tracking | Follows current price more closely than same-period EMA |
| Robust parameters | Default parameters perform well across most markets without frequent tuning |
Disadvantages
| Disadvantage | Description |
|---|---|
| Asymmetry | Due to the nonlinear term, behavior during up and down moves is not perfectly symmetric |
| Non-standard | Not built into all trading platforms |
| Opaque theory | The 4th power and choices are based more on empirical testing than rigorous derivation |
| Hard to combine | Unlike EMA, not easily used as a building component for other indicators |
Use Cases
- Trend following: As a primary trend identification tool
- Trailing stop-loss: As an adaptive stop-loss reference line
- Multi-market strategies: A single set of parameters works across multiple markets, reducing optimization effort
- Medium to long-term trading: Performs best on daily and higher timeframes
Comparison with Other Adaptive Moving Averages
| Feature | MD | KAMA | FRAMA |
|---|---|---|---|
| Adaptation basis | Price/MA ratio | Efficiency ratio | Fractal dimension |
| Formula complexity | Simple | Medium | High |
| Number of parameters | 2 (n, k) | 3 (n, fast, slow) | 2 (n, batch) |
| Smoothness | High | High | Medium |
| Popularity | Medium | Higher | Low |
- MD’s denominator contains . When price approaches zero or MD approaches zero, numerical instability may occur. Add protective logic when handling low-priced stocks or cryptocurrencies.
- MD is not suitable for smoothing oscillator-type indicators (such as RSI), because its adaptive mechanism is designed for trending prices.
- The choice of initial value () affects the first few periods of calculation, but the impact vanishes after sufficient data.