Skip to content

feat(eod): allocate Pricing & Timing / Rotation basis-gap slices to specific stocks (schema 2.2)#347

Merged
cipher813 merged 1 commit into
mainfrom
feat/per-ticker-sleeve-reallocation
Jul 9, 2026
Merged

feat(eod): allocate Pricing & Timing / Rotation basis-gap slices to specific stocks (schema 2.2)#347
cipher813 merged 1 commit into
mainfrom
feat/per-ticker-sleeve-reallocation

Conversation

@cipher813

Copy link
Copy Markdown
Collaborator

Summary

Closes alpha-engine-config-I2046. crucible-executor PR343 (schema 2.1) added per-ticker ib_market_value/market_value fields specifically as a "breadcrumb for future per-name attribution" but never used them for attribution. This PR is that follow-through: it decomposes the aggregate pricing_timing_usd sleeve (the IB-mark-vs-settled-close basis gap) per ticker instead of leaving it as a portfolio-wide generic bucket.

Why this decomposes exactly (no residual/fudge needed)

mark_basis(t) = Σ_{held today} (ib_market_value_i − market_value_i) and mark_basis(t−1) = Σ_{held yesterday} (ib_market_value_i − market_value_i), so pricing_timing_usd = mark_basis(t) − mark_basis(t−1) telescopes into an EXACT per-name sum: each ticker held on either day contributes basis_today_i − basis_prior_i (zero baseline on the day it wasn't held). This is not an approximation — the per-ticker sum equals the aggregate to the last cent, verified by new tests.

What changed

  • Each held/entered name's basis-gap slice folds into its own position component's contrib_usd (exposed separately too, as position_alpha_usd [pure settled-close economic alpha] + pricing_timing_usd [this name's slice], so the breakdown isn't lost).
  • Each fully-exited name's slice folds into the rotation component the same way.
  • The generic "Pricing & timing" line now carries ONLY the leftover no ticker could be attributed (e.g. a legacy snapshot missing ib_market_value) — will read ~$0 on any day both snapshots have complete schema-2.1 data.
  • "Unattributed" is deliberately left alone — it has no per-ticker basis in current data (fees/FX/untracked corporate actions), and force-allocating it would be a fabricated number, not a derived one (fail-loud/no-silent-allocation doctrine).
  • Schema 2.1 → 2.2 (purely additive: 2 new fields on positions[], 2 new fields on alpha_attribution/nav_reconciliation).

Tests

New TestPricingTimingPerTicker class (4 cases: retained position, same-day new entry, fully-exited name, missing-data fallback) plus updated existing tests for the schema bump. Full suite: 1465 passed, 4 skipped (no regressions).

Test plan

  • 1465/1465 tests green locally
  • CI green
  • After merge: next EOD run produces a schema-2.2 artifact; verify positions[].pricing_timing_contrib_usd populated for retained names and the "Pricing & timing" component shrinks toward $0 on a no-legacy-data day

🤖 Generated with Claude Code

…pecific stocks (schema 2.1→2.2)

Decomposes the aggregate pricing_timing_usd sleeve per-ticker using the
schema-2.1 ib_market_value/market_value fields (PR343), which telescopes
exactly: each held/entered name's basis gap folds into its own position
row, each fully-exited name's folds into Rotation. The generic "Pricing &
Timing" line now carries only the genuinely-unattributable leftover
(~$0 whenever both days' snapshots have complete schema-2.1 data).

Unattributed is deliberately left as a portfolio-level residual — no
per-ticker basis exists for it in current data, and fabricating one would
violate the fail-loud/no-silent-allocation doctrine.

New position fields: position_alpha_usd (pure settled-close economic
alpha) + pricing_timing_contrib_usd (this name's basis-gap slice),
alongside the existing combined alpha_contrib_usd. Exact tie-out
preserved (dollar_alpha == sum(components.contrib_usd)), verified by new
TestPricingTimingPerTicker cases covering retained/new-entry/exited/
missing-data scenarios.

Closes config-I2046.
@cipher813 cipher813 merged commit f0fb4c2 into main Jul 9, 2026
2 checks passed
@cipher813 cipher813 deleted the feat/per-ticker-sleeve-reallocation branch July 9, 2026 21:57
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