McGinleyDynamic — McGinley Dynamic
An average that adjusts its own speed to the gap between itself and price: the further price runs, the harder the line chases. Designed to avoid the whipsaw of a fixed-period average when the market changes pace.
Signature
McGinleyDynamic(period, on=<source>)| Argument | Type | Required | Notes |
|---|---|---|---|
period |
int Param or literal | Yes | Base speed. Default 14, bounds 1–400. |
on= |
symbol, OHLCV field, or indicator | No | Source. Defaults to the trade symbol’s close. |
Formula
$$ MD_t = MD_{t-1} + \frac{C_t - MD_{t-1}}{N,(C_t / MD_{t-1})^4} $$
The fourth power is what makes the response asymmetric: it accelerates hard when price runs away from the line.
Warmup
Starts at the first close; no window to fill.
Reading the value
md.valueself.trade.close > md.valueExample
class McGinleyTrail(Strategy): """Follow the dynamic line; it tightens automatically when price accelerates.""" period = Param(14, min=1, max=400) trade = Symbol() sizing = FixedCapital()
def execute(self): md = McGinleyDynamic(self.period, on=self.trade) if self.trade.close > md.value and self.trade.is_flat: self.buy(self.trade, reason="Above McGinley") if self.trade.close < md.value and self.trade.is_long: self.sell(self.trade, self.trade.position, reason="Below McGinley")Notes
- John R. McGinley, Journal of Technical Analysis.
- Proven by an assert-via-trade run on SPY daily (matched an independent strategy-side recursion within 0.05; zero alarm trades).
- Guarded against a non-positive line value (it would make the ratio meaningless); on that bar the line resets to price.
- A different recipe from pandas_ta’s
mcgd(10), not a different scale: measured on a 300-bar tape ours stays about 0.7 % away and never converges to it, because the construction (window offset, seed, weight normalisation) is its own.