* Add Hyperliquid HIP-3 perps as their own instruments A HIP-3 perp keeps Hyperliquid's coin name as its market key (xyz:AAPL, typed in any case) and a new Perp asset class. AAPL US Equity stays the listed stock. A reviewed table in tr-core links 27 app instruments to the perp on the same underlying, checked against trade.xyz's spec index, live meta and price. XYZ100, JP225 and HO stay unlinked because the docs don't name the index or tie the coin to the product. The gateway stops serving delisted markets. Hyperliquid keeps publishing mids for every delisted perp (56 core, 58 HIP-3 on 2026-11-02), so the market list, key resolution, subscriptions and history now check meta's isDelisted. A dex with nothing live gets no mids feed, as before. Perps come only from the Terminal server. Yahoo, the browser sources, sample mode and the Fallback wrapper refuse them instead of filling in. In the app, `AAPL PERP` opens the linked perp, and `PERP` or Shift+P switches the focused pane back and forth. Charts, books, tabs, the watchlist, the palette and SECF label perps "PERP · HL xyz". A chart on a linked instrument shows a switch chip once the server lists its perp as live, and a stock's simulated book offers the perp's real book, titled as the perp's. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Show a perp's trades beside its book, and record the HIP-3 decision The order book pane now lists recent trades when its book comes from the Terminal server. They go beside the ladder in a wide pane and below it in a tall one, and a perp's list is titled with its venue. They come from the server's trades topic through MarketData::trades, which no other source fills in. Fixes from reviewing the first commit: - With no server configured, perp_markets fails instead of returning an empty list. AAPL PERP then opens the perp, and its pane says why it can't load, instead of calling the perp not live. - The chart's switch chip draws only where it fits beside the bar count. - The PERP switching rule moved into tr-core (perps::switch_target), with a test. - The browser's source chip says "Crypto + perps live" when a server is in front, and its tooltip mentions HIP-3 perps. docs/architecture/server.md section 7 now records the decision and closes open question 9: the 27 links, the perps left unlinked and why, and how delisted markets are handled. The READMEs say where perps come from. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Say when a chart's cached bars couldn't refresh, and add the screenshots A chart paints from the disk cache, then refreshes from the network. If the refresh failed, it used to keep the cached bars and drop the error, so a perp whose server was down looked live. The range row now reads "5000 cached bars · the Terminal server is not reachable" in red. A failed page of older bars leaves the shown ones as they are. The book and trades say "the Terminal server is not reachable" when the connection is down, instead of a timeout's "deadline has elapsed". docs/img gets before and after shots for the desktop (an equity and a commodity with their perps, and the server down) and for the web build. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Keep delistings through failed refreshes, and stop showing old perp data From Greptile's review of #35: - A dex whose meta call fails now keeps what the last refresh listed. Before, its entries vanished from the registry, so its delisted markets resolved again. - Delisted markets' mids never enter the mids table. A market delisted while clients watch it loses its book, trades and bars streams: each subscriber gets Unavailable "... is delisted", and the upstream subscription goes. - A perp chart whose load failed asks the server again every 10 s while the pane shows it. Nothing else would reload it, since no live feed starts after a failed load. - The watchlist drops a perp's old quote when an answer leaves it out, instead of showing it as current. - A book or trades feed whose server lost Hyperliquid says "the Terminal server lost its Hyperliquid feed" until fresh data arrives. Crypto books fall back to Binance and Coinbase meanwhile, as they do when the server itself is away. Co-Authored-By: Claude Opus 5.5 <[email protected]> * Update the delisted set and the mids table under one lock From Greptile's second review of #35: set_delisted dropped a market's mid, released the table, and only then recorded the market as delisted. A mids message in between could put the market back, and quote subscribers would keep getting its price. Both now change under the table's lock, taken in the same order as apply. apply also drops any delisted market it finds in the table, so the next message from the venue clears one that got in anyway. Co-Authored-By: Claude Opus 5.5 <[email protected]> --------- Co-authored-by: Claude Opus 5.5 <[email protected]>
38 KiB
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 <GO>)
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
(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.
Built from reverse-engineering research. Chart UX was studied behaviourally on tradingview.com with 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/. 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
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 <EQUITY>,SPY <EQUITY>,SPX <INDEX>,BTCUSD <CRNCY>,EURUSD <CRNCY>,US10Y <GOVT>,CL1 <CMDTY>(keys display asAAPL 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 —
<SECURITY> [<FUNCTION>] <GO>(Enter is<GO>); 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 cmdtyopens 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 <SYM>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 withIND, 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 —
WEIworld markets (Americas/EMEA/Asia-Pacific indices, futures, Treasuries, FX, crypto and commodities with sparklines),GCUS 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, thenapi.binance.com), Coinbase Exchange fallbackBinance 24h ticker Binance kline websocket, Coinbase ticker fallback US Treasuries Treasury.gov daily par yield curve CSV (FRED fallback); Yahoo ^IRX/^FVX/^TNX/^TYXintradayTreasury.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_KEYare set, else YahooYahoo 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 xyzeverywhere.AAPL US Equitystays the listed stock.AAPL PERPopens the perp linked to it, andPERPor ⇧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=sampleruns 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.zipXML index, PTR PDFs parsed with pure-Rust text extraction). Scanned paper filings are detected and recorded as such.
- CSRF session, DataTables search API, HTML transaction tables) and the House Clerk
(disclosures-clerk.house.gov: yearly
- 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.govsenators_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,0disables;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 <name>(or ☆ in the directory/profile); when a tracked politician files a new PTR you get a toast, anALERTS nbadge and an entry inALERTS.
- Ingests Periodic Transaction Reports from the Senate eFD (efdsearch.senate.gov: agreement
-
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|6or 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 <PANEL>/SPLIT [DOWN] <PANEL>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 <name>, 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_HOMEon 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.
- 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 (
-
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 <name>(prefix match),THEME NEXT|PREV|LISTor ⌘⌥T;THEME SYSTEMfollows 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 thethemesfolder next tolayouts; 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 (
NSVisualEffectViewviaobjc2, incrates/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 ORDfilter to one security, the account picker to one account. Stocks, ETFs, funds, crypto and options (OCC symbols shown asAAPL 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=sampleorTR_BROKER=sample) they show a clearly labelled simulated portfolio. See Brokerage setup. -
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 410work 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. -
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
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|<theme name> 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 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:
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 <dir> 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. Pull requests get a preview;
site/README.md covers the workflow and the secrets it needs.
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
localStorageunderterminal/. The first load copies anything saved under the oldterminal-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.
- Create API keys (a client ID and consumer key) in the SnapTrade dashboard. Personal keys work too.
- Enter the Client ID and Consumer Key (masked; Show secrets reveals them) and click Save.
- 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.
- 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 <data dir>/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:
- 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'sallows_tradingflag and each connection's access type. - 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 endpoint; nothing is placed. - 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 opensORD, 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 <GO> |
load a security in the focused chart |
BTCUSD <CRNCY> · EURUSD <CRNCY> · US10Y <GOVT> · CL1 <CMDTY> · SPX <INDEX> |
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 <query> |
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, then1 <GO>. 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
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
hmacover 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/TRADEparsing; 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 foraarch64-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.










