# ONCHAIN-1 Family C: continuous-level and pooled-zone tests (preregistered, NOT BLIND) **Status:** written 2026-09-26 (UTC) and sealed with RFC 3161 timestamps (`holdout-audit seal-doc`) **before any Family C statistic was computed**. `run_family_c.py` does not exist at the time of sealing. ## 0. NOT BLIND: read this first This is a **preregistered but non-blind** test, and it is reported as such everywhere it is quoted. - The BTC price path through 2026-09-24 has been seen. - The Family A and Family B zone results (`results.json`, `SUMMARY.md`) have been seen, including every zone's episode dates and the average forward return after each zone. - Charts of these metrics against price are widely published; the author has a general impression of how valuation metrics behaved around the 2017, 2021 and 2024-25 highs. - No Spearman correlation, quintile table, pooled-event statistic or circular-shift null of the kind defined below has been computed on these data by this study. Why run it anyway: most Family A/B zone tests had 1 to 3 episodes and could not be tested. Family C uses every day of each metric's level (C1) and pools episodes across indicators (C2) to gain statistical power. What protects it is that every metric, sign, window, horizon, null, statistic and the multiple-testing family are fixed here, before computation, and that all results are published whatever they show. It cannot protect against choices shaped by what we have already seen; readers should weigh it accordingly. **Scope:** statistical analysis of past data only (`docs/SCOPE-POLICY.md`). No trading or investment advice. Asset guard unchanged: BTC price only; no commodities, metals or astro features; no leverage data (LRI-001 lock). **Governs:** Family C of ONCHAIN-1. The sealed preregistration (`prereg/preregistration.json`, SHA-256 `aafe3c37f5bbf83bc6e4b9a986ef1c936c3b74a927c253b833a5a7626482de40`) and `DEVIATION-001-data-source.md` (SHA-256 `f86c7d555e478b5f64d39b21510cc8cd1a8316cb1a3383d5b15ed3a14d2c3889`) are unchanged, and Families A and B and their results are not re-run or altered. ## 1. Data (no new data are fetched) - **Price:** the sealed Coinbase file `samples/data/raw/btc_daily.csv` (SHA-256 `064d2d183581eebe94c24ab3e69e318c369068c03adfe61bac39528f6a2d5c17`), missing days forward-filled, end 2026-09-24, loaded by `run.py`'s `load_price()` exactly as in Families A and B. - **UTXO metrics:** `bq/metrics_daily.csv` as committed (SHA-256 of the LF-normalised file `28c1e42349f110ed30d1d835349d8885849a80bafb4c61e0ff3d0e9ce4fea7df`; the CRLF bytes hashed in `MANIFEST.json` are `2884dae00f219963a14b7c1a3c7746b17769daf4c205ed0f62ae531616fc8fc2`; same content). No new BigQuery query. - **Block headers:** `raw/headers.csv` (git-ignored; SHA-256 `a69bc2d867edf4e5c46ea5b87aeb0e1fbc24ff795d7776b72407abe4f9025b15` per `MANIFEST.json`), used only to rebuild the Family A Puell and stock-to-flow series with `run.py`'s unchanged `load_issuance()`, `indicators()` and `s2f()`. - **Forward return:** F_h(t) = ln(close(t+h) / close(t)), h in {90, 365} calendar days, defined only if t+h <= 2026-09-24. ## 2. C1: continuous level tests For each metric M below and each h in {90, 365}: - **Sample:** every day t from the metric's OOS start (the verified effective start used in Families A/B) to 2026-09-24 minus h, on which both M(t) and F_h(t) are defined. M(t) uses data up to the close of t only (as computed for Families A/B). Let T be the number of such days. - **Statistic:** rho = Spearman rank correlation between M(t) and F_h(t) over the sample (average ranks for ties). - **Null:** circular shift of the metric relative to the returns. The metric's rank vector is rotated by k days (k drawn uniformly from the integers in [K, T - K], K = max(h, 365) = 365), and rho recomputed against the unshifted returns. The ranks are a permutation, so rotating them preserves each series' own autocorrelation and marginal distribution. 2,000 draws, `numpy.random.default_rng(20260925)`, a fresh generator per test (the Family A/B convention). - **p-value:** one-sided in the claimed direction d (d = -1 for a claimed negative correlation, +1 for positive): p = (1 + #{d x rho_null >= d x rho_obs}) / 2001. - **Quintile table (descriptive only, no inference):** days are split into quintiles of M over the same sample (the edges use the full sample, so they use hindsight; this table is descriptive and never evidence). For each quintile: number of days, mean M, mean F_h and exp(mean F_h) - 1. | ID | Metric (series) | OOS start | Claimed sign | Why that sign | |---|---|---|---|---| | C1-MVRV | MVRV = market cap / realized cap (column `mvrv`) | 2018-11-01 | negative | Top-type valuation metric: high values claimed to precede weak returns, low values strong returns. **MVRV is identical to price / realized price** by construction (MC / RC = close x S / (RP x S); checked numerically before sealing: ratio exactly 1). It is tested once, under this ID, from B6's realized-price start (the MVRV ratio, Mahmudov & Puell, Oct 2018, predates it). | | C1-MVRVZ | MVRV Z-score, sealed expanding-window version (`mvrv_z`, never `mvrv_z_fullhistory_lookahead`) | 2018-10-10 | negative | Top-type (B1). | | C1-SOPR | SOPR, unadjusted, 7-day SMA (`sopr_sma7`) | 2019-04-26 | negative | Creator (Shirakashi 2019): SOPR below 1 means coins sold at a loss (capitulation / reset, a claimed buying opportunity); high SOPR means profit-taking. Our reading of that claim as a level relation: lower SOPR, higher forward return. The creator's claim was made conditional on a bull market (B3); the unconditional level test is ours. | | C1-RR | Reserve Risk (`reserve_risk`) | 2019-05-31 | negative | Creator (Hauge 2019): low = high confidence / attractive, high = top zone. | | C1-STH | close / STH cost basis (`sth_cost_basis`) | 2021-07-01 | **positive** | Support/regime claim (B5, Glassnode): price above the STH cost basis marks a bull regime with higher forward returns. This is a momentum-type claim, so its sign is opposite to the valuation metrics. | | C1-PI | Pi Cycle ratio = 111-day SMA / (2 x 350-day SMA) | 2019-05-01 | negative | Top-type (A1): the ratio reaching 1 is claimed to mark cycle highs. | | C1-MAYER | Mayer Multiple = close / 200-day SMA | 2018-01-01 | negative | Top-type (A3): above 2.4 overheated, low values for accumulation. | | C1-2YMA | close / 730-day SMA | 2017-08-01 | negative | A4: below 1 buy, 5 or more take profit. | | C1-200WMA | close / 200-week MA (Sunday closes, as A2) | 2019-05-19 | negative | A2: close to or below the 200WMA claimed good times to buy. | | C1-PUELL | Puell Multiple (daily issuance, as A5) | 2019-04-01 | negative | A5: > 4 tops, < 0.5 bottoms. | | C1-S2F | close / PlanB stock-to-flow model price (as A6) | 2019-03-23 | negative | A6: price reverts toward the model, so below-model days claimed to precede higher returns. | **NUPL is not a separate test.** NUPL = 1 - 1/MVRV exactly (checked numerically before sealing: maximum difference 4e-10), a strictly increasing function of MVRV, so its Spearman correlation equals MVRV's over any common window. Counting it again would test the same hypothesis twice. For completeness, rho for NUPL over its own window (from 2019-03-01) and for price / realized price are reported descriptively, outside the Holm family. C1 contains 11 metrics x 2 horizons = **22 tests**. ## 3. C2: pooled zone tests (signal onsets) Two pools, by claim type. Each member is a zone exactly as sealed for Families A/B, evaluated from that member's OOS start. - **Bottom pool (claimed direction: positive):** NUPL < 0 (B2, from 2019-03-01); close < realized price (B6, 2018-11-01); Reserve Risk < 0.0026 (B4, 2019-05-31); MVRV-Z < 0 (B1 secondary, 2018-10-10); and the Family A bottom zones: close <= 1.10 x 200WMA (A2, 2019-05-19), close < 2-year MA (A4, 2017-08-01), Puell < 0.5 (A5, 2019-04-01), close < stock-to-flow model price (A6, 2019-03-23). - **Top pool (claimed direction: negative):** MVRV-Z > 5 (B1, 2018-10-10) and the Family A top signals: Pi Cycle crossing days (A1, 2019-05-01), Mayer Multiple > 2.4 (A3, 2018-01-01), close >= 5 x 2-year MA (A4, 2017-08-01), Puell > 4 (A5, 2019-04-01). Also the sealed Family B top bands, for completeness: NUPL >= 0.75 (B2) and Reserve Risk > 0.02 (B4). - **Not pooled:** SOPR bull-reset (B3) and close above STH cost basis (B5) are conditional bull-regime claims at a 90-day horizon, not cycle-bottom claims; the stock-to-flow above-model zone was a secondary reversion zone, not a published top signal. **Why onsets rather than zone days.** Pooling by the union of zone days would be dominated by chronic zones: it is already known from Family B that Reserve Risk < 0.0026 was on for 75% of OOS days and continuously since January 2022, so a union would merge nearly everything after 2021 into one long episode and lose power, the opposite of the aim. Family C therefore pools **signal onsets**: 1. For each member, its episodes are computed exactly as in Families A/B (runs of zone days over its OOS window, gaps under 30 days merged). Each episode's first day is an **onset**. An episode already in progress on the member's first OOS day (zone on the day before the OOS start) is excluded: that signal fired before publication. 2. The pool's onsets are sorted by date; an onset fewer than 30 calendar days after the previously kept onset (from any member) is a duplicate and is dropped (the earliest is kept). This is the existing 30-day merge gap, applied across indicators. 3. **Statistic:** D = mean F_365 over the kept onset days minus mean F_365 over all days of the pool window (from the pool's earliest member OOS start, 2017-08-01 for both pools, to 2026-09-24 minus 365), onsets without F_365 excluded. 4. **Null (joint):** the pooled onset indicator vector over the pool window is rotated by k (k uniform in [365, T - 365], 2,000 draws, seed 20260925), which shifts every member's onsets by the same k; D is recomputed. One-sided p in the claimed direction, as in C1. 5. **Testability:** INFERENTIAL only if at least 5 kept onsets have F_365 defined; otherwise DESCRIPTIVE ONLY, and the test enters Holm with p = 1. Reported alongside each pool (descriptive, outside Holm): the list of kept onsets with their member(s), each onset's F_365, and, for transparency, the zone-day union version (Family A/B `zone_test` on the union zone) with its episode count. C2 contains **2 tests**. ## 4. Multiple testing One Holm family for all Family C tests: **m = 24** (22 in C1 + 2 in C2), step-down at family-wise alpha = 0.05 on the one-sided p-values. Family C is separate from the Family A (m = 6) and Family B (m = 6) families, which are not changed. Verdicts: C1: **ASSOCIATION SUPPORTED** if Holm-adjusted p <= 0.05, otherwise **NOT SUPPORTED** (reported as "no statistically robust association"). C2: **SUPPORTED** / **NOT SUPPORTED** likewise, or **NOT TESTABLE (descriptive only)** under the testability rule. A result significant in the wrong direction is NOT SUPPORTED; its two-sided nature is only described, never claimed. ## 5. Interpretation rule A significant C1 correlation is **evidence of an association between the metric's level and later BTC returns over this period, not a tradable edge**. Family C grades no trading rule and runs no strategy audit; no rubric grade is issued. Overlapping daily forward returns mean the effective sample is a few market cycles; the circular-shift null accounts for this, but a result driven by two or three cycles is still a result about two or three cycles, and the write-up says so. Pooled results (C2) describe what followed the onsets of these signals as a group, not any single indicator. ## 6. C3: forward watch (prospective, blind) From 2026-09-25 onward, `samples/onchain1/FORWARD-WATCH.md` logs every new signal onset of the rules below, as data become available. **Nothing is evaluated now.** Rules watched (each exactly as sealed for Families A/B; an onset is the first day of a new episode, gap-under-30-days merge): - Top: Pi Cycle crossing (A1); Mayer Multiple > 2.4 (A3); close >= 5 x 2-year MA (A4); Puell > 4 (A5); MVRV-Z > 5 (B1); NUPL >= 0.75 (B2); Reserve Risk > 0.02 (B4). - Bottom: close <= 1.10 x 200WMA and close < 200WMA (A2); close < 2-year MA (A4); Puell < 0.5 (A5); close < stock-to-flow model (A6); MVRV-Z < 0 (B1); NUPL < 0 (B2); Reserve Risk < 0.0026 (B4); close < realized price (B6). - Regime: close > 200-day SMA with SOPR 7-day SMA <= 1 (B3); close crossing above / below the STH cost basis (B5). Log protocol: append-only, one line per onset (UTC date, rule, metric value, data source and file hash); entries are committed to git and never edited (corrections are appended as new lines). Price data after 2026-09-24 and UTXO metrics after that date require a later data refresh (a new price fetch and, for UTXO metrics, a logged BigQuery run); each refresh is recorded in the log. Zones already on at 2026-09-24 (continuing episodes) are recorded once as "in progress at start", not as new onsets. Any evaluation of forward returns after logged onsets requires its own sealed plan, written before any forward return after an onset is computed. ## 7. Implementation commitments - One script, `samples/onchain1/run_family_c.py`, reusing `run.py`'s `load_price`, `load_issuance`, `indicators`, `s2f`, `episodes`, `zone_test` and `holm` unchanged. It asserts the hashes above before computing anything. Results go to `samples/onchain1/family_c_results.json` and a Family C section in `SUMMARY.md` (with the NOT BLIND caveat in its first lines). Synthetic tests (the null gives roughly uniform p on independent series; a planted correlation is detected) are added to `tests/`. - The analysis is run once. A crash before any statistic is computed may be fixed and disclosed; any change to a definition after a statistic has been computed is a disclosed deviation, and the originally specified result is still reported. - Everything is published, whatever it shows.