Skip to content

fix: reconstruct volume from the two highest-volume contracts, not nearest expiry#16

Merged
mspinola merged 1 commit into
mainfrom
fix/reconstruct-volume-by-rank
Jul 14, 2026
Merged

fix: reconstruct volume from the two highest-volume contracts, not nearest expiry#16
mspinola merged 1 commit into
mainfrom
fix/reconstruct-volume-by-rank

Conversation

@mspinola

Copy link
Copy Markdown
Owner

Problem

_reconstruct_volume identified First/Second as the two earliest-expiry contracts with data on each day, then summed them as "true market volume." For products with serial months around a bi-monthly liquid cycle (GC, SI, …), the nearest serial month carries almost no volume, so the pick summed near-empty contracts and badly understated true volume.

Concretely, in the current store:

GC 2026-07-13:  FirstContract=GC-2026N vol=558   SecondContract=GC-2026Q vol=141,592

FirstVolume (558) < SecondVolume (141,592) on the same day — impossible if the selection ranked by volume. GC's Volume_Reconstructed came out at ~6% of the front-month continuous Volume (historical median).

How it surfaced

The cot-analyzer flow-engine regression (Step 3.5) for the reconstructed-volume promotion. Switching that engine to reconstructed volume moved GC's weekly commercial-flow estimate by ~79% — toward the understated number. Symbols where reconstructed ≈ front were unaffected:

symbol rec/front vol weekly flow Δ (max)
ES 1.00× 0.09%
6E 1.00× 0.43%
BTC 0.98× 7.6%
CL 0.72× 31.9%
GC 0.06× 79.2%

Fix

Rank contracts by descending volume per day; ties break by nearest expiry (columns are pre-sorted by expiry and the sort is stable); NaN sorts last. First/Second now mean the two dominant contracts — matching the README's stated semantics.

Adds test_reconstruction_picks_by_volume_not_expiry (nearest-expiry contract near-empty, later contract dominant → dominant must be First), which fails on the old logic and passes on the new. Full suite: 32 passed.

⚠️ Follow-up required — this fixes code, not data

The on-disk store still holds the wrong GC/CL reconstruction until a full producer pass re-runs (norgate.update(), Windows + norgatedata). Until then cot-analyzer still consumes the degraded values for those symbols. Sequence: merge → re-run producer → re-run the regression (expect GC rec/front → ≥1.0, flow Δ collapses).

Suggested post-migration gate: flag any symbol whose median rec/front ratio is outside ~[0.5, 3.0].

🤖 Generated with Claude Code

…arest expiry

_reconstruct_volume identified First/Second as the two earliest-expiry
contracts with data, then summed them as "true market volume." For products
with serial months around a bi-monthly liquid cycle (GC, SI, ...), the nearest
serial carries almost no volume, so the pick summed near-empty contracts and
badly understated volume — GC's Volume_Reconstructed was ~6% of the front-month
continuous Volume (proof: FirstVolume 558 < SecondVolume 141,592 on the same day,
impossible if ranked by volume).

Rank contracts by descending volume per day instead; ties break by nearest
expiry (columns pre-sorted by expiry, stable sort), NaN sorts last. First/Second
now mean the two dominant contracts, matching the README's stated semantics.

Surfaced by the cot-analyzer flow-engine regression: switching that engine to
reconstructed volume moved GC's weekly commercial-flow estimate ~79% toward the
understated number. ES/6E/BTC (reconstructed ~= front) were unaffected.

Adds test_reconstruction_picks_by_volume_not_expiry (nearest-expiry contract
near-empty, later contract dominant → dominant must be First). NOTE: the store
must be re-migrated by a full producer pass (Windows/norgatedata) before the
on-disk data reflects this fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mspinola
mspinola merged commit 7a48807 into main Jul 14, 2026
5 checks passed
@mspinola
mspinola deleted the fix/reconstruct-volume-by-rank branch July 20, 2026 16:17
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