Strategy-aware wallet drill-down: price + performance charts - #2
Conversation
Turn the wallet drill-down modal into an analytics view:
- Price panel (self-hosted TradingView Lightweight Charts, satisfies the
strict CSP): candlesticks + the indicators the wallet's OWN strategy uses,
computed from live strategy params, plus buy/sell trade markers coloured by
win/loss (realized P&L) and the live resting ladder + avg cost.
- Performance panel: one multi-series chart (balance / realized / unrealized /
fees) with colour-matched, clickable legend toggles.
- Exposure panel + activity stat strip (trades, wins/losses, win rate, avg
win/loss, profit factor).
- Strategy panel: metric blocks rendered generically from whatever the backend
returns for the wallet's CURRENT strategy, so excluding/reassigning a wallet
changes the panel automatically. Grid wallets show ladder/spacing/inventory/
regime; oscillators show their thresholds; committee wallets show cadence.
Backend reconstructs balance/P&L/fees/exposure per closed candle from the
wallet's own fills (nothing fabricated; empty wallets render a flat line). New
read-only endpoints /wallets/{id}/chart and /wallets/{id}/timeseries; the view
retains the candle window and adds strategy_metrics/activity/reason_breakdown.
Frontend stays within the A14 posture: no innerHTML, all colours via CSS
classes (style-src 'self' forbids inline styles), charts guarded so unit tests
with no charting library still pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1dcee56c44
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const chart = LightweightCharts.createChart(container, { | ||
| ...CHART_THEME, | ||
| width: container.clientWidth || 760, | ||
| height, | ||
| handleScale: true, | ||
| handleScroll: true, | ||
| }); |
There was a problem hiding this comment.
Permit the chart library's required layout styles
When the dashboard is served by create_app, every response has style-src 'self', but Lightweight Charts 4.2.3 lays out its generated table and canvases through inline element.style mutations (visible throughout the vendored asset). Browsers enforce those as inline styles, so this createChart path is blocked or left without the positioning and dimensions needed to render, making the new charts blank or malformed under the application's normal CSP; the chart integration needs a CSP-compatible styling approach or an appropriately scoped policy change.
Useful? React with 👍 / 👎.
|
|
||
| return InMemoryPortfolioView( | ||
| portfolio=portfolio, mark_price=mark, now=now, | ||
| candles=tuple(market), |
There was a problem hiding this comment.
Refresh retained candles along with the live mark
In --live mode this stores only the startup candle tuple, while start_market_refresher subsequently updates only view.mark_price and view.now. After the next closed candle, /chart, /timeseries, and the strategy metrics therefore remain permanently frozen at startup even though the wallet snapshot is marked at the newer price, producing contradictory and stale analytics whenever the detail panel is reopened; the retained candle window must be advanced by the live refresher as well.
Useful? React with 👍 / 👎.
| _line(candles, lambda c: ind.donchian_high(c, s.entry_period, exclude_last=False), | ||
| id="dc_up", label=f"Donchian {s.entry_period} high", pane="price", color=C_CHANNEL), | ||
| _line(candles, lambda c: ind.donchian_low(c, s.exit_period, exclude_last=False), | ||
| id="dc_dn", label=f"Donchian {s.exit_period} low", pane="price", color=C_STOP), |
There was a problem hiding this comment.
Plot Donchian channels from prior candles
For a DonchianBreakout wallet, the strategy calls donchian_high/low with their default exclude_last=True, so its actual trigger is the channel formed before the current candle and the current close can cross it. These overlays force exclude_last=False, causing the line to incorporate and move with the current candle's high/low; breakout and trailing-exit markers can consequently appear not to have crossed the displayed threshold. Use the same exclusion semantics as the strategy.
Useful? React with 👍 / 👎.
Summary
Turns the wallet drill-down modal into a real analytics view with a small number of rich charts (per the "fewer charts that do more" preference).
script-src 'self'CSP is satisfied) + the indicators the wallet's own strategy uses (computed from live strategy params) + buy/sell markers coloured by win/loss + live resting ladder & avg cost.Data
All time series are reconstructed deterministically from each wallet's own fills over the retained candle window — nothing is fabricated; empty wallets render a flat line. Reconciles to within $0.03 of the headline equity. New read-only endpoints
/wallets/{id}/chartand/wallets/{id}/timeseries.Safety
Stays within the A14 posture: no
innerHTML; all colours via CSS classes (style-src 'self'forbids inline styles); chart code guarded so the jsdom/static unit tests (no charting lib) still pass. Vendored library documented indashboard/static/vendor/NOTICE.md(Apache-2.0, pinned v4.2.3).Tests
920 passing (903 existing + 17 new in
tests/tradebot/test_chart_analytics.py).🤖 Generated with Claude Code