Coppock Curve
I. What is the Coppock Curve
The Coppock Curve (also known as the Coppock Indicator) is a long-term momentum indicator that applies a Weighted Moving Average (WMA) to the sum of two Rate of Change (ROC) values with different periods, in order to identify major market bottoms and the beginning of long-term bull markets. It was designed as a monthly-timeframe indicator, primarily used to determine when the market is recovering from a significant decline.
Historical Background
The Coppock Curve was invented by Edwin Sedgwick Coppock in 1962 and first published in Barron’s magazine. Interestingly, Coppock consulted bishops of the Episcopal Church and asked about the average time people need to recover from the loss of a loved one (11–14 months). He applied this “mourning period” to the market — believing that the market’s recovery from a bear market bottom follows a process similar to human psychological recovery. This is why he chose 11 months and 14 months as the ROC periods.
Indicator Classification
- Type: Oscillator, displayed in a separate panel
- Category: Momentum — long-term indicator
- Default Parameters: WMA period , long ROC , short ROC
- Value Range: Unbounded, oscillates around the zero line
- Original Design Timeframe: Monthly
This is one of the very few technical indicators designed based on “human psychological recovery cycles.” It does not seek frequent trades, but instead focuses on capturing major market bottoms — generating signals only once every several years.
II. Mathematical Principles and Calculation
Core Formula
Step 1: Calculate two ROC values with different periods
Step 2: Sum
Step 3: Calculate Weighted Moving Average (WMA)
The WMA weights are: , with a denominator of .
Step-by-Step Calculation Logic
- Calculate ROC(14): Percentage change between current price and price 14 periods ago
- Calculate ROC(11): Percentage change between current price and price 11 periods ago
- Add them together: ROC(14) + ROC(11)
- WMA(10): Apply a 10-period weighted moving average to the sum
Why Use WMA?
WMA (Weighted Moving Average) assigns greater weight to recent data, providing better responsiveness to recent changes while maintaining smoothness. Compared to SMA, WMA turning points appear earlier.
Coppock’s original design uses monthly data (ROC measured in months). If applied to daily charts, parameters should be adjusted to approximately 294 days (14 months × 21 trading days) and 231 days (11 × 21), with WMA at 210 days (10 × 21). However, many traders use shorter periods on daily charts.
III. Python Implementation
import numpy as np
import pandas as pd
def wma(series: pd.Series, period: int) -> pd.Series:
"""Calculate Weighted Moving Average (WMA)"""
weights = np.arange(1, period + 1, dtype=float)
return series.rolling(window=period, min_periods=period).apply(
lambda x: np.dot(x, weights) / weights.sum(), raw=True
)
def coppock_curve(close: pd.Series,
wma_period: int = 10,
long_roc: int = 14,
short_roc: int = 11) -> pd.Series:
"""
Calculate Coppock Curve
Parameters
----------
close : pd.Series
Close price series (monthly data recommended)
wma_period : int
WMA period, default 10
long_roc : int
Long ROC period, default 14
short_roc : int
Short ROC period, default 11
Returns
-------
pd.Series
Coppock Curve values
"""
roc_long = ((close - close.shift(long_roc)) / close.shift(long_roc)) * 100
roc_short = ((close - close.shift(short_roc)) / close.shift(short_roc)) * 100
roc_sum = roc_long + roc_short
return wma(roc_sum, wma_period)
# ========== Usage Example ==========
if __name__ == "__main__":
np.random.seed(42)
# Simulate monthly data (5 years = 60 months)
dates = pd.date_range("2019-01-01", periods=60, freq="ME")
# Simulate a decline-then-recovery market cycle
decline = np.linspace(0, -30, 20)
recovery = np.linspace(-30, 20, 40)
trend = np.concatenate([decline, recovery])
noise = np.cumsum(np.random.randn(60) * 2)
price = 100 + trend + noise
df = pd.DataFrame({
"date": dates,
"close": price,
})
df.set_index("date", inplace=True)
# Calculate Coppock Curve
df["Coppock"] = coppock_curve(df["close"])
print("=== Coppock Curve Results ===")
print(df[["close", "Coppock"]].dropna().to_string())
# Buy signal: Coppock turns up while below zero
df["prev_coppock"] = df["Coppock"].shift(1)
buy_signal = (
(df["Coppock"] > df["prev_coppock"]) & # Turning up
(df["Coppock"] < 0) # Still below zero
) & (
(df["prev_coppock"] <= df["Coppock"].shift(2)) # Previous period was declining
)
print("\n=== Buy Signals (Turning Up Below Zero) ===")
print(df.loc[buy_signal, ["close", "Coppock"]].to_string())
IV. Problems the Indicator Solves
1. Identifying Major Market Bottoms
The Coppock Curve’s core use case is identifying the bottom area of major bear markets. When the curve turns upward while below the zero line, it suggests the market is recovering from a deep decline.
2. Long-term Buy Signals
Classic buy signal:
- Coppock Curve is below the zero line (market has experienced a significant decline)
- The curve’s direction changes from declining to rising (turns upward)
- This signal indicates long-term momentum is recovering from the bottom
3. Bull Market Confirmation
When the Coppock Curve crosses above the zero line from negative territory, it confirms the long-term trend has shifted from bearish to bullish.
4. Sell Reference
Although Coppock originally designed the indicator as a buy-only tool, traders also use it in reverse:
- Curve turns down while above the zero line -> sell warning
- Curve crosses below zero -> long-term trend may be turning bearish
The Coppock Curve is an extremely low-frequency signal tool. On the S&P 500 monthly chart, it may generate a buy signal only once every few years. Do not attempt to use it for short-term trading or frequent operations.
V. Advantages, Disadvantages, and Use Cases
Advantages
| Advantage | Description |
|---|---|
| Focused on major bottoms | Designed specifically to capture major market bottoms, historically validated |
| Very few false signals | Low-frequency signals naturally filter out most market noise |
| Unique logic | Design philosophy based on human psychological recovery cycles |
| High historical win rate | Buy signals on the S&P 500 monthly chart have a very high historical win rate |
Disadvantages
| Disadvantage | Description |
|---|---|
| Very few signals | May produce only one signal every several years, low daily utility |
| Monthly only | Originally designed for monthly charts; daily use requires major parameter adjustments |
| Significant lag | Long-period ROC + WMA results in severely lagging signals |
| Not a sell indicator | Original design only provides buy signals; selling requires additional judgment |
Use Cases
- Long-term investors: Suitable for strategic position-building decisions measured in years
- Index investing: Works best on broad-based indices (e.g., S&P 500, CSI 300)
- Supplementary macro judgment: As a reference tool for judging major market cycle turning points
Comparison with Related Indicators
| Comparison | Coppock | MACD | RSI |
|---|---|---|---|
| Time scale | Monthly/yearly | Daily/weekly | Daily/weekly |
| Signal frequency | Very low | Medium | High |
| Best for | Long-term positioning | Swing trading | Short/medium-term |
| Best asset type | Broad indices | Stocks/indices | Stocks/ETFs |
- Monthly is king: Stick to using the Coppock Curve on monthly charts; its effectiveness on daily charts has not been fully validated.
- Combine with fundamentals: Coppock buy signal + leading economic indicators bottoming out = higher confidence long-term buy opportunity.
- Scale into positions: Don’t go all-in when the signal appears; build positions gradually over 3–6 months.
- Use other tools for selling: Coppock’s sell signals are less reliable than its buy signals. Consider using the 200-day moving average or monthly MACD to assist with sell decisions.