Add the cross-asset crowding strip - #36
Merged
Merged
Conversation
The Heatmap already carries every number this draws. What it does not do is let you see the whole board at once, because reading a grid means reading it column by column. `/strip` is the same verdicts as a picture: one row per market, grouped by asset class, sorted so the crowded ends of each group collect at its top and bottom. It reads the same get_matrix_data frame and computes nothing. Modelled on a printed positioning report, and deliberately unlike it in the places that report gets wrong. Written up in docs/design/positioning-report-view-ideas.md, which evaluates the source and records what shipped. No range bar. In index space a min..max rule is always the full axis, because the index IS the position within the range, so it would carry nothing; the printed version also draws windows differing by up to eight times at identical width. A diamond marks the value against a banded, ticked axis instead, and a Bar mode is available for the deviation-from-neutral reading. Shape is the verdict and colour is whose leg it is. A row the model has something to say about gets a diamond in the verdict colour; a quiet row gets a tick, the same mark the speculator legs use, in the app's Commercial colour. The legs drawn are the ones the selected model gates on, so the NPF strip has no Large Spec mark at all. Colour follows the ROW's setup state rather than each value's own level, same rule the Heatmap's index cells follow, so a lit mark deep in a band is an extreme with another leg blocking it. A hollow mark shows where the index stood MOMENTUM_PERIOD weeks ago, read from the momentum column belonging to the selected model's basis. Needs the "Comm Move Norm" column added in cotmetrics; degrades to no mark without it. Filters on two axes that cannot contradict each other: Show takes the verdict, Side takes which half of its own range the market sits in. Two columns on a wide screen, breaking only between classes and balancing on row count, since the classes are wildly uneven. The caption carries the report date, the model, the window, and counts anything hidden or missing. Two supporting moves, both to avoid a second copy: grid_colors leaves the Heatmap page for components.plot_colors, and next_date_selection leaves it for app_utils, so this page follows a release the same way without one page importing another. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The six-weeks-ago circles drew teal green against a red key. An OPEN Plotly symbol takes its outline from marker.color; marker.line is a second stroke around that. Only the line colour was set, so marker.color was None, which is not an error, it is the template colourway, whose third entry is #00cc96. The legend proxy did set marker.color, which is the only reason the disagreement showed up at all rather than just looking like a colour choice. The general test written for it found a second instance straight away: the speculator leg ticks set only marker.line.color too. Those render correctly, because a line-* symbol happens to draw from marker.line, so that one sat one symbol change away from silently becoming a template colour. Both now name marker.color, and the test asserts it for every drawn trace under both marks instead of pinning the single case that was noticed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
A new page at
/strip: the whole board on one screen, one row per market, grouped by asset class and sorted so the crowded ends of each group collect at its top and bottom. It reads the sameget_matrix_dataframe the Heatmap reads and computes nothing of its own. The only thing it changes is scan cost, since a grid is read column by column.Modelled on a printed cross-asset positioning report, and deliberately unlike it wherever that report defeats its own purpose.
docs/design/positioning-report-view-ideas.mdevaluates the source, quantifies what it gets wrong from its own numbers, and records what shipped and why.The marks
No range bar. In index space a min..max rule is always the full axis, because the index is the position within the range. The printed version also draws each market's windows at identical width when the underlying ranges differ by a median of 2.5x and up to 8.2x, so the fact worth seeing is the one thing it removes. A diamond marks the value against an axis ticked at the model's own gate values instead. A Bar mode is kept for the deviation-from-neutral reading.
Shape is the verdict, colour is whose leg it is. A row the model has something to say about gets a diamond in the verdict colour; a quiet row gets a tick, the same mark the speculator legs use, in the app's Commercial colour (
palette[0], as everywhere else). Leg ticks take slots 1 and 2 and say whether they are gating through opacity.Only the legs the model gates on. The strip asks the model, so the NPF strip carries no Large Spec mark at all, and the source report's single "net spec" series, which quietly folds Non-Reportables into the speculator leg, is not reproduced.
Colour follows the ROW's setup state, not each value's own level, the same rule the Heatmap's index cells follow. A lit mark deep inside a band is a market at an extreme with another leg blocking it, which is the interesting case rather than a defect.
Where it stood six weeks ago, as a hollow mark on the same row, clamped to the axis. Reads the momentum column belonging to the selected model's basis, which needs mspinola/cotmetrics#19. Without that column the mark simply does not draw.
Controls
Model, lookback and date follow the existing global stores. Added: Show (all / setups / setups and near) and Side (both / bullish / bearish), two axes that cannot contradict each other because a bull setup is above neutral by construction; Mark (dot / bar); Columns (1 / 2). Two columns break only between classes and balance on row count rather than class count, since the classes are wildly uneven.
The caption carries the report date, the model, the window, and counts anything hidden by a filter or dropped for having no index. It says the window is per-market on the Custom lookback, which is a hazard for a cross-asset ranking specifically.
Refactors
Two moves, both to avoid a second copy rather than for tidiness:
grid_colors/GridColors/DIM_TEXTleavepages/analytics/heatmap.pyforcomponents/plot_colors.py, now that two surfaces resolve the same palette into bull/bear/near. Re-exported, soheatmap.grid_colorsand its tests still resolve.next_date_selectionleaves the Heatmap forapp_utils, so this page follows a CFTC release the same way without one page importing another.Testing
pytest -q: 221 passed (33 new intests/test_strip_traces.py)ruff check src tests: cleanpython scripts/check_dep_floors.py: OK. No floor bump: the momentum column degrades to no mark on an older cotmetrics rather than raising, so this does not hard-require Carry index momentum on both bases in the Signal Matrix cotmetrics#19 to be released first.The figure logic in
components/strip_traces.pyis pure over the frame plus a colour set, so the layout is tested without a store, a palette file or a browser.pages/analytics/strip.pyis controls, caption and wiring.🤖 Generated with Claude Code