// TRADERVIEW — TRADERVUE-STYLE TRADING JOURNAL

traderview v0.2.0 · Tauri v2 + axum · embedded or external Postgres · vanilla JS + uPlot frontend · 12 broker importers · 648-tile launcher · MIT

686,756 Rust LOC · 7 library crates + Tauri shell · 91 tables · 46 migrations · 1,952 axum routes · 646 view modules · 648 launcher tiles · 239,580 JS LOC · 3,898 CSS LOC

Report GitHub
// Color scheme

>_TRADERVIEW — FULL DESKTOP TRADING SUITE

Replaces TraderVue ($30/mo journal) + DayTradeDash ($187/mo scanner) + StockInvest in one self-hosted binary — $2,604/yr saved. Tauri v2 desktop that downloads and runs an embedded PostgreSQL on first launch with a local auto-user, plus an axum web binary with argon2 + JWT for multi-user deployment. Both share seven library crates and the vanilla JS + uPlot frontend. 646 view modules across a 648-tile categorized launcher (Cmd-K). Live streams: Nasdaq halts (3s RSS), SEC EDGAR + 4 PR wires (catalyst radar), Finnhub WebSocket (6-panel intraday scanner), Webull broker (read-only positions). Executions are the atom; trades are FIFO-derived; the journal is markdown; expenses get OCR receipts and Schedule-C export.

Quickstart

Clone the repo, vendor uPlot, then pick a deploy target:

# 1. clone + vendor uPlot
git clone https://github.com/MenkeTechnologies/traderview
cd traderview
./scripts/vendor-uplot.sh

# 2a. desktop — Tauri v2, embedded Postgres
cargo tauri dev          # first launch downloads PostgreSQL (~80 MB)

# 2b. web — axum, external Postgres
docker compose up -d postgres
export DATABASE_URL=postgres://traderview:traderview@localhost:5432/traderview
export TRADERVIEW_JWT_SECRET=$(openssl rand -hex 32)
cargo run -p traderview-web --bin server
# open http://localhost:8080

The desktop app is a single user, fully offline. The web binary is multi-user with registration and JWT bearer auth. Same schema, same migrations, same FIFO roll-up, same frontend, same API surface.

Architecture — One Workspace, Two Deploy Targets

