Cryptolean
// Methodology · align

Putting two sources on the same calendar day.

Current definition align-v2. Charts stamped with it were computed by src/metrics/alignment.py, and every value plotted for a past date could have been computed on that date.

Definition and failure modes

The finding. blockchain_com stamps a daily value one calendar day later than Binance and Yahoo do. Its 00:00 UTC print is the previous day's close; Binance stamps a kline at its open. So BTC dated D lines up with every other tracked asset dated D−1.

Measured on daily log returns against ETH, the correlation at lag 0 is ≈0.00 and at lag −1 is ≈0.82, and that holds in 2018-2020, 2021-2022 and 2024-2026 alike. A stable ~0.82 sitting one day off a ~0.00 is a calendar convention, not a market relationship. Yahoo (BCH) and Binance agree at lag 0 and need no correction.

Why this is not fixed in src/fetch/. It should be, and the fetch layer is not this workstream's to change. More importantly, moving BTC's index by a day would move the 365-day mean, the expanding extremes and therefore every historical value of risk-v1 — a silent rewrite of the flagship metric to fix a cross-asset chart. So the correction lives here, is opt-in, and is applied only where two sources are compared to each other:

- single-asset charts:      never aligned; each asset against its own history
- cross-source comparisons: aligned, and the chart says so

measure_lag exists so the constant below can be re-derived from the data rather than trusted, and tests/test_charts.py re-derives it on every run. If a source changes its convention, the test fails instead of the charts quietly going wrong.

The second problem: forward-filled calendars. SPX, GOLD and SILVER arrive on a seven-day index with weekends and holidays carrying the previous close. Measured: 100% of Saturdays and Sundays are zero-change on all three, against 2.3% for Bitcoin. The S&P frame holds 36,014 rows for roughly 24,750 actual sessions.

That is fine for a price line and wrong for anything that counts days. Two sevenths of every window are fabricated flat observations, so the daily return spread comes out about 21% low, correlation is diluted by a mass of artificial zeros on one side of each pair, and a run-length or advance/decline count is measuring the calendar. sessions() recovers the real observations; periods_per_year() gives the annualiser that goes with them.

The fetch layer should carry an is_session column and this heuristic should then be deleted. Until it does, the detection is measured from the data rather than declared per source, because yahoo serves both ^GSPC on a five-day calendar and BCH-USD on a seven-day one — the calendar is a property of the instrument, not of the vendor.

Version history

Newest first. Each entry says what changed and whether values that had already been published moved with it, followed by the sentence from the module that decided the verdict.

  1. align-v22026-08-06AdditiveCurrent

    sessions(), periods_per_year(), common_returns() and the crypto/benchmark symbol split. align-v1's offsets are unchanged and no existing series moves.

    Output was added. Nothing already published changed, so every chart drawn under the previous version still reads the same.

    • unchangedsessions(), periods_per_year(), common_returns() and the crypto/benchmark symbol split. align-v1's offsets are unchanged and no existing series moves.
  2. align-v12026-08-05Initial

    blockchain_com offset measured at −1 day; Binance and Yahoo at 0. Applied to cross-source charts only.

    The first version of this metric. There is no earlier definition to restate.

Charts drawn with it

2 charts name this metric in their readout line. 1 name it first, so a count taken from the leading stamp alone reports 1 rather than 2. A chart built on several definitions carries all of them, and being second in that list is not the same as being unused.

Current version
align-v2
Versions on record
2
First dated
2026-08-05
Restatement policy
Never moved
Never restated. Every bump on record added output without redefining what was already there.
Charts
2
Source
src/metrics/alignment.py
Public functions
aligned_close, aligned_panel, benchmark_symbols, common_returns, crypto_symbols, is_business_calendar, measure_lag, offset_days, periods_per_year, session_close, sessions
Machine-readable
catalog.json · llms.txt