feat(runtime): add report-only intraday liquidity diagnostics#55
Merged
Merged
Conversation
P-I5f: an opt-in, REPORT-ONLY execution liquidity diagnostic for the intraday tail-rebalance path. For each desired rebalance trade (|target_weight - current_weight|) it sizes the trade against the SELECTED execution-minute 1min bar's traded amount (RMB) at a max participation rate and reports a capacity ratio. It uses ONLY the execution-minute bar already chosen by the tail execution model — never a future bar, daily amount/volume/close, or any EOD proxy. Report-only: it never changes fills, can_buy/can_sell, blocked reasons, target weights, achieved holdings, turnover, cost, NAV, factor scores, MMP grouping, alpha, or portfolio construction. Default-off, so every existing config validates and behaves byte-identically. - qt/config.py: nested LiquidityDiagnosticsCfg under intraday (enabled=false default; when enabled requires positive portfolio_notional, participation in (0,1], and only mode=report_only — each with a readable error). - runtime/backtest/engine.py: additive, default-off record_rebalance_plan flag + rebalance_plan_log() capturing the (target, current) weights the engine used; default False keeps the loop byte-identical (no plan rows, no behaviour change). - runtime/backtest/event_models.py: additive accessors exposing the raw up/down limit blocked-key sets so the diagnostic skips already-blocked trades without reclassifying their original reason. - runtime/intraday_liquidity.py (new): pure formula primitives + the report-only builder (feasibility-blocked excluded with original reason kept; missing/NaN/<=0 amount reported as missing capacity data; zero desired trade skipped). - qt/intraday_tail_framework.py: wires the diagnostic into the intraday-tail report path only when enabled; new report section states it did not alter fills/NAV. - config/phase_i5f_intraday_liquidity_diagnostics.yaml (new): SSE50 smoke based on the I5b config, illustrative 10,000,000 RMB sizing. - tests/test_i5f_intraday_liquidity.py (new): formula, config validation, and report-only invariants (enabling the plan log does not change NAV/turnover/cost/ holdings; capacity uses the execution-minute amount only; existing blocks keep their original reasons).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
P-I5f: an opt-in, report-only execution liquidity diagnostic for the
intraday tail-rebalance path. For each desired rebalance trade
(
|target_weight - current_weight|) it sizes the trade against the SELECTEDexecution-minute 1min bar's traded
amount(RMB) at a max participation rate andreports a capacity ratio:
It uses ONLY the execution-minute bar already chosen by the tail execution model —
never a future bar, daily amount/volume/close, or any EOD proxy.
Report-only: it never changes fills,
can_buy/can_sell, blocked reasons,target weights, achieved holdings, turnover, cost, NAV, factor scores, MMP
grouping, alpha, or portfolio construction. Default-off, so every existing
config validates and behaves byte-identically.
Changed files (7)
qt/config.py— nestedLiquidityDiagnosticsCfgunderintraday(enabled=falsedefault; when enabled: positive
portfolio_notional,max_participation_ratein(0,1], and onlymode=report_only— each with a readable error).runtime/backtest/engine.py— additive, default-offrecord_rebalance_planflag +
rebalance_plan_log()capturing the exact(target, current)weights theengine used. Default
Falsekeeps the loop byte-identical (no plan rows, nobehaviour change).
runtime/backtest/event_models.py— additive accessors exposing the raw up/downlimit blocked-key sets, so the diagnostic skips already-blocked trades without
reclassifying their original reason.
runtime/intraday_liquidity.py(new) — pure formula primitives + the report-onlybuilder.
qt/intraday_tail_framework.py— wires the diagnostic into the intraday-tailreport path only when enabled; new section states it did not alter fills/NAV.
config/phase_i5f_intraday_liquidity_diagnostics.yaml(new) — SSE50 smoke based onthe I5b config; illustrative
10,000,000RMB sizing.tests/test_i5f_intraday_liquidity.py(new, 17 tests).Smoke (cache-only minute, real SSE50)
run-phase-i5a-intraday --config config/phase_i5f_intraday_liquidity_diagnostics.yamlperiods=3, covered=58/58, stk_mins_live_calls=0, final_nav=0.976448.final_nav=0.976448is byte-identical to the accepted I5b smoke → enablingthe diagnostic did not move the book (report-only confirmed end-to-end).
reason kept), 0 missing-capacity, 42 inspected, 20 below 1.0x;
capacity ratio min
0.122/ p100.222/ median1.104/ p902.730.large-caps often can't absorb a 1M RMB trade at 5% participation; that's the point.
Gates (all green)
tests/test_intraday_execution.py test_i5b_execution_feasibility.py test_i5d_mmp_quintile.py: pass.pytest -p no:cacheprovider: 696 passed (678 baseline + 17 new I5f teststest_cache_config.pyconfig-glob auto-covering the new config).ruff: clean ·validate-config: 19/19 OK ·run-phase0: ic_mean=0.9600,annual_return=0.8408 unchanged.
git diff --check main...HEAD: clean; no merge markers.output; report/log contain no
.config.json/tushare.token.Report-only invariants (tested)
(engine
assert_frame_equal);amount is ignored);
stk_limitblocks keep their originalreasons and are never reclassified as liquidity blocks.
Non-goals honored
No partial-fill / volume-cap enforcement; no change to
simulate_fills/SimExecution/BacktestEngine/IntradayTailEventModelbehaviour beyondadditive + default-off; no MMP research or I5d/I5e rerun; no daily-volume proxy; no
D6 / schema registry / cache refactor; no progress-doc edits (AGENTS.md /
CLAUDE.md / contract untouched — separate post-acceptance goal); PR #38
untouched.