Skip to main content

pit-adjuster

PyPI version PyPI downloads CI License

中文说明

pit-adjuster 面向 A 股等股票市场的历史行情复权和公司行为数据处理。 它根据带时间点的公司行为档案重建固定基准价格,检查复权因子链是否连续, 并识别数据供应商悄悄切换复权口径的情况。工具只处理和验证历史数据, 不预测价格、不提供交易建议;公司行为的发生日、公告时间和数据覆盖范围 必须由使用者提供并核验。

Point-in-time fixed-basis back-adjustment engine for daily price history: rebuild prices so that any day reads exactly what that day could have known —plus drift detection for vendors that silently switch adjustment conventions. Python 3.11+, zero dependencies, Windows / Linux / macOS.

In plain words: data vendors silently switch adjustment conventions — the 2019 prices you see today may not be the ones you saw yesterday, and nothing in the CSV changes shape. pit-adjuster detects that change and rebuilds history from a point-in-time corporate-action archive, so your backtest never quietly breaks because the data's meaning changed under you.

adjustment chain python

Status: v0.1.1 alpha, published on PyPI. The adjustment math is battle-tested inside a production research pipeline, but this standalone package is new: expect the CLI and schema to shift before v1.0.

Why this exists

A-share (and most equity) history arrives from vendors in current-vintage adjusted form. Two silent dangers:

  1. The convention itself is not point-in-time. Prices you see today embed every adjustment event that ever happened —including events that were announced after a historical date. A backtest that uses them reads the future.
  2. Vendors switch conventions silently. One day your data source starts serving forward-adjusted prices where it served back-adjusted prices yesterday. Nothing in the CSV changes shape; every historical signal silently changes value.

pit-adjuster rebuilds history from two ingredients —current-vintage forward-adjusted (qfq) bars plus a point-in-time corporate-action archive —into a fixed-basis back-adjusted (hfq) chain where each day's price depends only on events whose ex-date is on or before that day. Then it checks: did the rebuild invert the vendor chain correctly, and does the vendor chain still agree with live raw prices today?

Philosophy

Price history must be reversible. A research pipeline that cannot prove its prices were knowable in the past is not doing backtesting —it is doing wishful thinking. pit-adjuster treats look-ahead freedom as a verifiable property, not a style preference:

  • PIT principle —every price, factor, and calibration depends only on information available at that historical point. See Kelly et al., "Scaling Point-in-Time Language Models" (NBER w35247) and Look-Ahead-Bench (arXiv:2601.13770) for why the whole industry is converging on this.
  • Look-ahead bias is measurable —Daniel, Sornette & Wohrmann (2008), "Look-Ahead Benchmark Bias in Portfolio Performance Evaluation" (arXiv:0810.1922) quantify how ex-post benchmark construction inflates performance. A vendor that silently swaps adjustment conventions is doing exactly this, inside your price column.
  • Formal ground —Fonseca (2026), "Look-Ahead-Freedom as Temporal Non-Interference" (arXiv:2607.04958) proves look-ahead-freedom is undecidable in general (Pi-0-1-hard when availability depends on data values), but admits a linear-time decidable type-effect system on the value-independent fragment —windowing, resampling, joins, PIT and vintage reads.

Honest boundary: this package implements verifiable checks for the value-independent fragment of the problem (factor chains, ex-date ordering, snapshot equivalence, chain inversion). For the general value-dependent case we fall back to heuristic guards and say so explicitly —verifiability is claimed only where the theory allows it.

Quick start

# install the published package from PyPI
pip install pit-adjuster

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

# try it on synthetic data (builds a fake qfq history + action archive,
# rebuilds to hfq, runs invert-check and drift-check)
python examples/demo.py

Rebuild your own history:

padj rebuild \
  --bars bars.json --actions actions.json \
  --as-of 2026-08-11 --code 600000 --out hfq.json

padj invert-check --bars hfq.json --actions actions.json --as-of 2026-08-11
padj drift-check --bars hfq.json --actions actions.json \
  --as-of 2026-08-11 --live live_closes.json

padj rebuild is the workhorse: it inverts the vendor qfq chain back to raw prices, then re-applies only events whose ex-date is on or before each bar date (fixed basis at the archive coverage start). Raw open/close are kept alongside adjusted prices so execution-level work can map back to nominal prices.

