Skip to content

feat(factors): reproduce minute ideal-amplitude factor + eval run (PR-D) - #64

Merged
StackOverFlow11 merged 2 commits into
mainfrom
feat/pr-d-minute-ideal-amplitude
Jul 19, 2026
Merged

feat(factors): reproduce minute ideal-amplitude factor + eval run (PR-D)#64
StackOverFlow11 merged 2 commits into
mainfrom
feat/pr-d-minute-ideal-amplitude

Conversation

@StackOverFlow11

Copy link
Copy Markdown
Owner

Summary

Reproduce the minute ideal amplitude factor from Kaiyuan Securities market-microstructure series #30 (2025-08-09) as the second report-reproduction factor (PR-D, loop 1/10), mirroring the accepted PR-C (jump_amount_corr) machinery end to end.

Factor minute_ideal_amp_10: pool the trailing N=10 trading days of 1min bars (PIT-filtered available_time <= d 14:50 BEFORE aggregation), per-bar amplitude = high/low − 1 (guards low>0, high>=low), require pooled n>=1150 else NaN, rank by raw minute close ((close, bar_end) tie-break), k=floor(0.25n); factor = mean(amp of top-k closes) − mean(amp of bottom-k closes). Pre-registered sign −1 (report: full-market IC −0.059 / ICIR −3.1). Daily signal traded close-to-close (is_intraday=False, same rationale as PR-C).

Components (all additive; frozen analytics/eval untouched): data/clean/intraday_amplitude.py (new, 200L) · MinuteIdealAmplitudeFactor in factors/compute/intraday_derived.py · runner qt/eval_minute_ideal_amplitude.py + CLI subcommand · config/phase_d_minute_ideal_amp.yaml (only substantive diff vs phase_c: the factor) · 23 new tests (hand-computed values, post-14:50 perturbation leakage tests, cross-symbol isolation, tie determinism, NaN gate, cache-only loader, two-run runner + dashboards).

Real run (CSI500 2021-07..2026-06, OOS split 2024-01-01, cache-only minutes: covered=995/996, stk_mins_live_calls=0, 486.6s): IC mean −0.02915, ICIR −0.4644, NW-t −16.33, N_eff 1205, IC win rate 0.687. Verdict Watch / Watch (exploratory cap): Predictive PASS (sign held both OOS subperiods); Incremental PASS vs value_ep/value_bp/volatility_20 book (orth. ICIR lower CI +0.195 > 0.15); Tradable NOT_ASSESSED. Prototype sanity pre-run: mean daily RankIC −0.0236 (sign matched pre-registration). Not a return/deployment claim.

Test plan

  • Full pytest: 1262 passed (baseline 1238 + 24; zero baseline tests disturbed) — rerun independently by orchestrator
  • ruff clean; phase0 regression ic 0.9600 / annual 0.8408 unchanged
  • Independent code review: APPROVE, no CRITICAL/HIGH/MEDIUM (factor math, PIT order, no-touch, runner fidelity, test quality, secret hygiene all verified)
  • Secret scan: 0 token/pointer occurrences in generated artifacts

Kaiyuan report §30 分钟理想振幅因子: pool the 1min bars of a symbol's trailing
N=10 trading days (PIT-truncated at 14:50 per bar via the I3 filter path), rank
the pooled minutes by RAW close, and return V_high - V_low where V_high/V_low are
the mean per-minute amplitude (high/low - 1) of the top / bottom floor(0.25*n)
minutes by close. >= 1150 valid pooled minutes required else NaN (honest missing).

- data/clean/intraday_amplitude.py: compute_minute_ideal_amplitude + LOCKED
  definition constants (N=10, lambda=0.25, min_minutes=1150). Pure, per-symbol
  isolated, never touches a forward return; ranking tie-break (close, bar_end) is a
  deterministic total order.
- factors/compute/intraday_derived.py: additive MinuteIdealAmplitudeFactor
  (column-select, is_intraday=False daily close-to-close, expected_ic_sign=-1
  pre-registered).
- tests: hand-computed formula (n=4/n=8/two-day pool), 14:50 PIT truncation +
  post-cutoff perturbation invariance, trailing-window drop, min_minutes gate,
  deterministic tie-break, per-symbol isolation, amplitude guards, empty/no-mutate,
  spec validity, bad-params.
…PR-D)

Second real StandardFactorEvaluator run, mirroring PR-C. Cache-only per-symbol
minute aggregation -> raw -> process -> two evaluations (no-book / with-book value
book) with md/json/dashboard outputs. Eval cell IDENTICAL to PR-C (CSI500 000905.SH,
2021-07-01..2026-06-30, OOS split 2024-01-01, book value_ep/value_bp/volatility_20,
fee 0.001); the only substantive difference is the subject factor, computed by the
runner from the intraday cache (not a config-listed daily factor).

- qt/eval_minute_ideal_amplitude.py: cache-only minute loader (stk_mins live calls
  provably 0), evaluate_two_runs, metric extraction, honest EvalConfig provenance.
- qt/cli.py: run-eval-minute-ideal-amplitude subcommand.
- config/phase_d_minute_ideal_amp.yaml: PR-D eval config.
- tests: cache-only loader (discloses empty, blocks when nothing cached), two-run
  evaluation core with dashboard PNGs, no-book never-Adopt structural guarantee.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant