# On-chain Batch 1: before vs after publication (DESCRIPTIVE ONLY, NOT A TEST) > Website copy, trimmed from `samples/onchain1/BEFORE-AFTER.md` (repository commit c1cef4d): three price figures in the cycle-table definition were removed. Nothing else was changed. **This is not a test.** No p-values, no grades, no multiple-testing correction, and nothing here is evidence for or against any claim. It shows how each of the 12 Batch 1 indicators looks on the history its creator could see when designing it (**before** publication, in-sample) next to how it looked **after** (the sealed out-of-sample window). The sealed results in `SUMMARY.md` and `results.json` are the only test results; this page does not change any of them. Statistical analysis of past data only; not investment advice. Code `before_after.py`, output `before_after.json`, test `tests/test_onchain1_before_after.py`. ## In one line each 1. **Pi Cycle Top:** fired within 3 days of 2 of 3 cycle tops before it was published (4 days early on the other) → 1 of 3 after (April 2021; no signal near the Nov 2021 or Oct 2025 highs). 2. **200-week MA:** price was near or below it within 30 days of 1 of 1 cycle low in its pre-publication data (Dec 2018) → 2 of 3 after (Nov 2022 and the 2026 low so far; not July 2021); a year after such days BTC averaged +154% vs +127% for any day before → +102% vs +42% after. 3. **Mayer Multiple:** above 2.4 within 30 days of 3 of 3 cycle tops before it was published → 0 of 3 after (its last signal ended 31 days before the April 2021 high; none near Nov 2021 or Oct 2025). 4. **2-Year MA Multiplier:** price was below the 2-year MA within 30 days of 1 of 1 cycle low in its pre-publication data (Jan 2015) → 3 of 4 after (not the July 2021 low); before publication, days below it were followed by about the same 1-year return as any day (+104% vs +105%), after by +108% vs +33%. 5. **Puell Multiple:** below 0.5 within 30 days of 2 of 3 cycle lows before it was published → 2 of 3 after (not the 2026 low so far); before publication its signal days were followed by a lower 1-year return than average (+84% vs +130%), after by a higher one (+105% vs +42%). 6. **Stock-to-flow:** price was below the model within 30 days of 3 of 4 cycle lows before publication → 3 of 3 after, but only because price has been below the model on 79% of days since; below-model days were followed by +428% vs +163% a year later in the data it was fitted on → +26% vs +42% after. 7. **MVRV Z-score:** above 5 within 14 days of 3 of 3 cycle tops before it was published → 1 of 3 after (April 2021; it never reached 5 near the Nov 2021 or Oct 2025 highs). 8. **NUPL:** below 0 within 30 days of 2 of 4 cycle lows before it was published (Jan 2015, Dec 2018; not the 2011 or mid-2013 lows, where our early values are least reliable) → 1 of 3 after (Nov 2022 only). 9. **SOPR reset:** before publication, reset days were followed by about the same 90-day return as any day (+29% vs +29%) → +17% vs +7% after (the sealed test found that gap not significant). 10. **Reserve Risk:** below 0.0026 within 30 days of 2 of 4 cycle lows before it was published → 2 of 3 after, but since publication it has been below the band on 75% of days (every day since Jan 2022). 11. **Short-term-holder cost basis:** over the next 90 days, BTC averaged +40% after days above it vs +26% after any day before it was published → +4% vs +3% after. 12. **Realized price:** price was below it within 30 days of 1 of 3 cycle lows before it was published (Jan 2015; not the 2011 or mid-2013 lows, where our early values are least reliable) → 2 of 4 after (Dec 2018 and Nov 2022; not July 2021 or the 2026 low so far). **The pattern.** The three top signals (Pi Cycle, Mayer Multiple, MVRV Z-score) look strongest on the data they were designed on: between them 8 of 9 pre-publication tops flagged within the claimed window, then 2 of 9 after, both at the April 2021 high, and none at the Nov 2021 or Oct 2025 highs. The bottom signals do not follow that pattern: several looked no better than an average day before publication (2-year MA, Puell, NUPL, realized price) and better after, and two (stock-to-flow, Reserve Risk) "caught" lows after publication mainly because they were switched on most of the time. With 1 to 4 cycles per window none of this can separate skill from luck, which is why the sealed tests report most of these as descriptive only. ## Method - **Same rule as the sealed test.** For each indicator: the frozen rule and zone of its primary sealed test, the 30-day episode merge gap, and its primary horizon (365 days; 90 days for SOPR reset and STH cost basis). Same code (`run.py`: `indicators`, `s2f`, `fwd`, `episodes`; Family B metrics from `bq/metrics_daily.csv`). - **BEFORE window:** from the first day every input of the rule and a price exist, to the day before the sealed out-of-sample start. - **AFTER window:** the sealed out-of-sample window. Episodes and average returns are copied from `results.json` (the published numbers). The script also recomputes them with its own code and stops if any differs (all 12 reproduce exactly). - **Average return:** geometric mean of the h-day forward log returns, exp(mean) - 1, on zone days vs on all days of the window, over days whose full h-day window ends by 2026-09-24 (as in the site table). Forward returns from the last h days of the BEFORE window run into the AFTER period. - **Prices:** Bitstamp's public daily close from 2011-08-18 to 2015-07-19 and the sealed Coinbase file from 2015-07-20, spliced as in `DEVIATION-001-data-source.md` and `bq/metrics.py`. **There is no price data before 2011-08-18**, so nothing before that date is covered (the 2010 and June 2011 peaks are missing). The daily metric series already covered the pre-publication years, so no new BigQuery query was needed. - **"Tops called" / "lows caught":** an extreme counts as called at window W if it falls within W days before the start to W days after the end of an episode in the same window (the geometry of the sealed `top_hit`/`bottom_hit`). W is the creator's claimed timing where one exists (Pi Cycle 3 days, MVRV Z-score 14 days), otherwise 30 days. Results at 90 days are in the JSON. Only zone days inside the same window count. This uses the cycle table below, **not** the sealed `top_hit`, which compared each signal with the highest close within a year either side. Under the sealed definition, the April 2021 Pi Cycle crossing and MVRV-Z episode were misses because the Nov 2021 close was higher. Here April 2021 is a cycle top in its own right, because a 53% fall followed it. ### Per-indicator windows | ID | Indicator | Rule (primary zone) | Horizon | BEFORE window | AFTER window (sealed) | |---|---|---|---|---|---| | A1 | Pi Cycle Top | 111DMA crosses above 2 x 350DMA (top) | 365d | 2012-08-01 to 2019-04-30 | 2019-05-01 to 2026-09-24 | | A2 | 200-week MA | close <= 1.10 x 200WMA (bottom) | 365d | 2015-06-14 to 2019-05-18 | 2019-05-19 to 2026-09-24 | | A3 | Mayer Multiple | MM > 2.4 (top) | 365d | 2012-03-04 to 2017-12-31 | 2018-01-01 to 2026-09-24 | | A4 | 2-Year MA Multiplier | close < 2yMA (bottom) | 365d | 2013-08-16 to 2017-07-31 | 2017-08-01 to 2026-09-24 | | A5 | Puell Multiple | Puell < 0.5 (bottom) | 365d | 2012-08-16 to 2019-03-31 | 2019-04-01 to 2026-09-24 | | A6 | Stock-to-flow | close < model (bottom) | 365d | 2011-08-18 to 2019-03-22 | 2019-03-23 to 2026-09-24 | | B1 | MVRV Z-score | Z > 5 (top) | 365d | 2011-08-19 to 2018-10-09 | 2018-10-10 to 2026-09-24 | | B2 | NUPL | NUPL < 0 (bottom) | 365d | 2011-08-18 to 2019-02-28 | 2019-03-01 to 2026-09-24 | | B3 | SOPR (unadjusted) | close > 200DMA and SOPR 7d SMA <= 1 (bull-regime reset) | 90d | 2012-03-04 to 2019-04-25 | 2019-04-26 to 2026-09-24 | | B4 | Reserve Risk | RR < 0.0026 (bottom) | 365d | 2011-08-18 to 2019-05-30 | 2019-05-31 to 2026-09-24 | | B5 | STH cost basis | close > STH cost basis (bull regime) | 90d | 2012-09-21 to 2021-06-30 | 2021-07-01 to 2026-09-24 | | B6 | Realized price | close < realized price (bottom) | 365d | 2011-08-18 to 2018-10-31 | 2018-11-01 to 2026-09-24 | Start dates are set by warm-up: 200 days of price for the Mayer Multiple and the 200-day SMA, 350 for Pi Cycle, 365 for Puell, 730 for the 2-year MA, 200 Sundays for the 200WMA, and 400 days for STH cost basis. Stock-to-flow, NUPL, Reserve Risk and realized price start on the first priced day. MVRV-Z starts one day later, because the first day's standard deviation is zero. ## Cycle table **Definition.** A **cycle top** is an all-time-high close followed by a fall of at least 50% (close to close) before the next all-time high. A **cycle low** is the lowest close between two consecutive tops. Before the first top, it is the lowest close from the data start. After the last top, it is the lowest close so far, which is provisional. The data begin after the June 2011 peak, so the running high is seeded with that peak. A wide range of seed values gives the same table, and the script checks this. Dates are UTC closes. The 2013 dates come from Bitstamp; later dates come from Coinbase. | Cycle top | Fall before the next all-time high | Following cycle low | |---|---|---| | (June 2011, before our data) | | 2011-10-20 (first low in our data) | | 2013-04-09 | -71% | 2013-07-06 | | 2013-12-04 | -85% | 2015-01-14 | | 2017-12-16 | -84% | 2018-12-15 | | 2021-04-13 | -53% | 2021-07-20 | | 2021-11-08 | -77% | 2022-11-21 | | 2025-10-06 | -53% so far | 2026-06-30 (provisional: lowest close so far) | **Stricter variant (at least a 75% fall):** only 2013-12-04, 2017-12-16 and 2021-11-08 qualify. The Oct 2025 high is listed as unconfirmed. Under this variant, all three top signals called **2 of 2 tops before publication → 0 of 1 after**. The 2021 and 2025 run-ups show the same thing in both variants: each of these signals fired, at most, at the first of the two 2021 highs. ## Before vs after, all 12 | ID | Indicator | BEFORE: episodes | BEFORE: avg return after zone days vs all days | AFTER: episodes | AFTER: avg return after zone days vs all days | Extremes called at the claimed window, before → after | |---|---|---|---|---|---|---| | A1 | Pi Cycle Top (top, 3d) | 3 | -42% vs +130% | 1 | -33% vs +42% | tops 2/3 → 1/3 | | A2 | 200-week MA (bottom, 30d) | 3 | +154% vs +127% | 3 | +102% vs +42% | lows 1/1 → 2/3 | | A3 | Mayer Multiple (top, 30d) | 4 | +24% vs +211% | 3 | -21% vs +36% | tops 3/3 → 0/3 | | A4 | 2-Year MA Multiplier (bottom, 30d) | 3 | +104% vs +105% | 4 | +108% vs +33% | lows 1/1 → 3/4 | | A5 | Puell Multiple (bottom, 30d) | 3 | +84% vs +130% | 4 | +105% vs +42% | lows 2/3 → 2/3 | | A6 | Stock-to-flow (bottom, 30d) | 6 | +428% vs +163% | 6 | +26% vs +42% | lows 3/4 → 3/3 | | B1 | MVRV Z-score (top, 14d) | 6 | -11% vs +168% | 1 | -15% vs +44% | tops 3/3 → 1/3 | | B2 | NUPL (bottom, 30d) | 3 | +105% vs +164% | 3 | +82% vs +42% | lows 2/4 → 1/3 | | B3 | SOPR reset (90d horizon) | 17 | +29% vs +29% | 13 | +17% vs +7% | n/a (regime claim) | | B4 | Reserve Risk (bottom, 30d) | 3 | +179% vs +159% | 2 | +84% vs +42% | lows 2/4 → 2/3 | | B5 | STH cost basis (90d horizon) | 11 | +40% vs +26% | 7 | +4% vs +3% | n/a (regime claim) | | B6 | Realized price (bottom, 30d) | 2 | +99% vs +166% | 3 | +94% vs +45% | lows 1/3 → 2/4 | The "all days" averages differ a lot between windows: BTC rose far faster in 2011 to 2018 than since. Compare zone days with all days **within** a window, not across windows. The share of days each zone was on is in the JSON (`zone_share_of_all_window_days`). A zone that is on most of the time "catches" lows cheaply: after publication, stock-to-flow was on for 79% of days and Reserve Risk for 75%. The two regime claims (SOPR reset, STH cost basis) are not about turning points, so no extremes are counted for them. ### Top by top (nearest signal day, in days relative to the top; negative = before) | Top | A1 Pi Cycle (3d) | A3 Mayer (30d) | B1 MVRV-Z (14d) | |---|---|---|---| | 2013-04-09 | BEFORE: no (-4 d) | BEFORE: yes (0 d) | BEFORE: yes (0 d) | | 2013-12-04 | BEFORE: yes (+1 d) | BEFORE: yes (0 d) | BEFORE: yes (0 d) | | 2017-12-16 | BEFORE: yes (0 d) | BEFORE: yes (0 d) | BEFORE: yes (0 d) | | 2021-04-13 | AFTER: yes (-1 d) | AFTER: no (-31 d) | AFTER: yes (0 d) | | 2021-11-08 | AFTER: no (-210 d) | AFTER: no (-240 d) | AFTER: no (-207 d) | | 2025-10-06 | AFTER: no (-1638 d) | AFTER: no (-1668 d) | AFTER: no (-1635 d) | ### Low by low (zone on within 30 days? nearest zone day relative to the low) | Low | A2 200WMA | A4 2yMA | A5 Puell | A6 S2F | B2 NUPL | B4 Reserve Risk | B6 Realized price | |---|---|---|---|---|---|---|---| | 2011-10-20 | not yet computable | not yet computable | not yet computable | BEFORE: yes (0 d) | BEFORE: no | BEFORE: no | BEFORE: no | | 2013-07-06 | not yet computable | not yet computable | BEFORE: no | BEFORE: no (+88 d) | BEFORE: no | BEFORE: no | BEFORE: no | | 2015-01-14 | not yet computable | BEFORE: yes | BEFORE: yes | BEFORE: yes | BEFORE: yes | BEFORE: yes | BEFORE: yes | | 2018-12-15 | BEFORE: yes | AFTER: yes | BEFORE: yes | BEFORE: yes | BEFORE: yes | BEFORE: yes | AFTER: yes | | 2021-07-20 | AFTER: no | AFTER: no | AFTER: yes (-23 d) | AFTER: yes | AFTER: no | AFTER: no | AFTER: no | | 2022-11-21 | AFTER: yes | AFTER: yes | AFTER: yes | AFTER: yes | AFTER: yes | AFTER: yes | AFTER: yes | | 2026-06-30 (provisional) | AFTER: yes | AFTER: yes | AFTER: no | AFTER: yes | AFTER: no | AFTER: yes | AFTER: no | ### Secondary zones (same method; the sealed tests treated these as secondary) | Zone | BEFORE: episodes, avg return zone vs all | AFTER: episodes, avg return zone vs all | Extremes within 30 days, before → after | |---|---|---|---| | A4 close >= 5 x 2yMA (top) | 1, -56% vs +105% | 2, -67% vs +33% | tops 1/1 → 1/4 (Dec 2017 only) | | A5 Puell > 4 (top) | 4, -21% vs +130% | 0 (never fired) | tops 3/3 → 0/3 | | B1 MVRV-Z < 0 (bottom) | 2, +99% vs +168% | 3, +94% vs +44% | lows 1/3 → 2/4 | | B2 NUPL >= 0.75 (top) | 4, +6% vs +164% | 0 (never fired) | tops 3/3 → 0/3 | | B4 Reserve Risk > 0.02 (top) | 4, -32% vs +159% | 0 (never fired) | tops 3/3 → 0/3 | The top bands of Puell, NUPL and Reserve Risk each flagged every pre-publication top, then never fired again after publication. ### Family B early-data sensitivity (first year of priced data dropped: BEFORE from 2012-08-18) | ID | Episodes | Avg return zone vs all days | |---|---|---| | B1 MVRV-Z > 5 | 5 (was 6) | -15% vs +133% (was -11% vs +168%) | | B2 NUPL < 0 | 3 | +105% vs +131% | | B3 SOPR reset | 16 (was 17) | +22% vs +28% | | B4 Reserve Risk < 0.0026 | 3 | +179% vs +127% | | B6 close < realized price | 2 | +99% vs +132% | The MVRV-Z episode of Aug to Sep 2011 is an artefact: the expanding-window standard deviation has only a few days of history then. Dropping the first year removes it, and the direction of every comparison stays the same. ## Caveats - **Descriptive only.** No p-value, grade or Holm adjustment is computed or implied. With 1 to 4 cycles per window, "before looked better than after" is exactly what chance plus in-sample design would produce, and it cannot be tested with this little data. - **BEFORE is in-sample by design.** Creators built these rules on this history: thresholds were chosen, in part, because they fit these tops and lows. Stock-to-flow's regression was fitted on it. A good BEFORE record is expected and says little about skill. - **Some BEFORE windows run slightly past publication.** The BEFORE window ends at the sealed out-of-sample start, which for a few indicators is later than the first publication: the 200WMA (published Jan 2019, window from 2019-05-19 because of warm-up in the sealed Coinbase file), the Mayer Multiple (2017, month unverified, so the window starts 2018-01-01), and STH cost basis (Glassnode framework 2020, sealed start 2021-07-01). - **Early data are thinner.** Before 2015-07-20 the prices are Bitstamp's, which was a small, illiquid venue in 2011 to 2013 (Mt. Gox dominated trading then). Its closes can differ from those of other venues. There is no price before 2011-08-18. The 2010 and June 2011 peaks, and any signal around them, are not covered. Commonly quoted "called every top" records may include those. - **Early on-chain values are least reliable.** Coins created before 2011-08-18 carry zero cost in our realized cap. This pushes the realized price down, and NUPL and MVRV up, most in 2011 and 2012. It may be part of why NUPL and realized price did not flag the 2011 and mid-2013 lows. The HODL Bank starts at zero on 2011-08-18, so Reserve Risk starts high and drifts down for years. That makes early top-band readings easy, and later bottom-band readings easy too. STH cost basis needs 400 days of priced history, so it starts on 2012-09-21. - **Price-source differences.** Forward returns for BEFORE days before mid-2015 use Bitstamp for the start price. They use Coinbase for any end date from 2015-07-20. The cycle table mixes the two in the same way. - **The cycle table is ours.** "50% fall before a new high" is a simple objective rule. It counts April 2021 and April 2013 as tops, and many narratives would not. The stricter 75% variant is shown above, and it does not change the picture. The 2026 low is provisional. - **Same rules, no tuning.** Nothing was re-fitted. Every rule, threshold, horizon and merge gap is the sealed one, and the AFTER numbers are the published ones. ## Reproduce ``` uv run python samples/onchain1/before_after.py # needs the git-ignored raw/ price and header files (see MANIFEST.json) uv run pytest tests/test_onchain1_before_after.py ``` Derived statistics only; no price levels are published. Not investment advice.