Skip to main content

falsification-ledger

PyPI version PyPI downloads CI License

Featured in awesome-quant — the curated list of quant libraries (Trading & Backtesting section).

中文说明

falsification-ledger 是量化研究的可验证实验记录本,也适用于 A 股回测。 研究开始前先登记假设,以及什么证据会推翻它;之后把证据写入追加式、 哈希串联的记录,再进行一次性裁决和命中率统计。它帮助减少事后挑选结果, 但不替代数据审计、统计检验或人工判断。

A hash-chained, append-only ledger for research claims: pre-register the hypothesis and the evidence that would kill it before the study runs, then adjudicate honestly and measure your hit rate against a random baseline. Python 3.11+, one dependency (jsonschema), Windows / Linux / macOS.

Status: v0.1.1 alpha, published on PyPI. The ledger semantics are distilled from a production research pipeline, but this standalone package is new: expect the CLI and schemas to shift before v1.0.

Why this exists

Quantitative research has a self-deception problem: you test 500 factor ideas, remember the 3 that worked, and forget the 497 that died. By the time you "validate" the lucky survivors, the evidence is already contaminated by what you saw. Every backtest-hygiene tool on the market attacks the statistics of this problem (deflated Sharpe, PBO, multiple-testing corrections). falsification-ledger attacks the process: it makes you write down, before seeing evidence:

  • what you expect (support / against / uncertain), and
  • what evidence would kill your claim (the falsification contract).

Then it keeps the receipts. Every event lands in an append-only JSONL hash chain —any edit after the fact is detected by fl verify —and the report answers the only question that matters: do your pre-registered beliefs actually hit, or is your hit rate indistinguishable from a random baseline? (Wilson 95% CI vs the most common actual verdict.)

Philosophy

Research is a promise; the ledger keeps it.

  • Falsifiability is the default, not the exception. Popper's criterion —a claim is scientific only if something could count against it —is usually invoked as a lecture. Here it is a required JSON field (falsification_contract on preregister).
  • Pre-analysis plans have known costs and benefits. Olken (2015), "Promises and Perils of Pre-Analysis Plans" (JEP 29(3)) documents both; this tool implements the benefits (frozen expectations, audit trail) while keeping the costs explicit (uncertain verdicts and exploratory source types are first-class, so you can register what you genuinely do not know).
  • Moderation beats total freezing. Banerjee & Duflo, "In Praise of Moderation" argue for layered pre-registration; source_type (paper / business / cross_domain / pipeline / other) exists so confirmatory and exploratory claims are never mixed in the same bucket.
  • Finance can become scientific. López de Prado (2023), Causal Factor Investing asks whether factor investing can become a science; this ledger is one concrete answer —evidence with a chain of custody, adjudicated against a pre-registered expectation.
  • Automated research needs machine-checkable evidence. EviBound (arXiv:2511.05524) and ECLIPSE v2.0 argue that agentic research pipelines must eliminate false claims through verifiable evidence; fl submit validates falsification reports against a JSON Schema and computes content IDs, so gates can trust the evidence without trusting the messenger.

See it in action

fl verify catching a retroactive edit — every event is a hash-chain link, and a one-field change breaks the chain at a specific line number:

fl verify tamper detection

And the report speaks plainly. On a real 8-case demo ledger, fl report answers the only question that matters — are you better than a coin flip?:

fl report output

Full JSON: docs/report-example.txt — hit rate 0.71 with a 95% Wilson CI of [0.36, 0.92] against a 0.57 random baseline: baseline inside CI, so the report says "no systematic signal" — and refuses to pretend otherwise.

Quick start

# install the published package from PyPI
pip install falsification-ledger

# or run without installing anything:
#   PYTHONPATH=src python -m falsification_ledger --help

# try the full loop on a scratch ledger (creates files under a temp dir)
python examples/demo.py

The manual loop:

fl init --state-dir ~/.research-ledger

# 1. BEFORE running the study: register what you expect,
#    and what evidence would kill the claim.
fl preregister --state-dir ~/.research-ledger \
  --case-id MOMENTUM-OOS-2026Q3 \
  --verdict support \
  --reason "momentum rank IC stays positive OOS" \
  --source-type paper \
  --contract kill-criteria.json

# 2. When an independent check produces evidence, submit it:
fl submit --report falsification-report.json
# -> {"content_id": "sha256:...", "evidence_status": "valid", ...}