┌──────────────────────────────────────┐ │ frontend/ (vanilla JS + uPlot) │ │ dashboard / trades / journal / ... │ └──────────────┬───────────────────────┘ │ HTTP /api/* ┌────────────────┴────────────────┐ │ │ ┌─────────▼──────────────┐ ┌────────────▼─────────────┐ │ src-tauri │ │ traderview-web (axum) │ │ (traderview-desktop) │ │ bin: server │ │ embedded postgres │ │ external postgres │ │ auto-login local user │ │ argon2 + JWT auth │ └─────────┬──────────────┘ └────────────┬─────────────┘ │ │ └────────────────┬────────────────┘ │ ┌────────────────▼─────────────────┐ │ traderview-{core, db, import} │ │ shared library crates │ └──────────────────────────────────┘

The desktop and web binaries are thin shells. All domain logic, all SQL, all broker parsing lives in the three library crates. The decision "embedded vs external Postgres" and "local auto-user vs multi-user with auth" is the only thing that distinguishes them.

Desktop · traderview-desktop

Tauri v2 shell. postgresql_embedded downloads a portable PostgreSQL on first launch (cached in ~/.theseus), data lives under $APP_DATA_DIR/traderview/pg/. Auto-creates a single local user and auto-logs in. Axum router runs on a random localhost port; the WebView talks to it via fetch. Postgres shuts down cleanly on window close.

Web · server

Axum 0.7 router on 0.0.0.0:8080 (configurable). Connects to external Postgres via DATABASE_URL. argon2 password hashing on registration, JWT bearer auth on every protected route. CORS allowlist via TRADERVIEW_CORS_ORIGIN. Refuses to start without TRADERVIEW_JWT_SECRET.

Shared · traderview-{core,db,import}

Three library crates that both binaries link. core owns models + FIFO roll-up + stats. db owns sqlx pool + migrations + embedded-Postgres lifecycle. import owns broker parsers (Webull first). One-way dependency graph: desktop and web both depend on all three; import and db both depend on core; nothing depends on desktop or web.

Crate Graph

CrateLinesPurpose
traderview-core150,944Domain types (User / Account / Execution / Trade / Plan / Goal / Strategy), FIFO roll-up, statistics (win-rate / expectancy / R-multiple / SQN / Sharpe / Sortino), Kelly + correlation-aware position sizing, Monte Carlo equity forecaster, stryke-JIT backtest engine + walk-forward sweeper, sentiment scoring, custom indicator AST.
traderview-db21,927sqlx pool factory + 46 embedded migrations, embedded PostgreSQL lifecycle (stale-PID lock cleanup, persisted password file), 50+ repo modules covering everything from trades & journal to live halts & catalysts & live_ticks stores. Background pollers for Yahoo / FINRA / EDGAR / nasdaqtrader / Finnhub WS / Reddit WSB / StockTwits / CoinGecko. In-process LRU caches with eviction.
traderview-import2,47712 broker CSV parsers — Webull, Lightspeed, IBKR Flex, ThinkOrSwim, TD Ameritrade, Schwab, Fidelity, ETrade, Robinhood, TradeStation, DAS Trader, TradeZero — plus a Generic ColumnMap parser for unknown sources (column-mapping wizard). Asset classes: stocks, options, futures, forex.
traderview-web57,771axum 0.7 router — 1,952 routes split across 89 route files. argon2 + JWT auth, multipart upload, WebSocket endpoints for halts / catalysts / live ticks / Webull. Custom request/response logging middleware (snippets bodies on 4xx/5xx). client-errors sink for browser-side reports.
traderview-expense447,269Trading-expense tracker — categorization rules engine, OCR-pipeline integration, Schedule-C report generator, multi-account reconciliation. Used by the expense view + receipt upload.
traderview-ocr3,926Receipt OCR via the system tesseract binary + image preprocessing (binarize, deskew). Extracts merchant / amount / date for the expense matcher.
traderview-tax1,948Tax computation crate — wage / cap-gains / Schedule-C lines, multi-state nexus, fed/state bracketing. Backs the tax wizard view.
src-tauri · traderview-desktop494Tauri v2 shell. Worker-thread bring-up of embedded Postgres → migrations → axum on a random localhost port; main thread waits on a channel for either an ApiConfig or a String error. Native-dialog on failure. tracing-appender non-blocking file log + panic hook to ~/Library/Application Support/traderview/traderview.log. Embedded handle held across axum::serve so Postgres can't be dropped mid-request.
Total686,756Plus 239,580 LOC vanilla JS (646 view modules) and 3,898 LOC CSS. No bundler, no npm.

Schema — 83 Tables, 38 Migrations

Migrations under migrations/0001_initial.sql through 0046_budgets.sql — each one adds a self-contained feature. Money is NUMERIC(20, 8) everywhere. 91 base tables, 130 indexes, 24 PostgreSQL enum types. Grouped by domain:

DomainRepresentative tables
Identity & accountsusers, accounts, api_tokens, mentorships
Execution & tradesexecutions, trades, trade_executions, trade_tags, tags, imports
Journaljournal_entries, note_templates, trade_reviews, chart_drawings, screenshots
Plans, goals, disciplineplans, trading_goals, goal_progress, discipline_violations
Price data & quotesbars, quote_snapshots, news_items, earnings_events, dividends
Live feedshalts, catalysts, mentions (sentiment), tick_snapshots
Watchlists & screeningwatchlists, watchlist_symbols, filter_sets
Alerts & webhooksalerts, strategy_alerts, strategy_alert_fires, hotkeys, webhooks, webhook_deliveries, disclosures_watchers
Backtest & strategybacktest_runs, backtest_presets, walk_forward_runs, custom_indicators
Paper tradingpaper_accounts, paper_orders, paper_positions
Portfolio / riskrebalance_targets, rebalance_runs, tax_lots
Disclosuresdisclosures (Form 4, 13D/G, Senate/House STOCK Act)
Communityshares, shared_comments, forum_categories, forum_threads, forum_posts, boards, board_items
Settings & AIuser_settings, ai_settings, ai_journal_cache, dashboards
Expensesexpense_accounts, expense_categories, expense_transactions, expense_rules, expense_receipts

Enum types (24): sides (side_t, trade_side_t), statuses (trade_status_t, order_status_t, review_status_t), asset classes, alert triggers, sentiment sources, halt reason codes, etc. — see migrations/0001_initial.sql and feature-incremental migrations for the full set.

HTTP API — 1,865 Routes Under /api/

89 route files in crates/traderview-web/src/routes/. Bearer-auth required on everything except /health, /config, /auth/*, and /client-errors. WebSocket endpoints expose live feeds. Grouped by domain (representative endpoints — see frontend/js/api.js for the full method-bound bindings):

GroupSample routes
Auth + configGET /config, GET /auth/me, POST /auth/login, POST /auth/register
Trades + executionsGET/POST /trades, POST /trades/rollup, POST /trades/{id}/risk, POST /trades/merge, POST /trades/bulk, POST /trades/close-expired-options, POST /trades/{id}/split, GET/POST /executions
Journal + AI + reviewsGET /journal/day/{day}, GET /journal/trade/{id}, POST /journal-ai/{id}/analyze, GET /trade-reviews/needed/{acct}
Reports (17 cuts)/reports/overview, /by-symbol, /by-day-of-week, /by-hour, /by-hold, /r-distribution, /comparison, /exit-efficiency, /liquidity, /drawdown, /risk-adjusted, /calendar
Live streams (WS)WS /ws/halts, WS /ws/catalysts, WS /ws/ticks, WS /ws/webull
Research per-symbol/symbols/{sym}/quote, /signals, /news, /earnings, /dividends, /recommendations, /insiders, /fundamentals, /holders
Screener + scannersGET /screener/run, GET /screener/top, GET /scans/run (24 presets)
Options + vol/options/{sym}, /greeks, /vol-surface/{sym}, /iv/scan, /iv/symbols/{sym}
Markets + breadth/markets/snapshot (cached), /premarket/snapshot, /breadth/snapshot, /fear-greed, /sector-rotation
Backtest enginePOST /backtest/run, POST /backtest/walk-forward, GET/POST /backtest-presets, POST /custom-indicators/eval/{sym}
Paper tradingPOST /paper/accounts, GET /paper/accounts/{id}/positions, POST /paper/accounts/{id}/orders, POST /paper/accounts/{id}/reset
Alerts + webhooks + hotkeysGET/POST /alerts, POST /alerts/{id}/toggle, GET/POST /strategy-alerts, GET /strategy-alerts/fires, GET/POST /hotkeys, GET/POST /webhooks, POST /webhooks/{id}/test
Sentiment/sentiment/feed, /sentiment/ranked, /sentiment/symbol/{sym}, /sentiment/series/{sym} (Reddit WSB + StockTwits)
Crypto/crypto/markets, /crypto/global, /crypto/btc/chain
Tax + reports/tax-lots/{acct}?year=&method=FIFO|LIFO, /r-distribution/{acct}, /discipline/{acct}, /mood-analytics/{acct}, /equity-forecast, /fill-quality/{acct}
Webull (read-only)POST /webull/connect (tokens in memory only), GET /webull/snapshot
Expenses + OCRGET/POST /expense/transactions, POST /expense/import, POST /expense/receipts, POST /expense/receipts/{id}/attach, GET /expense/report/schedule_c?year=
Community/shares, /shared/{slug}, /forum/threads, /forum/threads/{id}/posts, /mentorships, /boards
Custom dashboardsGET/POST /dashboards, GET /dashboards/{id} — user-defined boards built from widgets
Client error sinkPOST /client-errors (no auth — browser-side window.onerror + unhandledrejection + console.error funnel)

Desktop mode binds to a random localhost port and auto-logs in as the local user. Web mode requires POST /api/auth/login → JWT → Authorization: Bearer …. A custom request/response logging middleware records every request with elapsed_ms; 4xx/5xx responses get a 4KB body snippet attached to the log entry for offline debugging.

Frontend — Vanilla JS + uPlot, 641 Views, 644-Tile Launcher

Zero npm. Zero bundler. Zero JS framework. 239,580 LOC vanilla ES modules + 3,898 LOC CSS served as static files. axum's tower-http fs middleware in web mode; Tauri loads from disk via custom tauri://localhost scheme in desktop mode.

The launcher (Cmd+K) is the entry point — 646 tiles across 10 categories with a live-filter search and Enter-jumps-to-first-match. There is no fixed nav strip; the topbar carries 11 shortcuts and the rest is the launcher.

⚡ Live Markets (6 tiles)

Live Scanner (Finnhub WS, 6-panel), Halts (Nasdaq RSS + TTS), Catalysts (EDGAR + PR wires), Pre-market (futures + commodities + crypto + FX + econ events), Tape (time & sales), Heatmap (sector / S&P).

📊 Trading (16 tiles)

Webull (read-only broker), Live Positions (open P/L), Paper Trade, New Trade, Pre-trade Plans, Position Size (Kelly + correlation-aware), Hotkeys editor.

📓 Journal (9 tiles)

Journal (per-trade + daily + general), AI Journal (GPT post-mortem with cache), Trade Reviews (forced reflection on |R| ≥ 2), Trade Compare, Replay, Tape Replay, Discipline, Mood Analytics, Goals.

🔎 Charts & Research (178 tiles)

Charts (OHLC + persisted drawings), Research, Watchlists, Screener, Scanners (24 presets), Top Signals, Compare, Pairs, Correlation, Sectors, Sector Rotation, Breadth, Fear/Greed, Sentiment, Dark Pool, Short Interest, Volatility, Vol Surface, Options Chain, Earnings Cal, Earnings IV, Disclosures, Economy, News, Crypto.

📈 Reports (23 tiles)

Dashboard (overview + equity + world map), Reports (17 cuts), R-Multiple, Equity Forecast (Monte Carlo), Fill Quality (slippage vs NBBO), Risk, Rebalance, Tax Lots, Expenses (with OCR), Calendar, Accounts Overview.

🧷 Strategy & Automation (7 tiles)

Backtest (stryke-JIT), Backtest Presets, Walk-forward, Custom Indicators, Strategy Alerts (AND/OR/NOT), Alerts (price/threshold), Webhooks (Discord/Slack/generic).

💬 Community (4 tiles)

Shares (public trade links), Community (forum), Mentorship, Boards (public/private symbol boards).

⚙️ Admin & Data (18 tiles)

Import (12 brokers), CSV Wizard, Exports (CSV/JSON/Schedule D), Accounts, Tags, Search (full-text), Settings, Developer (API tokens), Tutorial (? hotkey).

Race-safe view dispatch. app.js maintains a per-dispatch token (currentViewToken()) bumped on every navigation. Every view captures the token at render start and bails after each await if the token is stale — prevents the "document.getElementById(...) returns null after navigation" crash that hits naïve SPAs when slow async resolves into a replaced DOM.

js/api.js wraps fetch with auth, error reporting, JSON parsing, and an ApiError class. js/error_reporter.js funnels window.onerror, unhandledrejection, and overridden console.error to POST /api/client-errors, queue-capped at 200 to survive a console-error loop. uPlot vendored under frontend/lib/ — pinned, reproducible, no CDN at runtime.

Importing — 12 Brokers + Column-Mapping Wizard

Built-in parsers (crates/traderview-import/src/brokers.rs):

  • Webull · Lightspeed · IBKR Flex · ThinkOrSwim · TD Ameritrade · Schwab · Fidelity · ETrade · Robinhood · TradeStation · DAS Trader · TradeZero · Generic (column-mapping wizard)

Pipeline per upload:

  1. Raw rows + file hash recorded in imports for audit / re-parse.
  2. Each row maps to an execution and inserts under (account_id, broker_order_id, executed_at, symbol, side, qty, price) — dedupe-safe.
  3. FIFO roll-up re-runs for affected (account_id, symbol) pairs and rewrites trades.

Re-importing the same CSV is idempotent. Unknown brokers go through the CSV Wizard — you point at any CSV, the UI maps columns to execution fields (symbol / side / qty / price / executed_at / fees), and the mapping is saved per-broker per-user. Asset class is auto-detected from symbol patterns (options: SYMyyMMddCNNNN; futures: =F suffix; FX: =X suffix).

Live Data Streams — Polled Upstream, Pushed Downstream

Server-side pollers run on tokio tasks, push to in-process DashMap+broadcast stores, then fan out to browsers over WebSocket. All stores are bounded with oldest-first eviction (halts cap 2,000; catalysts cap 10,000) so multi-day sessions don't grow without limit.

StreamSourceInterval
Haltsnasdaqtrader.com/rss.aspx?feed=tradehalts3s
EDGAR filingssec.gov/cgi-bin/browse-edgar?action=getcurrent&type=4&output=atom6s
PR wiresBusiness Wire / PR Newswire / GlobeNewswire / AccessWire RSS30s each
Finnhub tickswss://ws.finnhub.io (free tier: 25 syms / connection — chunked)realtime
Webull brokertradeapi.webullbroker.com (your pasted tokens; never on disk)5s
Reddit WSBreddit.com/r/wallstreetbets/new.json60s
StockTwitsapi.stocktwits.com/api/2/streams/symbol/{sym}.json60s per symbol
FINRA Reg-SHOcdn.finra.org/equity/regsho/daily/on demand (back-walked by day)
Yahoo quote / fundamentalsquery1.finance.yahoo.com v8/v10cached 60s per symbol in quote_snapshots + 60s in-process world-markets cache
CoinGecko + blockchain.comCrypto markets + BTC chain statson demand

Ticker extraction (catalyst NER) handles $SYM cashtags, parenthetical (SYM) with stop-word filter, and exchange-prefixed forms (NYSE:, NASDAQ:, AMEX:, OTC:). Halt reason codes (T1, T5, LUDP, MWC1/2/3, H10, …) are looked up in a static reason-code table for readable labels.

Resilience & Hardening

  • Stale-lock recovery. Embedded Postgres checks postmaster.pid before start; if the recorded PID is dead, removes the lockfile so a SIGKILL'd parent doesn't permanently block the next launch.
  • Persisted PG password. Random password file (mode 0600) in the data dir — initialized once, reused forever — so auth survives across launches.
  • Backend held across axum::serve. The Embedded handle is owned by the worker thread for the lifetime of the server; explicit drop after serve. Earlier, the handle dropped at function exit and pg_ctl stop killed Postgres mid-request — every subsequent query timed out with "pool timed out".
  • Real concurrency for multi-symbol fan-outs. premarket::snapshot + markets::snapshot + market_data::quotes + compare::compare all use futures_util::future::join_all — previously serial loops blocked /api/premarket/snapshot for 150 seconds and starved the pool.
  • Pool sized for cold-start fan-out. max_connections=32, min_connections=4 (kept warm), acquire_timeout=15s.
  • Per-view race tokens. Frontend dispatch increments a counter on every navigation; views bail post-await if their captured token is stale, preventing null-DOM crashes.
  • Browser-side error sink. window.onerror, unhandledrejection, and overridden console.error all POST to /api/client-errors (queue-capped). The Rust log mirrors every browser failure.
  • WebKit SecurityError guards. Under Tauri's tauri://localhost custom scheme, navigator.sendBeacon, Notification.requestPermission, new Notification, speechSynthesis.speak, and localStorage all throw cross-origin SecurityErrors. Each is try/caught so boot survives.
  • CSP allows ws://127.0.0.1:* so WebSocket connections to the dynamic backend port aren't blocked under custom scheme.

Configuration

VariableModeDefaultPurpose
DATABASE_URLwebrequiredPostgres connection string.
TRADERVIEW_JWT_SECRETwebrequiredHMAC secret for JWT signing. Rotate to invalidate outstanding tokens.
TRADERVIEW_BINDweb0.0.0.0:8080axum listen address.
TRADERVIEW_CORS_ORIGINweb*CORS allowlist.
TRADERVIEW_LOGbothinfotracing-subscriber env-filter directive.
$APP_DATA_DIR/traderview/pg/desktopOS app-data dirEmbedded Postgres cluster location.

The desktop app stores its Postgres cluster under the OS-appropriate app-data directory: ~/Library/Application Support/com.menketechnologies.traderview/pg/ on macOS, ~/.local/share/com.menketechnologies.traderview/pg/ on Linux, %APPDATA%\com.menketechnologies.traderview\pg\ on Windows.

What's Built

AreaItemStatus
FoundationWorkspace + 7 crates + 46 migrationsDone
FoundationFIFO trade roll-up + stats (expectancy, R-multiple, SQN, Sharpe, Sortino)Done
FoundationTauri v2 desktop + embedded Postgres bootstrap, axum web binary w/ argon2 + JWTDone
Import12 broker parsers + Generic column-mapping wizardDone
LiveHalts (Nasdaq RSS, 3s) + Catalysts (EDGAR + 4 PR wires) + Finnhub WS scannerDone
LiveWebull read-only broker integration (paste session tokens)Done
JournalPer-trade + daily + general notes, templates, trade reviews, AI post-mortem cacheDone
Analytics17 reports + R-distribution + Monte Carlo forecast + fill-quality + tax-lot tracker + Schedule D exportDone
Strategystryke-JIT backtest + walk-forward sweeper + custom-indicator AST + strategy alerts (AND/OR/NOT)Done
ResearchOptions chain + Greeks + IV surface + earnings-IV crush + short interest + dark poolDone
CommunityPublic trade shares + forum + mentorship + boardsDone
ExpensesMulti-account expense tracker + receipt OCR + Schedule-C reportDone
UX648-tile launcher (Cmd-K) + in-app tutorial (?) + 11-shortcut topbarDone
HardeningPer-view race tokens + browser-side error sink + WebKit SecurityError guards + bounded in-memory cachesDone
RoadmapLightspeed live broker (currently CSV-only)Planned
RoadmapCloud sync — encrypted snapshot to S3/R2Future

What This Replaces

ToolCostReplaced by
TraderVue (trade journal)$30/moTrades + Journal + Reports + AI Journal + Trade Reviews
DayTradeDash (Warrior Trading scanner)$187/moLive Scanner + Halts + Catalysts + Pre-market + Scanners (24 presets)
StockInvest.us (signal site)variesTop Signals + Screener + Research (per-symbol dossier)
Zendoo Live Scannersfree w/ TTSLive Scanner with built-in TTS voice alerts
Total saved$2,604/yr (self-hosted, your data stays local)

Built by MenkeTechnologies, part of the MenkeTechnologiesMeta stack alongside strykelang, zshrs, zpwr, and the broader Rust + CLI family.