Skip to content
Open RaamTrade

CoppockCurve — Coppock Curve

A weighted average of two long rates of change. Coppock built it to time bottoms in monthly index data — an economist’s answer to “when has the market finished mourning” — and it is still read that way: the turn up from below zero is the signal.

Signature

CoppockCurve(long_roc, short_roc, wma_period, on=<source>)
Argument Type Required Notes
long_roc int Param or literal Yes Longer rate of change. Default 14, bounds 1–400.
short_roc int Param or literal Yes Shorter rate of change. Default 11, bounds 1–400.
wma_period int Param or literal Yes Weighted-average smoothing. Default 10, bounds 1–200.
on= symbol, OHLCV field, or indicator No Source. Defaults to the trade symbol’s close.

Formula

$$ \text{Coppock} = \text{WMA}\big(\text{ROC}(n_l) + \text{ROC}(n_s),\ w\big) $$

Warmup

long_roc + wma_period bars.

Reading the value

cop.value
cop.crossed_above(0)

Example

class CoppockBottom(Strategy):
"""The classic use: buy the turn up from below zero."""
trade = Symbol()
sizing = FixedCapital()
def execute(self):
cop = CoppockCurve(14, 11, 10, on=self.trade)
if cop.crossed_above(0) and self.trade.is_flat:
self.buy(self.trade, reason="Coppock turned up")
if cop.crossed_below(0) and self.trade.is_long:
self.sell(self.trade, self.trade.position, reason="Coppock turned down")

Notes

  • Edwin Coppock, Barron’s (1962). The 14/11/10 defaults are his, chosen for monthly bars.
  • Proven by an assert-via-trade run on SPY daily (finite and in range on every bar; zero alarm trades).
  • On daily bars this fires far more often than Coppock intended — scale the periods or use weekly data.