# 3. AFTER the study: adjudicate honestly.
fl adjudicate --state-dir ~/.research-ledger \
  --case-id MOMENTUM-OOS-2026Q3 --verdict support

# 4. Measure whether you are better than a coin flip.
fl report --state-dir ~/.research-ledger --min-cases 20

# 5. Any time: prove nobody rewrote history.
fl verify --state-dir ~/.research-ledger

Commands

Command What it does
init Create the ledger state directory
preregister Register a claim: --case-id, --verdict (support/against/uncertain), --reason, optional --source-type, optional --contract (falsification contract JSON). Duplicate registration for the same case is rejected
submit Validate a falsification report against the contract schema; print its content ID (sha256:...) and evidence status (valid / invalid / missing). Read-only; exits non-zero on blockers
adjudicate Backfill the actual verdict for a registered case (register required; once per case)
report Hit-rate report: resolved cases, completeness, participation, hit rate with Wilson 95% CI, random baseline, per-source-type breakdown, verdict_ready gate
verify Recompute the hash chain of the whole ledger; detects any edit, insertion, or reordering
version Print version

Global flag: --state-dir on every stateful command (default: none —the ledger path is always explicit, so a git add . can never sweep it into version control).

Ledger format

The ledger is a JSONL file at <state-dir>/ledger.jsonl. Every line is one event:

{"schema_version": "falsification_ledger.prediction_event.v1",
 "event": "register", "record_id": "...", "case_id": "CASE-1",
 "expected_verdict": "support", "expected_reason": "...",
 "source_type": "paper", "falsification_contract": {...},
 "actual_verdict": null, "recorded_at": "...", "concluded_at": null,
 "prev_hash": null,
 "event_hash": "sha256(prev_hash || 0x00 || canonical payload)"}

verify recomputes every event_hash and checks each prev_hash link. Any tampering —editing a reason, deleting a line, reordering events —breaks the chain at a specific line number.

Falsification reports

A falsification report is the machine-readable evidence produced by an independent check (null-model randomization, OOS rank IC, FDR correction, protocol deviation, effect CI, cost sensitivity, ...). The contract:

  • schema: schema/falsification-report.schema.json (draft 2020-12, additionalProperties: false, fail-closed);
  • content ID: sha256: over domain-prefix || 0x00 || canonical JSON — the same report always yields the same ID, a one-field change yields a different ID;
  • evidence status (fail-closed for gates):
    • valid —conformant, conclusion not_falsified, consistency intact;
    • invalid —non-conformant, or conclusion falsified, or explicitly inconsistent;
    • missing —conclusion inconclusive: treated as absent evidence.

Verification model

fl verify is the tamper-evidence layer: it re-derives the entire chain from the file bytes and reports the first bad line. Combined with preregister (frozen expectations) and submit (content-addressed evidence), a research pipeline can prove to itself —and to reviewers —that the expectation existed before the evidence did. Nothing here trades, prices, or decides.

Development

python -m pip install -e . pytest
python -m pytest

CI runs the full test suite on Ubuntu, Windows and macOS with Python 3.11 and 3.12. Issues are handled on weekends; pull requests are welcome.

Related work

Project family

Part of Holdout — a toolchain against self-deception in quantitative research:

Sister org: Metabolism Toolsworkspace-metabolism, policy-driven file lifecycle management for agentic workspaces.

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

falsification_ledger-0.1.2.tar.gz (21.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

falsification_ledger-0.1.2-py3-none-any.whl (16.0 kB view details)

Uploaded Python 3

File details

Details for the file falsification_ledger-0.1.2.tar.gz.

File metadata

  • Download URL: falsification_ledger-0.1.2.tar.gz
  • Upload date:
  • Size: 21.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for falsification_ledger-0.1.2.tar.gz
Algorithm Hash digest
SHA256 7a21d20a4d11f620571ab6bc956fc9b2c0b334c7a325983f6d7ee41d67be1db6
MD5 20871752f9201fd0767221eb830733e2
BLAKE2b-256 027e63adedf9625700ccb3212a63bc8028562d663ec2b425cc4dac27b76fe4c4

See more details on using hashes here.

File details

Details for the file falsification_ledger-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for falsification_ledger-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 14d3d8cfd14bbc96e40381730914a7ff461d5ed2b6a1a94e8f56c6e0798edb17
MD5 52724320cf73618019e7249dd93c1671
BLAKE2b-256 ac69d335682e87a9758a6d9b16b36c9313007cb766a2183acd0371f40898cdfd

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.2 This release

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page