08.Charts & per-symbol research
uPlot OHLC + persisted drawings + technical overlays, the per-symbol dossier (quote / signals / news / earnings / dividends / insiders / fundamentals / holders), the options chain + Greeks + IV surface, and the right-click symbol-nav menu that connects every grid in the app.
The Charts view
frontend/js/views/charts.js. uPlot (vendored under frontend/lib/uPlot/, no CDN at runtime) renders the price + volume panes. Bars are fetched from GET /api/symbols/{sym}/bars?tf=&from=&to=, cached locally for the session, and lazy-extended as you scroll the time axis.
- Timeframes — 1m / 5m / 15m / 30m / 60m / 1d / 1w / 1mo.
- Overlays — VWAP, SMA, EMA, Bollinger Bands, Donchian, Ichimoku, anchored VWAP, supertrend. Toggle from the overlay menu; the active set persists per-symbol.
- Indicator panes — RSI, MACD, ATR, ADX, OBV, volume profile. Stack as many sub-panes as fit.
- Drawings — trend lines, horizontal levels, Fib retracements, rectangles, text labels. Saved to
chart_drawingskeyed by symbol; survive across launches. - Trade markers — your executions on the symbol appear as up/down arrows at the bar of
executed_at, with the trade ID on hover. - Crosshair sync — open the same symbol in two charts (multi-monitor); crosshairs synchronize across them.
The chart uses uPlot's tier of canvas rendering — comfortable with 50 000+ bars on screen. Scrolling further back lazy-fetches via the same bars endpoint.
Per-symbol research dossier
Open Research on any symbol (right-click → Research, or Cmd+K → Research → type symbol) and you land on a one-page dossier. Each section is a route under /api/symbols/{sym}/...:
| Section | Route | Source |
|---|---|---|
| Quote + 1d/1mo/1y mini-charts | /symbols/{sym}/quote | Yahoo v8 (cached 60s) |
| Top signals | /signals | Local TA over recent bars |
| News | /news | Yahoo + PR-wire local store |
| Earnings + IV crush history | /earnings | Yahoo + locally derived IV |
| Dividends | /dividends | Yahoo v10 |
| Analyst recommendations | /recommendations | Yahoo v10 |
| Insider transactions | /insiders | EDGAR Form 4 |
| Fundamentals | /fundamentals | Yahoo v10 |
| Institutional holders | /holders | Yahoo v10 |
| Short interest | /short-interest/{sym} | FINRA Reg-SHO daily |
| Sentiment | /sentiment/symbol/{sym} | Reddit WSB + StockTwits |
| Sentiment time series | /sentiment/series/{sym} | derived from the feed |
Every section is independently loadable — slow sections don't block the rest of the page. Failures show a small inline error and a retry link; the page never goes blank because one route 5xx'd.
Options chain + Greeks + IV surface
Options live in their own subtree:
GET /api/options/{sym}— the chain. Expiries × strikes × calls/puts grid; bid / ask / last / volume / open interest / IV / Greeks per leg.GET /api/greeks— Black-Scholes Greeks for an arbitrary contract spec (used by the chain view and the position-size calculator).GET /api/vol-surface/{sym}— implied-vol surface (strike × tenor). Rendered as a heatmap + a smile / skew line chart at the user-selected tenor.GET /api/iv/scan— IV-rank / IV-percentile scanner across a universe. Highlights symbols at unusually high or low IV.GET /api/iv/symbols/{sym}— per-symbol IV history + rank/percentile.
The chain view supports strategy builders (vertical / iron condor / calendar / diagonal / butterfly) — picking the legs writes a paper trade with computed Greeks and breakevens.
Screener + scanners
- Screener (
GET /api/screener/run) — multi-filter equity screener: price / market cap / volume / RVOL / float / sector / technical conditions (above SMA50, RSI < 30, etc.). Save filter sets per-user. - Top signals (
GET /api/screener/top) — the screener's "most interesting today" preset stack. - Scanners (
GET /api/scans/run) — 24 preset scanners: gap-and-go, opening range break, parabolic, mean reversion, end-of-day momentum, earnings reaction, etc. The presets live intraderview-core::scanners; user customs land in step 10.
Compare / Pairs / Correlation
- Compare (
GET /api/compare) — multi-symbol % return + cumulative return + drawdown comparison over a date range. - Pairs — long/short pair analytics: spread, ratio, z-score, half-life of mean reversion. Useful for cointegrated-pair traders.
- Correlation — multi-symbol correlation matrix on configurable lookback + returns frequency. Sortable + heatmapped.
Sectors, breadth, fear & greed
- Sectors — sector ETF performance grid + heatmap.
- Sector Rotation — relative-strength rotation chart (RRG) of the 11 SPDR sectors vs SPY.
- Breadth — advance/decline, new highs / new lows, % of S&P above 50/200 SMA.
- Fear & Greed — composite indicator (volatility + momentum + breadth + safe-haven demand + put/call + junk-bond demand).
Right-click symbol-nav — 222 paths
Every grid that emits a symbol (Trades, Executions, Live Scanner, Halts, Catalysts, Watchlists, Screener results, Scanner results, Reports by-symbol, Tax Lots, Open Positions, Compare results, Sentiment, Top Signals, Earnings Cal, Disclosures, Dark Pool, Short Interest, IV Scan, the chart's own symbol header, …) registers a data-context-scope slug; the global ctxmenu handler attaches the same 6-way symbol-nav menu (Charts / Options / Research / Earnings / News / Copy).
37 distinct symbol-aware view scopes × 6 nav targets = 222 distinct nav paths. Items are registered in a single ALL_SCOPED_ITEMS array; handler bodies are 3-4 LoC each via 6 shared helpers (clipboardWrite / refreshView / dataFromTarget / toastErr / toastOk / symbolFromTarget). Two regression tests pin that every emitting tag carries the data-* attrs its handler reads, and that every registered scope is documented.
Per-row context scopes — 18 of them
Symbol nav is one menu; data scopes are another. Per-row scopes give you row-specific actions (delete, edit, copy ID, duplicate, mark reviewed, …):
trade-row, symbol-row, journal-entry, tag-chip, webhook-row, api-token-row, account-row, plan-row, share-row, board-row, dashboard-sidebar-item, hotkey-row, custom-indicator-row, alert-rule-row, strategy-alert-row, watchlist-symbol-row, position-row, backtest-preset-row
Every right-click is handled by the same global handler — adding a new scope is one line in ALL_SCOPED_ITEMS.