Markets › Futures · ES futures (1-hour bars)
Coppock Curve Backtest: 1H Bars on S&P 500 Futures
The turns of the Coppock Curve (14 / 11 / 10) as a signal on 1-hour ES bars, around the clock, with and without a stop and targets.
Buried · No proven edgeLooked great on the chart. Not on the ledger.
Variants tried: 12 · Passed every gate: 0 · Holdout opened: yes (used before this test)
Short answer: no, not in this test. We backtested the Coppock Curve (14, 11, 10; its turns as signals, no filter) on 1-hour ES futures in 12 variants with and without a stop and targets, net of costs. None passed every gate and all 12 lost money after costs; the best, CC-L-S, lost 65 R over 2,981 trades.How much costs took here, compared across all 54 of our tests →
00The verdict in three lines
- The Coppock Curve is a weighted average of two rates of change; our signal is the one in the author's indicator at its defaults, with no filter: buy when the curve turns up, sell when it turns down. We ran it on 1-hour ES bars in 12 variants (long only and long and short, each with no stop, a 1 R stop, targets at 1 R, 2 R and 3 R, and a third at each), with the rules, gates, costs and a matched shifted-state control fixed in a dated specification before any 1-hour Coppock value was computed.
- None passed, and all 12 lost money after costs. The best, ES CC-L-S, lost 65 R over 2,981 trades. The development t-statistic was negative for every variant, and the highest result against the shifted-state control was percentile 36.8 (95 needed).
- The curve turns too often to pay its way. 5,963 signals in 6.7 years is about 886 a year. The long-only versions earned little before costs (0.01 R a trade for the no-stop version, against a cost of 0.04 R), and the long-and-short versions lost money before costs.
01What we tested
The curve: raw = ROC(14) + ROC(11) of the 1-hour closes, and the Coppock Curve is a 10-bar weighted moving average of raw (weights 10 for the newest bar down to 1). The signal: a bull signal when the curve turns up after not rising, a bear signal when it turns down after not falling, read at the close of each bar. Entries only on a signal, filled at the next 1-minute open; the opposite signal exits; after a stop or a target the position stays flat until the next signal. All 24 hours, positions held over weekends. Exits and R are those of our 1-hour golden cross test: 1 R = 1.5 times the 14-bar ATR at the signal bar; the stop wins a tie; a level gapped through fills at the open; slippage on every fill. The 12 variants are long only (L) and long and short (LS) with six exit rules: N (no stop, no target), S (stop only), T1, T2, T3 (stop and one target) and T123 (a third at each target, the exact average of T1, T2 and T3).
Background. We tested this indicator on ES before, in NinjaTrader on the 1-minute and 5-minute charts, with ADX and 1-hour-alignment filters, and with every signal reversed: profit factors of 0.83 to 0.91 after costs and nothing better. Those tests had no frozen specification and no control, so this is the first test of the signal under the protocol. The filters and the shorter charts are not part of it.
02Data and costs
E-mini S&P 500 futures, back-adjusted continuous 1-minute history built into 39,787 hourly bars, 1 Jan 2020 to 25 Sep 2026. Periods: development 2020 to 2023, validation January 2024 to March 2025, holdout April 2025 to the end. The holdout is not clean: the same data appeared in earlier tests, including the earlier Coppock ones. Costs are the ES model: $5.76 commission plus one tick of slippage on each fill, $30.76 a trade (about 0.04 R), and the same $30.76 for each quarterly roll a position is held through. For scale, one contract bought on 2 Jan 2020 and held to the end made +$186,788, with no costs.
Engine check: before the run, cc_selftest.js checked a hand-worked example of the curve and the signals, matched the engine's curve and signals to a naive recomputation on the real bars, and matched an independent re-implementation of the trade simulation trade by trade for all 12 variants on the same signals (cc_selftest_result.txt). It printed pass or fail only, no result.
03Results: all 12 variants
Net R is the sum of the trades' results in R after costs, and gross R is the same before costs; the profit factor and t-statistic use net R. Dollars are per contract. The 95% range is the Wilson interval for the win rate.
| Variant | Trades | Net after costs | R per trade | Gross, before costs | $ per contract | Winners (95% range) | Profit factor | Holdout* net | Verdict |
|---|---|---|---|---|---|---|---|---|---|
| ES CC-L-N | 2,981 | -81 R | -0.03 R | +32.2 R | -$86,370 | 1099 of 2981 (35% to 39%) | 0.94 | -16 R | Buried |
| ES CC-L-S | 2,981 | -65 R | -0.02 R | +48.4 R | -$72,874 | 1026 of 2981 (33% to 36%) | 0.95 | +1 R | Buried |
| ES CC-L-T1 | 2,981 | -139 R | -0.05 R | -25.8 R | -$126,542 | 1235 of 2981 (40% to 43%) | 0.87 | -18 R | Buried |
| ES CC-L-T2 | 2,981 | -92 R | -0.03 R | +20.9 R | -$103,558 | 1053 of 2981 (34% to 37%) | 0.92 | +17 R | Buried |
| ES CC-L-T3 | 2,981 | -72 R | -0.02 R | +40.8 R | -$86,474 | 1030 of 2981 (33% to 36%) | 0.94 | +4 R | Buried |
| ES CC-L-T123 | 2,981 | -101 R | -0.03 R | +12.0 R | -$105,525 | 1127 of 2981 (36% to 40%) | 0.91 | +1 R | Buried |
| ES CC-LS-N | 5,963 | -285 R | -0.05 R | -55.7 R | -$359,990 | 2018 of 5963 (33% to 35%) | 0.90 | -63 R | Buried |
| ES CC-LS-S | 5,963 | -238 R | -0.04 R | -9.6 R | -$291,668 | 1894 of 5963 (31% to 33%) | 0.91 | -31 R | Buried |
| ES CC-LS-T1 | 5,963 | -302 R | -0.05 R | -73.5 R | -$310,597 | 2401 of 5963 (39% to 42%) | 0.86 | -36 R | Buried |
| ES CC-LS-T2 | 5,963 | -289 R | -0.05 R | -60.9 R | -$329,300 | 1966 of 5963 (32% to 34%) | 0.88 | -13 R | Buried |
| ES CC-LS-T3 | 5,963 | -242 R | -0.04 R | -13.2 R | -$307,254 | 1902 of 5963 (31% to 33%) | 0.90 | -27 R | Buried |
| ES CC-LS-T123 | 5,963 | -278 R | -0.05 R | -49.2 R | -$315,717 | 2164 of 5963 (35% to 38%) | 0.88 | -25 R | Buried |
Cumulative net R by month for long only with no stop, long only with only a stop, and long and short with no stop. * Holdout already used before this test. PF = profit factor.
04With and without a stop and targets
Long only on the left, long and short on the right. “Stop / target / signal” counts how the long-only trades ended (for T123 each third counts as one exit). The last column is the average gross result per trade in R before costs, then the average cost per trade in R.
| Exit rule | Long only, net R | Winners | How the trades ended | Long and short, net R | Winners | Gross / cost per trade (long only) |
|---|---|---|---|---|---|---|
| N: no stop, no target | -81.2 R | 37% | stop 0 · target 0 · signal 2,981 | -284.7 R | 34% | +0.01 R / 0.04 |
| S: stop 1 R only | -64.9 R | 34% | stop 785 · target 0 · signal 2,196 | -238.4 R | 32% | +0.02 R / 0.04 |
| T1: stop 1 R, target 1 R | -138.9 R | 41% | stop 694 · target 908 · signal 1,379 | -301.8 R | 40% | -0.01 R / 0.04 |
| T2: stop 1 R, target 2 R | -92.2 R | 35% | stop 769 · target 409 · signal 1,803 | -289.3 R | 33% | +0.01 R / 0.04 |
| T3: stop 1 R, target 3 R | -72.4 R | 35% | stop 782 · target 173 · signal 2,026 | -241.7 R | 32% | +0.01 R / 0.04 |
| T123: a third at 1 R, 2 R and 3 R | -101.2 R | 38% | stop 2,245 · target 1,490 · signal 5,208 | -277.6 R | 36% | 0.00 R / 0.04 |
No exit rule produced a variant that passed every gate. The best long-only result was the stop alone (-65 R, against -81 R with no stop), and the targets did not change the picture: -139 R, -92 R and -72 R at 1 R, 2 R and 3 R. 5 of the 12 variants were positive before costs and not after (cause “Costs” below); the others were negative before costs as well.
05Is it the signal or the market?
The benchmark is a circularly shifted state-series control, not a random-entry test. The state is the direction of the last Coppock signal; the real state series is shifted by a random offset of at least 5% of its length, so the same up and down episodes fall on other dates, while the real prices, the same entry, stop, target and exit rules and the same costs are applied and the ATR-based R (and every stop and target distance) is recomputed at the shifted signal time from the real prices. This is done 500 times with fixed seeds. The bar is the 95th percentile of the average net R per trade.
| Variant | Trades | Real average per trade | Control median | Control 5th to 95th | Percentile (95 needed) |
|---|---|---|---|---|---|
| ES CC-L-N | 2,981 | -0.03 R | -0.01 R | -0.04 R to +0.02 R | 24.2 |
| ES CC-L-S | 2,981 | -0.02 R | -0.01 R | -0.04 R to +0.01 R | 33.4 |
| ES CC-L-T1 | 2,981 | -0.05 R | -0.03 R | -0.05 R to -0.01 R | 7.0 |
| ES CC-L-T2 | 2,981 | -0.03 R | -0.02 R | -0.04 R to 0.00 R | 21.2 |
| ES CC-L-T3 | 2,981 | -0.02 R | -0.02 R | -0.04 R to +0.01 R | 36.8 |
| ES CC-L-T123 | 2,981 | -0.03 R | -0.02 R | -0.04 R to 0.00 R | 19.0 |
| ES CC-LS-N | 5,963 | -0.05 R | -0.04 R | -0.07 R to -0.01 R | 30.6 |
| ES CC-LS-S | 5,963 | -0.04 R | -0.03 R | -0.05 R to -0.01 R | 28.4 |
| ES CC-LS-T1 | 5,963 | -0.05 R | -0.04 R | -0.06 R to -0.02 R | 11.8 |
| ES CC-LS-T2 | 5,963 | -0.05 R | -0.04 R | -0.06 R to -0.02 R | 15.4 |
| ES CC-LS-T3 | 5,963 | -0.04 R | -0.03 R | -0.05 R to -0.01 R | 31.4 |
| ES CC-LS-T123 | 5,963 | -0.05 R | -0.04 R | -0.05 R to -0.02 R | 18.8 |
Nothing came close: the highest was ES CC-L-T3 at percentile 36.8. The real signal's timing did no better than the same pattern of episodes placed on other dates.
06The gates
| Variant | Trades | 1. PF ≥ 1.2 in validation | 2. ≥ 50 trades in each period | 3. t ≥ 2.5 on development | 4. Above the 95th percentile of the shifted-state control | 5. Positive without the 10 best trades | 6. Holdout net positive (already used) |
|---|---|---|---|---|---|---|---|
| ES CC-L-N | 2,981 | fail | pass | fail | fail | fail | fail |
| ES CC-L-S | 2,981 | fail | pass | fail | fail | fail | pass |
| ES CC-L-T1 | 2,981 | fail | pass | fail | fail | fail | fail |
| ES CC-L-T2 | 2,981 | fail | pass | fail | fail | fail | pass |
| ES CC-L-T3 | 2,981 | fail | pass | fail | fail | fail | pass |
| ES CC-L-T123 | 2,981 | fail | pass | fail | fail | fail | pass |
| ES CC-LS-N | 5,963 | fail | pass | fail | fail | fail | fail |
| ES CC-LS-S | 5,963 | fail | pass | fail | fail | fail | fail |
| ES CC-LS-T1 | 5,963 | fail | pass | fail | fail | fail | fail |
| ES CC-LS-T2 | 5,963 | fail | pass | fail | fail | fail | fail |
| ES CC-LS-T3 | 5,963 | fail | pass | fail | fail | fail | fail |
| ES CC-LS-T123 | 5,963 | fail | pass | fail | fail | fail | fail |
All 12 variants have thousands of trades, so the sample-size rule never applied. Gate 3 (development t-statistic of at least 2.5, raised from 2.0 because more than four variants were tried) is failed by every variant, and the t-statistic was negative for all of them.
07Verdict by variant
| Variant | Cause | Gates failed | Verdict |
|---|---|---|---|
| ES CC-L-N | Costs | 1, 3, 4, 5, 6 | Buried |
| ES CC-L-S | Costs | 1, 3, 4, 5 | Buried |
| ES CC-L-T1 | No proven edge | 1, 3, 4, 5, 6 | Buried |
| ES CC-L-T2 | Costs | 1, 3, 4, 5 | Buried |
| ES CC-L-T3 | Costs | 1, 3, 4, 5 | Buried |
| ES CC-L-T123 | Costs | 1, 3, 4, 5 | Buried |
| ES CC-LS-N | No proven edge | 1, 3, 4, 5, 6 | Buried |
| ES CC-LS-S | No proven edge | 1, 3, 4, 5, 6 | Buried |
| ES CC-LS-T1 | No proven edge | 1, 3, 4, 5, 6 | Buried |
| ES CC-LS-T2 | No proven edge | 1, 3, 4, 5, 6 | Buried |
| ES CC-LS-T3 | No proven edge | 1, 3, 4, 5, 6 | Buried |
| ES CC-LS-T123 | No proven edge | 1, 3, 4, 5, 6 | Buried |
What this test covers, exactly: the turns of the Coppock Curve at its default settings (14, 11, 10) and no filter, as a signal on 1-hour ES bars (6.7 years, back-adjusted), around the clock, positions held over weekends, R fixed at 1.5 ATR(14), with the costs above. “No proven edge” means a convincing edge was not demonstrated; it is not proof that none exists.
What we did not test: the indicator's filters, other settings, 1-minute and 5-minute charts under the protocol, the original monthly use of the curve, other markets, and other stop sizes.
TWhat this shows, and what to take into your own tests
What the results show
- None of the 12 variants passed, and all 12 lost money after costs: the best, ES CC-L-S, lost 64.9 R. The development t-statistic was negative for every variant (the highest was -1.31, 2.5 needed).
- The curve turns often: 5,963 signals in 6.7 years, about 886 a year and a trade every 10 hours on average. The long-only no-stop version made +32.2 R before costs over 2,981 trades, 0.01 R a trade against a cost of 0.04 R; the long-and-short versions lost money before costs.
- No variant beat the shifted-state control: the highest was percentile 36.8, with 95 needed.
- No tested stop or target configuration passed every gate, with or without a stop, long only or long and short.
What remains unknown
- The filters of the author's indicator (ADX, alignment with the 1-hour chart), other settings and other timeframes. Earlier, unprotocolled tests of the 1-minute and 5-minute charts with filters also found nothing, but they had no frozen specification.
- The original use of the curve: a long-term buy signal on monthly index data (Coppock, 1962). This test is about hourly timing.
- Other markets, and other stop sizes. R was fixed at 1.5 ATR(14) in advance.
Why it failed
A signal that fires about 886 times a year has to earn more than its cost on every trade. Here the cost is about 0.04 R a trade and the gross result of the long-only no-stop version is 0.01 R a trade, with a development t-statistic of -1.38; the long-and-short versions lost money even before costs, so the curve's turns carry almost no information about the next hours.
What you can apply to your own tests
- Count your signals per year first. Several hundred a year means costs are the first hurdle.
- Compare the gross result per trade with the cost per trade before you test exits.
- Report a result in the unit you trade (dollars) and in R, so a stop-and-target grid is comparable.
- A chart that looks great after the fact is not a test: freeze the rules, then run them.
A note on the numbers: drawdown figures are measured on closed trades unless a table says it includes open losses. Open losses inside a trade are not counted in a closed-trade drawdown, so real account risk is higher, especially for systems with no stop. Backtests are not live trading.
FAQCommon questions
Does the Coppock Curve work for day trading?
Not in our test. On 1-hour ES bars from 2020 to 2026 the curve gave 5,963 signals, about 890 a year, and none of 12 variants passed. The long-only no-stop version made -81 R after costs and its development t-statistic was -1.38; the long-and-short versions lost money even before costs.
Do a stop loss and take profit help a Coppock Curve strategy?
Not enough to matter. With the stop only, the long-only version lost 65 R against 81 R with no stop, and targets at 1 R, 2 R and 3 R made -139 R, -92 R and -72 R. No stop and target configuration passed every gate.
Does the Coppock Curve beat random timing?
No. Against a circularly shifted state-series control (the same signal episodes placed on other dates), the highest of the 12 variants reached percentile 36.8; 95 was needed.
How was the Coppock Curve tested?
On 1-hour ES futures, around the clock, with rules written and dated before the data was run, costs included on every trade, results split into development, validation and holdout periods, a random-entry control as the benchmark, and every variant reported. The curve was used at its default settings with no filter. Read the protocol.
08Check our arithmetic
cc_spec.md
cc_lib.js · cc_run.js · cc_selftest.js · gh_lib.js · ma_lib.js · control_audit_lib.js · hourly_lib.js · rsi2_protocol.js
cc_selftest_result.txt · cc_results.txt · cc_summary.json
ES
Code provenance: our own code, written from the standard definition of the Coppock Curve and of the ATR. No third-party source code is used or published.
09Data notes
Added 8 Oct 2026, after a data audit; no result, gate or verdict on this page changed. The ES 1-minute file used here (NinjaTrader, back-adjusted; hashes in data_manifest.md) has holes: 10 windows of missing data inside sessions or whole sessions, listed in data_holes.json (for example 19 to 23 October 2020, 6 to 7 November 2022, 27 to 28 November 2025). They are shared with the NQ and gold files from the same source, and we did not fill them. We removed every trade that was open across one of them and recomputed the gates and verdicts (the benchmark percentile is taken from the original run): 62 trade-hole overlaps summed over the 12 ES variants, no verdict changed. Some individual gates changed in 1 of the 12 variants (CC-L-T123: gate 6 PASS->FAIL), none of which decides a verdict. The full table is in hole_sensitivity.txt.
The prices are also back-adjusted: each contract roll shifts older prices by a fixed amount so that the series has no jump at the roll. Results in R and in dollars are right; older prices are not the prices that traded.
10Corrections
14 Oct 2026, display only: values that round to zero were shown with a sign (“-0.00 R” or “+0.00 R”); they are now shown as 0.00 R. No number changed. 8 Oct 2026, after a data audit, no result, gate or verdict changed: a Data notes section was added (the holes in the ES file, the back-adjustment, and a check without the trades open across the holes, which changed no verdict). 22 Oct 2026, navigation: added a link to the new guide comparing trading costs across all our tests. No result changed. 22 Oct 2026, navigation: added a link to the new guide comparing trend following and mean reversion across all our tests. No result changed. 22 Oct 2026, navigation: added a link to the new guide comparing versions with and without a stop loss across our tests. No result changed.
+More tests and guides
- Macd crossover strategy backtest
- Supertrend indicator backtest
- Rsi divergence strategy backtest
- Golden cross 1 hour backtest
- Did the stop loss help? This test next to the other with-and-without pairs
- Trend following vs mean reversion: this test next to the others of its style
- Free prop firm challenge calculator
- What all the backtests found so far
- The backtesting protocol
- How to backtest a trading strategy without fooling yourself
- Backtesting glossary