Skip to content

Heatmap: an Offside column, so the grid says who is losing - #59

Merged
mspinola merged 1 commit into
mainfrom
claude/offside-column
Aug 24, 2026
Merged

Heatmap: an Offside column, so the grid says who is losing#59
mspinola merged 1 commit into
mainfrom
claude/offside-column

Conversation

@mspinola

Copy link
Copy Markdown
Owner

What this adds

An Offside column on the heatmap, in its own "Cost Basis · Large Specs" group: how far Large Specs sit from their own average cost, in the market's weekly standard deviations. Negative is under water. Reads cotmetrics.offside (mspinola/cotmetrics#28); this repo computes nothing.

Every positioning column on this page is about size — how unusual, how extreme, how many dollars of risk. None said whether the holders are up or down.

Four decisions worth reviewing

Its own group, not a third Exposure column. It reads a different cohort (LEG_LARGE, where the dollar-risk column uses LEG_SPEC) and answers the opposite question. A basis computed on the summed large+small net describes a trader who is both cohorts at once, and the two have different average costs and behave differently when under water. Large Specs is also the cohort every published figure for this measure is quoted on.

No percentile, unlike Risk %ile. Dollar risk is incomparable across markets, so it must be ranked against a market's own history before it means anything. Offside is already comparable by construction: dividing by the market's own sigma is what the measure does, and 0 means "at the cohort's average cost" in every market. Ranking it would replace a readable quantity with a percentile of one.

Only the losing tail lights, and the colour is a P&L statement. Lit at <= -2 sigma in the bear colour. That is the sign of the cohort's own mark, not a direction verdict: red means "these holders are down", not "this market goes lower". Being deep in profit is not distress, so the column is deliberately asymmetric where a z-score column would not be. -2 is a display threshold, deliberately rounder than any figure in the study (pooled p10 is about -1.7).

The tooltip refuses to promise capitulation. The obvious inference from a lit cell — they are trapped, so they must fold — was pre-registered, tested against 44 markets and did not hold (npf#214, verdict "adverse-move proxy"; within equally severe adverse moves, deep-offside cohorts capitulated no more often and Small Traders significantly less). The copy says the number is a reading of who is losing and not a forecast, and two tests pin that wording so it cannot quietly drift into a claim.

Verification

  • Live store, all 18 rows in Energies/Metals/Currencies populate with consistent basis/mark pairs (Euro reads -1.7 because Large Specs are net short into a rising euro; Mexican Peso +5.9 long and in profit).
  • The lit path, end to end: driving the real render_heatmap_layout at target date 2026-06-30 returns Euro -2.09 and Corn -5.91, both matching the emitted condition params.value != null && params.value <= -2.0 and rendering in #FF4D4D.
  • In the browser: group header, +/- formatting and dim styling all render as intended; screenshot behaviour matches Risk %ile.
  • Page registry still loads all 16 routes, which is the check that matters when use_pages imports every page at startup.
  • 11 new store-free tests (join on own week, unpriceable market stays a row, failure returns None, object dtype for the null guard, styling both branches, and the two copy pins). Full suite 448 passed, ruff clean, check_dep_floors.py OK.

Floor

cotmetrics[options]>=0.7.0. This is an import-time floor rather than a nominal one: against 0.6.0 the module does not exist and, because use_pages imports every page at startup, the ImportError takes down the whole route registry rather than one column.

Merge mspinola/cotmetrics#28 first, or CI here cannot resolve the floor.

🤖 Generated with Claude Code

Every positioning column on this page is about size: how unusual it is, how
extreme, how many dollars of risk. None of them says whether the people holding
the position are up or down. This adds that, reading cotmetrics.offside: how far
Large Specs sit from their own average cost, in the market's weekly sigma.

Its own group rather than a third Exposure column, because it reads a different
cohort (LEG_LARGE, not the LEG_SPEC dollar-risk column) and answers the opposite
question. A basis on the summed large+small net describes a trader who is both
cohorts at once, and the two have different costs and behave differently when
under water. Large Specs is also the cohort every published figure for this
measure is quoted on.

No percentile, unlike Risk %ile, and the asymmetry is deliberate: dollar risk is
incomparable across markets so it must be ranked against a market's own history
first, while offside is already comparable by construction (dividing by the
market's own sigma is what the measure does) and 0 means "at cost" everywhere.
Ranking it would replace a readable quantity with a percentile of one.

Only the losing tail lights, at <= -2 sigma, in the bear colour. That is a P&L
statement, not a direction verdict: the number is the sign of the cohort's own
mark, so red means "these holders are down", not "this market goes lower". The
tooltip says so explicitly, and says the deep readings do NOT forecast a position
being cut, because that exact inference was pre-registered, tested against 44
markets and did not hold (npf #214, verdict "adverse-move proxy"). A tooltip that
let a reader draw it would be asserting the thing that failed.

Verified against the live store: all 18 rows in Energies/Metals/Currencies
populate with consistent basis/mark pairs, and the page registry still loads all
16 routes, which is the check that matters when use_pages imports every page at
startup. Floor raised to cotmetrics>=0.7.0 for the same reason: against 0.6.0 the
import takes down the whole registry, not one column.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mspinola
mspinola merged commit 603f422 into main Aug 24, 2026
3 of 6 checks passed
@mspinola
mspinola deleted the claude/offside-column branch August 24, 2026 03:00
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