Portfolio Manager

What It Is

The cockpit for my real US brokerage account: positions, leverage, trade journal, and the discipline layer on top. It deliberately does not place trades — the broker does execution, this app keeps me honest about the trades I place. Anchor & Flow, my position framework, is the backbone: anchor positions define the book, flow positions rotate, and every holding gets audited against the rules instead of my mood.

Claude Is the Sync Engine

The data pipeline is the unusual part. The official IBKR MCP connector is OAuth'd to my Claude account and can only be called from inside a Claude chat — the backend on Cloud Run can't touch it. So the sync pattern is: I say "sync my IBKR" in a chat, Claude pulls positions, balances, and trades from the connector, and POSTs the raw payload to one import endpoint. Claude is the fetcher; the backend is the sink.

This replaced the old TWS Gateway integration, which was worse than it sounds: Gateway holds a single login session, so every sync from the server kicked my mobile app off the account. The connector killed that whole class of pain.

A Journal That Can't Lie

The trade journal keys every row on IBKR's own trade ID, so re-syncing is idempotent — importing the same window twice can't create duplicates. That property earned its keep during the rebuild: the old journal had accumulated ~1,100 rows of import junk (hundreds of duplicates, sell rows with zero proceeds, a few trades that never actually filled). Rebuilt from the connector's history it came out to 963 authoritative trades, with my hand-written trade notes preserved across the wipe.

Same honesty rule for the scorecard: monthly P&L is the sum of IBKR's per-trade realized P&L — commission-inclusive, correct for options — not a naive entry-minus-exit calculation. The naive version diverged from reality by up to 2x. If the number on the dashboard can't survive reconciliation against the broker statement, it doesn't ship.

Tripwires, Not Willpower

For every open option position I pre-commit the levels while I'm still objective: the underlying price where the thesis is broken (cut), where it's working, a time stop, and a premium backstop. On every sync the backend checks the live underlying against the plan and writes an alert only when the status transitions — one clean signal, not a daily nag.

Three days after this shipped, it fired on a real position: the underlying broke the cut level and the alert landed exactly as designed. The lesson it forced was better than the feature — overriding a tripwire requires drawing a new concrete line, because "monitor closely" is how a broken thesis becomes a bigger loss.

The Audit Bot

Type a ticker, get a verdict. The System Audit Bot runs each holding through a Minervini-style Trend Template — moving-average structure, position in the 52-week range, relative strength against a real ranked universe — and returns an action with an ATR-based plan attached: hard stop at 2×ATR, trim level at 1.5×ATR, pyramid levels if the position is proving itself. A leverage gauge tracks the whole book against my 1.5x tolerance with dollar headroom and a what-if input.

The weekly review tab holds the rules I wrote after breaking them with real money — diagnose before liquidating, never set the stop at your entry, no market orders on thin names, hedge by de-levering. The app's job is to put those rules in front of me while I still have the position.

Stack

React 19 + TypeScript PWA on Cloudflare Pages, FastAPI on Cloud Run, Turso (libSQL) for storage. No WebSockets, no daemons — state advances when a sync runs, which turns out to be exactly as real-time as a swing trader needs.

The original build story — from back when this was a WebSocket dashboard talking to a local Gateway.