Commands

Command What it does
rebuild Rebuild bars to fixed-basis hfq: open/high/low/close adjusted, raw_open/raw_close nominal, adj_factor cumulative multiplier, volume normalized to shares
invert-check Ex-date continuity sanity check: is raw_{ex-1} × factor_e ≥ raw_ex? Informational —real ex-dates carry overnight returns, so violations can be false positives
drift-check Static forward-adjustment detection. Compares inverted raw closes against live raw closes; divergence above tolerance is authoritative —a vendor chain that no longer matches the archive
snapshot-equivalence Compare two rebuilt outputs (e.g. old and new pipeline versions) date-by-date within tolerance —the "did anything change?" gate
version Print version

Global flags: --help on every subcommand; JSON outputs via --out where supported; everything else prints a human-readable summary.

Data model

Bars —a JSON list of daily bars, each with at least date (ISO) and close; open/high/low/volume/amount/turnover are preserved through the rebuild:

{"date": "2026-06-12", "open": 95.0, "high": 96.0, "low": 94.5, "close": 95.5, "volume": 1234500}

Actions —a point-in-time corporate-action archive, one record per event, with ex_date, adjustment_factor and available_at:

{"ex_date": "2026-06-15", "adjustment_factor": 0.95, "available_at": "2026-06-14T18:00:00", "action_type": "cash_dividend_stock_distribution"}

Invalid records (missing ex-date, non-positive or non-finite factor) are dropped; only events with ex_date <= as_of_date participate. The schema lives in schema/corporate-action.schema.json.

Adjustment math

Standard A-share factor math (as documented by exchange reference-price rules):

factor_e = (prior_close - cash) / (prior_close * (1 + bonus + transfer))
qfq_t    = raw_t * prod_{e: ex_date_e > t} factor_e
hfq_t    = raw_t * prod_{e: ex_date_e <= t} (1 / factor_e)

rebuild inverts the vendor qfq chain back to raw prices, then applies the hfq chain with a fixed basis at the archive coverage start. Key property (under test): hfq and qfq yield identical adjusted returns for the same factor chain, while hfq additionally guarantees that a price at time t is untouched by events with ex-date after t.

Volume normalization follows the A-share convention: most codes store volume in lots (×100 to shares); STAR-market codes (688/689 prefixes) store native shares. Both are parameterizable —see --volume-to-shares and the native_share_prefixes argument in rebuild_bars.

Verification model

pit-adjuster never trusts its inputs:

  • invert-check —factor continuity at ex-dates (sanity, false-positive tolerant)
  • drift-check —inverted raws vs live raws (authoritative divergence detection; this is the "static forward-adjustment detector" —if a vendor swaps conventions, this fires)
  • snapshot-equivalence —before/after equivalence of two rebuilds, the reproducibility gate for pipeline migrations

Every check is read-only. 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 Tools — workspace-metabolism, policy-driven file lifecycle management for agentic workspaces.

License

MIT

Metadata

Release files for pit-adjuster 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pit-adjuster 0.1.2
File Size Uploaded
pit_adjuster-0.1.2.tar.gz 22.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pit-adjuster 0.1.2
File Interpreter ABI Platform
pit_adjuster-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 38.1 kB

Release files / pit_adjuster-0.1.2.tar.gz

Download URL pit_adjuster-0.1.2.tar.gz
Size 22.1 kB
Tags Source
SHA-256 checksum
How to use checksums
f63e0f793c8211cada82f7520a682e2e066c8fa3325aec71eb526a00cfaacd9a
BLAKE2b-256 checksum
How to use checksums
4b90fba97799b1b47c699e55f9b816f29fded3f023aa8af4b91d1d59032d5edd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release files / pit_adjuster-0.1.2-py3-none-any.whl

Download URL pit_adjuster-0.1.2-py3-none-any.whl
Size 16.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f4bc76a9a7f2a6287dbeba2849b1202bb1031cdbd9aff3191db5ada1a765bf40
BLAKE2b-256 checksum
How to use checksums
5a5f41bbab8bc27ddbb547249351a770cf7774db4ef3faec6c699c7c1d73fd8a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.15

Release history Release notifications | RSS feed

0.1.5

2 release files

0.1.3

2 release files

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release 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