# Terminal A fast, keyboard-driven market terminal in pure Rust: TradingView-class GPU charting with a Bloomberg Terminal look (dense tiled panes, monospace numbers, a command line like `AAPL `) across **stocks, ETFs, indices, FX, crypto, US Treasuries, futures/commodities and options**, plus **congressional trade tracking ingested directly from the official STOCK Act disclosure systems** and **your own brokerage accounts through [SnapTrade](https://snaptrade.com)** (read-only by default, with opt-in order entry). Native compact UI, themes from Bloomberg amber to Solarized, and a fully dockable workspace with saved layouts. ![Terminal: AAPL chart with congress trade markers and RSI, the Congress trades feed, world markets and a multi-asset watchlist](docs/img/overview.png) > **Built from reverse-engineering research.** Chart UX was studied behaviourally on > tradingview.com with [REA](https://github.com/morluto/rea) in website mode (passive captures of > the public, logged-out chart page), then given a Bloomberg Terminal look. Findings, evidence IDs > and their design implications are in [`docs/analysis/`](docs/analysis/README.md). Only behaviour > was studied: no TradingView or Bloomberg code, scripts, icons, fonts or other assets are used or > included here. The disclosure parsers were likewise built by examining the public Senate eFD and > House Clerk sites and their filings. ## Screenshots | | | |---|---| | ![Bloomberg theme: NVDA chart with congress markers and Nancy Pelosi's trade history with estimated returns](docs/img/bloomberg-politician.png) | ![Options chain (OMON) for AAPL with bid/ask, IV and delta per strike beside the chart](docs/img/options-omon.png) | | **Bloomberg theme** — `NVDA`, `POL PELOSI`: party-coloured B/S markers and a politician profile with estimated return, hit rate and disclosure lag | **Options** — `AAPL OMON`: every expiry, calls and puts by strike, IV and greeks, spot line | | ![Terminal Light theme with the latest congressional trades feed](docs/img/light-congress.png) | ![Nord theme, sidebar on the right, dragging a Watchlist tab onto the chart pane's dock compass](docs/img/docking-nord.png) | | **Terminal Light** — the latest STOCK Act filings with party, chamber, owner and amount filters | **Docking** (Nord theme, sidebar on the right) — drag a tab onto the compass to tab or split | | ![Live theme editor: Monokai applied to the chart while its colours are shown in Settings](docs/img/theme-editor.png) | ![Theme gallery in Settings › Appearance](docs/img/theme-gallery.png) ![Congress marker hover card with disclosure lag](docs/img/hover-card.png) | | **Theme editor** — edit any colour, font or density live; save, duplicate, import/export TOML or JSON | **Theme gallery** and the **marker hover card** (politician, amount, traded/filed, disclosure lag) | | ![Portfolio summary: total value, unrealised P&L, cash, buying power, allocation bar, top holdings and accounts beside an AAPL chart](docs/img/portfolio.png) | ![Positions table with quantity, live last price, average cost, value and unrealised P&L](docs/img/positions.png) | | **Portfolio** — `PORT`: value, unrealised P&L, cash and buying power, allocation, top holdings, accounts (simulated sample shown) | **Positions** — `POS`: live terminal quotes (cyan) reprice holdings; click a row to chart it | Screenshots are from the Linux build under Xvfb with live data (October 2026); on macOS the same UI gets the native title bar with traffic lights, window vibrancy behind the sidebar and SF fonts. ## Features - **Multi-asset with Bloomberg-style market keys** — `AAPL `, `SPY `, `SPX `, `BTCUSD `, `EURUSD `, `US10Y `, `CL1 ` (keys display as `AAPL US Equity`, `BTCUSD Curncy`, `US10Y Govt`, `CL1 Comdty`). The yellow key is optional for known tickers. A built-in catalog covers ~120 instruments (regional indices, equity index futures, energy/metals/grains, the full Treasury curve, majors and crosses, top crypto, popular ETFs and large caps); anything else resolves by convention. - **Command line and search** — ` [] ` (Enter is ``); typing anywhere starts a command, with a live interpretation underneath (`5` → "Interval 5 minutes") and symbol matches across all asset classes (catalog instantly, plus Yahoo search after a short pause); ↑/↓, Tab, Enter; history with ↑/↓. `SECF gold cmdty` opens a full search panel. - **Charts** — GPU-rendered candles, OHLC bars, line and area; 1m, 5m, 15m, 30m, 1H, 4H, 1D, 1W, 1M plus quick ranges (1D … ALL); volume; 151 indicators; `CMP ` compare; log scale; crosshair with OHLC legend; smooth pan and zoom over a million bars. Live crypto bars from the Binance websocket (Coinbase fallback). - **Indicators** — 151 built-in studies: 23 moving averages (SMA, EMA, WMA, Hull, DEMA/TEMA, KAMA, ALMA, T3, McGinley, VIDYA, FRAMA, MAMA/FAMA, Ehlers filters, GMMA…), 8 bands and channels (Bollinger, Keltner, Donchian, STARC, standard-error and VWAP bands…), 43 momentum oscillators (RSI, MACD, Stochastic, StochRSI, CCI, Williams %R, TSI, KST, Fisher, Schaff, QQE, WaveTrend, Connors RSI…), 22 trend tools (ADX/DMI, Aroon, Vortex, Parabolic SAR, SuperTrend, Ichimoku, Alligator, ZigZag, fractals, Chandelier and Chande Kroll stops…), 16 volatility measures (ATR, close-to-close and Parkinson, Garman-Klass, Rogers-Satchell and Yang-Zhang estimators, Ulcer, Mass index, squeeze momentum…), 23 volume studies (OBV, A/D, CMF, MFI, Klinger, NVI/PVI, VZO…), 11 rolling statistics and five pivot-point families. Type a code with optional parameters (`RSI`, `SMA 200`, `BB 20 2.5`), browse and search with `IND`, or right-click the chart. Oscillators get their own panes (up to six) with reference levels; moving averages can be added several times; indicators are saved with the layout. - **Drawings** — trendline (Alt+T), horizontal (Alt+H), vertical (Alt+V) and fib retracement (Alt+F), stored in (time, price) so they survive zoom and timeframe changes; magnet (Alt+M) snaps to OHLC; click to select, Del to remove. - **Options** (`AAPL OMON`, ⌘⇧O) — full chains from Yahoo for US equities, ETFs and indices (SPX via ^SPX): every expiration, calls and puts by strike with bid/ask/last, change, volume, open interest and IV, plus Black-Scholes greeks (Δ, Γ, Θ/day, vega) from each contract's IV, the dividend yield and the 3-month T-bill rate; in-the-money shading, spot line, ±10/±20/all strikes; offline mode shows a flagged simulated chain. - **Markets** — `WEI` world markets (Americas/EMEA/Asia-Pacific indices, futures, Treasuries, FX, crypto and commodities with sparklines), `GC` US Treasury yield curve (now vs 1M and 1Y ago, 2s10s / 3m10y / 5s30s), **news** (`AAPL CN`; Yahoo headlines, CoinDesk for crypto) and **order book** depth (`BTCUSD CRNCY OB`; live Binance book, Coinbase fallback; markets without a free public book show a clearly marked simulation). - **Market data behind a trait** (`tr_data::MarketData`), routed per asset class to free sources: | Asset class | History | Quotes | Live | |---|---|---|---| | Crypto | Binance public REST (`data-api.binance.vision`, then `api.binance.com`), Coinbase Exchange fallback | Binance 24h ticker | Binance kline websocket, Coinbase ticker fallback | | US Treasuries | Treasury.gov daily par yield curve CSV (FRED fallback); Yahoo `^IRX/^FVX/^TNX/^TYX` intraday | Treasury.gov | — | | FX, indices, futures | Yahoo Finance (`EURUSD=X`, `^GSPC`, `CL=F`) | Yahoo spark (batched) | — | | Stocks, ETFs | Alpaca when `APCA_API_KEY_ID`/`APCA_API_SECRET_KEY` are set, else Yahoo | Yahoo spark | — | | Hyperliquid HIP-3 perps (`xyz:AAPL`, `xyz:GOLD`, `xyz:EUR`) | The Terminal data server only (`TR_SERVER_URL`) | Server mids | Server candles, book and trades | A HIP-3 perp is its own instrument, labelled `PERP · HL xyz` everywhere. `AAPL US Equity` stays the listed stock. `AAPL PERP` opens the perp linked to it, and `PERP` or ⇧P switches back and forth. A perp has no other source, so it never gets sample data; without the server it shows why. No keys are required. `TR_PROVIDER=sample` runs fully offline on deterministic, class-aware sample data (BTCUSD near 65,000, EURUSD near 1.09, US10Y near 4.2%) **with simulated live ticks**, and the live router falls back to sample data when a source is unreachable. Bars are cached in SQLite so charts paint from disk on start. Older history pages in as you scroll left. - **Congress trades** (key feature) - Ingests Periodic Transaction Reports from the **Senate eFD** (efdsearch.senate.gov: agreement + CSRF session, DataTables search API, HTML transaction tables) and the **House Clerk** (disclosures-clerk.house.gov: yearly `{year}FD.zip` XML index, PTR PDFs parsed with pure-Rust text extraction). Scanned paper filings are detected and recorded as such. - Normalises politician, party, chamber, state, ticker, buy/sell, amount range, transaction date and filed date into SQLite. Party comes from the official rosters (clerk.house.gov `MemberData.xml`, senate.gov `senators_cfm.xml`); politicians are keyed by bioguide ID, which also repairs typos in the source index. - Refreshed on a schedule (every 30 minutes by default, `TR_CONGRESS_REFRESH_MIN`, `0` disables; `REFRESH`/F6 forces one), incrementally — only unseen filings are fetched. - Panels: latest trades feed with party/chamber/side filters (`CONG`); per-ticker "who in Congress traded it" (`NVDA CONG`, or right-click any ticker); politician profile with trade history and **estimated performance** (amount-weighted directional return, hit rate, average disclosure lag) (`POL PELOSI`); directory (`POL`). - **Chart overlay**: B/S markers at transaction dates coloured by party (blue D, red R, purple I); hover for a card with politician, amount, owner, traded/filed dates and the disclosure lag. - **Alerts**: `TRACK ` (or ☆ in the directory/profile); when a tracked politician files a new PTR you get a toast, an `ALERTS n` badge and an entry in `ALERTS`. - **Dockable workspace and saved layouts** - Any panel (chart, watchlist, news, order book, world markets, yield curve, options, Congress feed, politicians, alerts, search, settings, help) docks anywhere: drag a tab (or a pane's header) onto another pane and drop on the compass (centre adds a tab, arrows split), with a ghost preview and a labelled landing highlight, or drag to a window edge. Resize with dividers (double-click to equalise), tabs in every pane, grid presets (`LAYOUT 1|2|2H|3|4|6` or the toolbar), and pop any pane out into its own native window (close it to dock back). Add panels from each pane's **+** menu, `NEW ` / `SPLIT [DOWN] ` or ⌘1…⌘0. - **Link groups**: give panes a colour (`LINK BLUE`, or the tab menu) and one security change drives every linked chart, order book, news, options and per-ticker Congress pane; clicking a row in a linked watchlist or world-markets pane loads it into the group. - **Saved layouts**: save, name, rename, duplicate, delete and switch (`LAYOUT `, the sidebar list, ⌥1…⌥9); the active layout autosaves and is restored on launch. Each layout is a JSON file in `~/Library/Application Support/terminal/layouts` (`$XDG_DATA_HOME` on Linux) and can be imported or exported (`LAYOUT EXPORT`/`IMPORT`, or Settings › Layouts). Per-pane settings (chart type, indicators, drawings, filters, depth, link, tab title) and, optionally, the theme (`LAYOUT THEME ON`) save with the layout. - **Themes** — built-in Terminal Dark, Terminal Light, Bloomberg (amber on black, monospace, compact), High Contrast, Solarized Dark/Light, Nord and Monokai. A theme sets every colour (backgrounds, panels, text, accent, up/down, candles, grid, series), the interface and number fonts and size, and density (compact, regular, comfortable). Pick one from the gallery in Settings › Appearance, the View menu, `THEME ` (prefix match), `THEME NEXT|PREV|LIST` or ⌘⌥T; `THEME SYSTEM` follows the OS with a chosen dark and light theme. Settings › Themes is a live editor: editing a built-in makes a copy (built-ins stay read-only); duplicate, rename, delete, import or export as TOML or JSON. Custom themes are TOML files in the `themes` folder next to `layouts`; a partial file inherits everything else from Terminal Dark or Light. - **Native, compact UI** — a macOS unified compact toolbar with the traffic lights inset, a translucent source-list sidebar with window vibrancy (`NSVisualEffectView` via `objc2`, in `crates/macos`) that can sit on either side (`SIDEBAR LEFT|RIGHT`, ⌘⌥S; the toolbar toggle moves and mirrors with it, right-click it for the View menu), SF Pro for chrome and SF Mono for numbers, segmented controls, spring animations, hover states and context menus. The System theme follows the OS appearance and accent colour; charts render at native retina scale with 4x MSAA. - **Brokerage accounts (SnapTrade)** — connect your brokers once through SnapTrade's Connection Portal (opened in your browser) and the terminal shows real accounts and balances (`ACCT`), positions with unrealised P&L (`POS`), orders from the last 30 days (`ORD`), activity such as trades, dividends, interest and transfers (`ACTV`) and a portfolio summary with allocation (`PORT`). Holdings are repriced with the terminal's own live quotes; clicking a position, order or activity row charts it, and right-click offers the option chain, news, Congress trades and watchlist. `AAPL POS` / `AAPL ORD` filter to one security, the account picker to one account. Stocks, ETFs, funds, crypto and options (OCC symbols shown as `AAPL 350C`) are supported. Read-only unless you turn on trading (below); Connect Brokerage requests read-only access. Without credentials the panes show a setup screen; offline (`TR_PROVIDER=sample` or `TR_BROKER=sample`) they show a clearly labelled simulated portfolio. See [Brokerage setup](#brokerage-setup-snaptrade). - **Demo account and easy trading** — a **DEMO** paper-trading account ($100,000 virtual cash) is selected by default; the toolbar badge shows DEMO or a red **LIVE** and switches between them (switching to live asks first and is remembered). Buy/Sell buttons sit on charts, watchlist rows and positions (plus **Close**), ⇧B / ⇧S trade the security in focus, and `BUY AAPL 10`, `SELL ALL TSLA`, `BUY NVDA $500`, `SELL MSFT 5 LMT 410` work from the command line or ⌘K. One compact ticket: side, shares or dollars, market/limit (stops under More), live estimated cost against buying power. Demo orders fill in one click at the live quote (limits and stops when the quote crosses) and persist in the app data folder; Settings › Trading resets the account. Live orders stay opt-in and go through SnapTrade's preview and a single confirmation. See [Trading](#trading-opt-in). - **Command palette** — ⌘K (Ctrl+K on Linux and Windows) opens a centred, theme-matched palette that fuzzy-searches every function code (`PORT`, `POS`, `ORD`, `OMON`, `THEME`, …), tickers (load the quote and chart), new panels, layout presets and saved layouts, themes, Settings tabs and workspace actions (move the sidebar, open Brokerage settings). Each row shows its shortcut; recent picks come first. ↑↓ select, ↵ open, Esc close. - **Hotkeys and preferences** — every hotkey is rebindable from a native shortcut table in Settings › Hotkeys and Help (click a binding, press the new keys); defaults for new charts and order books; everything persists in `prefs.json`. ## Running ```sh cargo run --release # Yahoo data, congress ingest in the background TR_PROVIDER=sample cargo run --release # offline APCA_API_KEY_ID=… APCA_API_SECRET_KEY=… cargo run --release # Alpaca ``` Data lives in `~/Library/Application Support/terminal` (macOS) or `$XDG_DATA_HOME/terminal` (Linux), or `TR_DATA_DIR`. Versions from before the project was renamed used a `terminal-rs` folder in the same place; the first launch moves it to `terminal` and leaves a link at the old path, so builds that still use the old name find the same files. The first congress ingest covers the current and previous year (a few minutes; it runs in the background while you work). `cargo run -p tr-congress --example ingest -- congress.sqlite3` runs one ingest from the CLI. Appearance: `TR_THEME=light|dark|` overrides the saved theme, `TR_MSAA=1|2|4|8` sets chart anti-aliasing (default 4 on macOS), `TR_VIBRANCY=0` disables the translucent sidebar, and ⌃⌘S (Ctrl+Shift+S elsewhere) toggles the sidebar. `scripts/bundle-macos.sh` builds a retina-capable `Terminal.app` (icon from `scripts/build-icon.sh`); `scripts/release-macos.sh` builds the universal (Apple Silicon + Intel) app, signs it with a Developer ID certificate, notarizes it and packages `Terminal.dmg`, plus the zip and signed `appcast.xml` that installed copies update from (one-time credential setup is at the top of the script). The app checks that feed once a day through [Sparkle](https://sparkle-project.org) and offers to install a newer release; Terminal › Check for Updates… or `UPDATE` checks at once. `scripts/check-macos-cross.sh` compiles and lints the whole workspace for aarch64-apple-darwin from Linux (zig as the C cross-compiler; linking needs the macOS SDK). ## In the browser The same code also builds for WebAssembly and runs in a browser tab on WebGPU: ```sh rustup target add wasm32-unknown-unknown cargo install wasm-bindgen-cli --version 0.2.129 --locked # must match Cargo.lock brew install binaryen # wasm-opt scripts/build-web.sh # writes site/static/app cd site && npm run dev # then open http://localhost:5173/app/index.html ``` `scripts/build-web.sh ` writes somewhere else instead; any static file server works. Add `?sample` to the URL to run offline on sample data, or `?fps` for the frame-time readout. Every push to `master` builds it and deploys it with the site to [terminal.rasmic.xyz/app](https://terminal.rasmic.xyz/app/). Pull requests get a preview; [site/README.md](site/README.md#deploys) covers the workflow and the secrets it needs. ![The browser build in Chrome: a live BTCUSD chart from Binance beside a demo-account position](docs/img/web-live-crypto.png) What the browser build can and can't do yet: - Crypto is live, because Binance and Coinbase allow cross-origin requests. History, quotes, order books and websocket bars all come from them. Yahoo, Treasury.gov, Alpaca and CoinDesk don't allow them, so every other market shows sample data and the toolbar says "Crypto live". A same-origin proxy can fix that later. - HIP-3 perps (`xyz:AAPL`) are live through the Terminal data server the page is built with. They never fall back to sample data: while the server is unreachable they say so. - Congress disclosures, SnapTrade accounts and live order entry need the desktop app. The paper trading demo account works. - Layouts, settings, themes and the demo account are saved in `localStorage` under `terminal/`. The first load copies anything saved under the old `terminal-rs/` prefix, without overwriting newer entries. - Charts need WebGPU, since they read bars from storage buffers in the vertex shader. Browsers without a WebGPU adapter get a second, larger build on WebGL2 where everything except the chart series works. Measured with Playwright driving Chrome 155 on an Apple M4 Pro: | | WebGPU build | WebGL2 build | |---|---|---| | `.wasm` | 5.60 MB (2.26 MB gzip, 1.69 MB brotli) | 7.48 MB (2.99 MB gzip, 2.22 MB brotli) | | JS glue | 115 KB | 169 KB | - A cold load from localhost draws its first frame 91 to 97 ms after navigation, the medians of three runs of 9 loads, two headless and one in a Retina window. On a 50 Mbit/s link with 40 ms of latency it takes 446 ms, and 1.64 s on 10 Mbit/s with 80 ms. - Panning and zooming a chart costs 1.3 to 1.5 ms of CPU in the UI code and 2.4 to 3.3 ms for the whole frame (medians across runs), and holds the display's 60 Hz. - egui's two emoji fonts, 740 KB together, load after the first frame instead of inside the `.wasm`. ## Brokerage setup (SnapTrade) Everything happens in **Settings › Brokerage**, with no commands needed. Open it from the sidebar (Portfolio › **Brokerage Settings**), the toolbar's View menu (**Brokerage Accounts…**), the gear button on any portfolio pane, or the setup screen; `PORT SETUP` still works too. 1. Create API keys (a client ID and consumer key) in the [SnapTrade dashboard](https://dashboard.snaptrade.com). Personal keys work too. 2. Enter the **Client ID** and **Consumer Key** (masked; **Show secrets** reveals them) and click **Save**. 3. Click **Register User**. This creates a SnapTrade user for this installation and saves its user secret, which SnapTrade only returns once. With personal keys, leave the user fields empty. 4. Click **Connect Brokerage…**. SnapTrade's Connection Portal opens in your browser with read-only access; sign in to your broker there. New accounts appear within a minute. The status card at the top always says where you are and what to do next ("Not set up", "Connected · 3 accounts at 2 brokerages · synced 14:32", or the API's error). **Test Connection** reloads accounts and connections on demand. **Connected brokerages** lists every connection with its accounts; a connection the broker has expired shows **Reconnect…**, which re-authenticates it in the portal, and **Disconnect** removes a connection and its accounts from SnapTrade after an explicit confirmation. **Where credentials live.** On macOS the client ID, consumer key, user ID and user secret are stored together in the **Keychain** (generic password, service `terminal`, account `snaptrade`); credentials saved under the old service, `terminal-rs`, move there the first time the app reads them. Elsewhere they go in `/secrets/snaptrade.json` with owner-only permissions (0600 in a 0700 directory). They are never written to the repository, layouts, prefs or logs; request errors are scrubbed of the URL (which carries the user secret), and the settings screen masks secrets. **Forget Credentials** removes them. `SNAPTRADE_CLIENT_ID`, `SNAPTRADE_CONSUMER_KEY`, `SNAPTRADE_USER_ID` and `SNAPTRADE_USER_SECRET` override the saved values field by field (useful for CI or a shell profile), and `TR_SECRET_STORE=file` uses the file store on macOS. **How it talks to SnapTrade.** Requests go to `https://api.snaptrade.com` and are signed as the SnapTrade docs specify: `clientId` and a Unix `timestamp` in the query, and a `Signature` header holding a base64 HMAC-SHA256 (keyed with the consumer key) of the canonical JSON `{"content","path","query"}`. Portfolios refresh every two minutes while a portfolio pane is visible (every 20 s for five minutes after opening the portal); `PORT REFRESH` reloads on demand. Brokerage data can be delayed or cached by SnapTrade depending on your plan, which is why holdings are repriced with the terminal's live quotes where a market key exists. ## Trading (opt-in) The **demo account** needs no setup: it is a local paper-trading account (`demo-account.json` in the app data folder) with no commissions, no short selling and Day orders expiring at the 4 p.m. New York close. Switch to your brokerage accounts with the toolbar badge, `MODE LIVE`, or Settings › Trading (`DEMO` switches back). Live trading is **off** until you enable it in **Settings › Trading**, which asks you to acknowledge that confirmed orders are real. Then: 1. Make sure the connection allows trading. Connections made with **Connect Brokerage** are read-only; **Reconnect with Trading Access…** in Settings › Trading opens the Connection Portal asking for trading access where the broker supports it (`trade-if-available`). Settings › Trading lists, per brokerage, whether trading is available, from SnapTrade's `allows_trading` flag and each connection's access type. 2. Open a ticket (`BUY AAPL 10`, a Buy/Sell button, ⇧B / ⇧S), pick the account and order type, and click **Review**. The broker checks the order through SnapTrade's [order impact](https://docs.snaptrade.com/reference/Trading/Trading_getOrderImpact) endpoint; nothing is placed. 3. The broker's estimate opens one confirmation dialog. **Send** places exactly the previewed trade (`POST /trade/{tradeId}`). Editing the ticket after previewing, or waiting past the preview's validity (SnapTrade expires it after five minutes), requires a new preview. A preview is used up when it is sent. If the answer is lost (network error, timeout, 5xx), the ticket reports the status as **unknown** and opens `ORD`, because the broker may have accepted the order; only a 4xx is reported as a rejection. Which order types a broker accepts varies and SnapTrade does not publish it per broker, so the preview is where unsupported combinations are rejected. Dollar amounts work only for market/day orders at brokers that support notional orders; fractional share quantities are refused up front at brokers SnapTrade reports as not supporting them. Settings › Trading also has an optional **maximum order value** and a default account. Trading access is read once per brokerage connection (`/authorizations`), cached for an hour (on disk too) with a **Refresh** button. SnapTrade requests are limited to four at a time; a rate-limited read waits for `Retry-After` and retries, and a rate limit is shown as a quiet "retrying" note rather than an error. Orders are never retried automatically. Tests never place real orders: the trading client is exercised only against a local mock server, and the app's flows against the simulated portfolio and the demo account. ## Keyboard shortcuts and commands Press **F1** (or type `HELP`) for the full, searchable list; every hotkey can be rebound in Settings › Hotkeys. On Linux and Windows ⌘ is Ctrl and ⌥ is Alt. | Keys | Action | |---|---| | ⌘K (Ctrl+K) | command palette: fuzzy search over commands, tickers, panels, layouts, themes, settings and actions | | F1 · F2 · F3 · F4 · F5 · F6 · F12 | help · Congress feed · politicians · alerts · watchlist · refresh filings · frame timing | | F7 · F8 · F9 | brokerage portfolio · positions · orders | | Tab · ⇧Tab | next · previous pane | | ⌘1 … ⌘0 · ⌘⇧O | new chart, watchlist, news, order book, world markets, yield curve, Congress, politicians, alerts, search pane · options chain | | ⌘D · ⌘⇧D · ⌘T · ⌘W · ⌘⇧P | split right · split down · new tab · close pane · pop out | | ⌘S · ⌥1 … ⌥9 | save layout · switch to saved layout 1–9 | | ⌃⌘S (Ctrl+Shift+S) · ⌘⌥S | toggle sidebar · move sidebar to the other side | | ⌘⌥T · ⌘, | cycle theme · settings | | ⌥T · ⌥H · ⌥V · ⌥F · ⌥M | draw trendline · horizontal · vertical · fib · magnet | | ⌥R · ⌥L · Esc · Del | reset chart view · log scale · cancel · delete selected drawing | | wheel · drag · drag axes · double-click | zoom · pan · stretch · reset | | Command | Action | |---|---| | `AAPL` · `AAPL US EQUITY ` | load a security in the focused chart | | `BTCUSD ` · `EURUSD ` · `US10Y ` · `CL1 ` · `SPX ` | other asset classes | | `5` `1H` `D` `1W` `1M` · `YTD` `5Y` `ALL` | interval · quick range | | `RSI` `MACD` `SMA 200` `BB 20 2.5` · `IND` `IND VOLUME` · `CLEAR` | toggle any of the 151 indicators (optional parameters) · indicator picker · remove all | | `CMP MSFT` · `LOG` · `CANDLE` `BAR` `LINE` `AREA` | compare · log scale · chart type | | `AAPL OMON` · `AAPL CN` · `BTCUSD CRNCY OB` · `WEI` · `GC` · `SECF ` | options · news · order book · world markets · yield curve · search | | `CONG` · `NVDA CONG` · `POL PELOSI` · `TRACK PELOSI` · `ALERTS` · `REFRESH` | Congress feed · who traded it · profile · track · alerts · refresh | | `NEW BOOK` · `SPLIT DOWN NEWS` · `POP` · `LINK GREEN` · `TITLE Desk` · `CLOSE` | add, split, pop out, link, rename, close panes | | `LAYOUT 4` · `LAYOUT SAVE Macro` · `LAYOUT Macro` · `LAYOUT RENAME Rates` · `LAYOUT DUP` · `LAYOUT DEL` · `LAYOUT EXPORT` | grid preset · saved layouts | | `THEME BLOOMBERG` · `THEME NEXT` · `THEME SYSTEM` · `THEME EDIT` · `THEME COMPACT` · `LAYOUT THEME ON` | themes | | `PORT` · `ACCT` · `POS` · `ORD` · `ACTV` · `AAPL POS` · `AAPL ORD` | brokerage portfolio · accounts and balances · positions · orders · activity · one security | | `PORT REFRESH` · `PORT CONNECT` · `PORT SETUP` (`BROKER`) | reload accounts · connect a broker in the browser · SnapTrade keys | | `BUY AAPL 10` · `SELL ALL TSLA` · `SELL MSFT 5 LMT 410` · `SELL TSLA 3 STP 250 LMT 245` · `BUY NVDA $500` · `TRADE` | order ticket, prefilled (demo: one click; live: review and confirm) | | `DEMO` · `MODE LIVE` · ⇧B · ⇧S | switch account mode · buy / sell the security in focus | | `SIDEBAR RIGHT` · `SIDEBAR` · `PREFS` · `HELP` | sidebar side or visibility · settings · help | | right-click chart / watchlist / feed row / sidebar toggle | context menu (chart type, indicators, draw, add to watchlist, who traded it, View menu) | ## Architecture ``` app/ eframe shell: command line, docked panes, chart widget, panels dock.rs docking tree (splits + tab groups): insert/move/remove, layout, resize, presets layouts.rs saved layout documents (JSON) and the layouts folder store prefs.rs appearance, keymap and panel defaults (prefs.json) themes.rs theme model, built-in themes, TOML/JSON theme files and the themes folder app/ workspace (drag and drop, pop-out windows, link groups), panels, settings, chrome worker.rs tokio runtime: all network, SQLite, pyramid and indicator work (UI never blocks) storage.rs saved files: the data folder on desktop, localStorage in the browser web.rs browser entry point (eframe web runner), console logging, frame timings web/ the page that hosts the browser build crates/core Bar/Series, timeframes, market keys + security catalog, indicators and their registry (codes, parameters, panes, levels), sample data crates/data MarketData trait; per-class router (Binance/Coinbase, Treasury.gov/FRED, Yahoo, Alpaca), websocket live feeds, sample provider with simulated ticks; bar cache; the browser router (crypto live, the rest sampled) and a tokio/browser task shim crates/chart wgpu renderer, LOD pyramids, viewport math, axes, drawings, egui paint callback crates/congress Senate eFD + House Clerk parsers, rosters, SQLite store, refresh, alerts, performance crates/broker SnapTrade client (request signing, accounts, balances, positions, orders, activity), order entry (impact preview, place, cancel, capabilities), portfolio model and P&L, Keychain / owner-only credential store, simulated sample and order simulator docs/analysis REA research notes on TradingView chart UX ``` **Rendering.** Bars are uploaded once per data version into a storage buffer as a level-of-detail pyramid (level *k* merges 2^k bars), and geometry is generated in the vertex shader (one instance per bar or line segment). Each frame picks the level that keeps instances at ≥ 2 px, so the work per frame is bounded by the plot width, not the series length: a 1M-bar chart fully zoomed out draws about 800 instances. Pan and zoom only rewrite a few hundred bytes of uniforms; bar indices are split into integer and fraction for f32 precision at millions of bars. Axes, legend, crosshair, drawings and markers are cheap egui shapes. **Threading.** The UI thread sends requests to the worker and drains responses each frame; history fetches, pyramid building (≈ 200 ms for 1M bars), indicators, SQLite queries and the congress ingest all run on tokio tasks. The worker owns each chart's bar series, so initial history, paging and live websocket ticks merge into one copy; live updates are coalesced to at most four GPU re-uploads a second. ## Performance Measured on Linux with Mesa **llvmpipe (a CPU software rasterizer)** — a real GPU is much faster: - **Cold start**: window and GPU ready in **143 ms**; charts paint from the SQLite cache as soon as the worker answers. - **1M-bar pan/zoom** (`cargo run --release -p tr-chart --example framebench`, 1600×900, candles + volume + 2 overlays, 300 frames per phase): | phase | CPU per frame p50 / p99 | until GPU done p50 / p99 | |---|---|---| | zoom out to all 1M bars | 0.07 / 0.20 ms | 3.09 / 5.27 ms | | pan across history | 0.06 / 0.18 ms | 1.40 / 3.93 ms | | zoom in to 8 px/bar | 0.05 / 0.19 ms | 1.34 / 2.63 ms | All within the 8.33 ms budget for 120 fps even on the software rasterizer. Criterion versions: `cargo bench -p tr-chart --bench frame`. - **In the app** (F12 readout, interactive wheel-zoom + drag): UI CPU ≈ 0.2 ms per frame, 118 fps. To try a million bars interactively: `TR_PROVIDER=sample TR_SAMPLE_BARS=1000000 TR_HISTORY_LIMIT=1000000 TR_FPS=1 cargo run --release`, then `1 `. With all 1M one-minute bars visible on llvmpipe under Xvfb the app measured UI CPU 0.36 ms and 76 fps for the whole window (software rasterization and presentation bound; the chart pass itself is the benchmark above). - **Indicators over 1M bars** (`cargo bench -p tr-core`): SMA 1.8 ms, EMA 2.2 ms, VWAP 7.0 ms, Bollinger 29 ms; RSI and MACD are single-pass (≈ 12 ms and 26 ms including first-touch of their output memory). The whole 151-indicator catalogue at default parameters over 100k one-minute bars takes ≈ 134 ms on macOS (Ichimoku, the slowest, 6.6 ms). ## Tests ```sh cargo test --workspace # unit + fixture tests (parsers, indicators, chart, app) cargo test -p tr-data -- --ignored # live tests: every asset class, quotes, curve, search, websocket cargo bench -p tr-core && cargo bench -p tr-chart ``` - Parsers are tested against real filings captured from the official sources (`crates/congress/tests/fixtures`): multi-page House PDFs with partial sales and page-break rows, spouse/joint owners, wrapped and open-ended amounts, CUSIP vs ticker, exchanges, private holdings, a scanned paper filing, Senate search JSON (electronic, paper and amended reports) and PTR tables. An end-to-end refresh test covers discovery, roster joins, idempotency and alerts. - Data-source parsers are tested against captured responses: Binance klines/24h ticker/websocket kline frames, Coinbase candles/stats/websocket ticker, Treasury.gov curve CSV, FRED CSV, Yahoo chart/spark/search. Market-key parsing, catalog search and symbol mapping per source are unit tested; opt-in live tests hit the real sources for every asset class. - Indicators are checked against reference values (Wilder's RSI example, hand-computed EMA, MACD, population-SD Bollinger, session VWAP) and hand-computed windows (stochastic, %R, CCI, WMA, true range, Donchian, envelopes, %B, OBV and A/D, CMF, Aroon, pivots). Every catalogue entry runs on intraday and daily random walks and on degenerate input (no bars, one to three bars, flat zero-volume bars) at its default, minimum and maximum parameters, checking alignment, declared ranges and no panics; layouts saved in the old indicator format still load. - Layouts: the dock tree (insert, split, tab, move, remove/normalise, resize clamping, presets, JSON round trip and repair of hand-edited files), layout documents (every panel kind and its settings, links, popped windows, older formats), the store (save, list, rename, duplicate, delete, import, export, safe file names), migration from pre-docking settings, prefs and keymap parsing/rebinding. - Themes: every built-in round-trips through TOML and JSON, partial theme files inherit from the dark/light base, the themes folder store (save, rename, delete, name collisions), copy-on-write names and migration of older appearance preferences. - Brokerage: request signatures match values computed independently with Python's `hmac` over the documented canonical JSON; an end-to-end test runs the client against a local mock SnapTrade server that verifies every request's signature, timestamp and auth parameters and serves fixtures shaped like the API's responses (stocks, ETFs, crypto, options, cash equivalents, string and numeric decimals, a failing account); P&L for longs, shorts and option multipliers; market-key mapping; OCC symbols; credential storage permissions and redaction; errors never echo the user secret; every portfolio view renders. - Trading: order validation (prices per order type, stop-limit direction, notional rules, path-safe ids); a mock SnapTrade trading server checks the signed symbol lookup, order impact, placement of the previewed trade, cancel and portal requests; expired or simulated previews are never sent; per-account capabilities from brokerage and connection; `BUY`/`SELL`/`TRADE` parsing; edited tickets invalidate their preview; the simulator fills, rests and cancels orders. - The chart renders real frames offscreen on whatever adapter is present and checks pixels. ## Platform notes and limitations - macOS is the primary target (wgpu Metal backend); Linux works with Vulkan or GL. This repository was developed and run on Linux (X11, software Vulkan). For macOS, the GPU and UI stack (`tr-core`, `tr-chart`, `tr-macos`, eframe/winit) is cross-checked for `aarch64-apple-darwin`, and CI (`.github/workflows/ci.yml`) builds, tests, lints and launches the app with screenshots on macOS arm64 and Intel runners. - Scanned paper filings (some House PTRs and Senate `/paper/` reports) are recorded and alerted but not OCR'd, so their trades are not itemised. - Estimated performance uses disclosed value bands (midpoints), so it is an estimate of trade-level skill, not a reconstruction of anyone's portfolio. - Yahoo's chart endpoint is unofficial and rate-limited; use Alpaca for a supported free source. Senate eFD terms prohibit using the data for commercial purposes or credit decisions; the terminal accepts the eFD agreement on your behalf for personal research use.