- Initial state load (positions + P&L) from REST
- Live deltas (fills, splits, redemptions) from WebSocket
- A reconciliation step that runs periodically
Architecture
Step 1 — Boot the state
Everything is keyed on the wallet address — no account setup needed, and it works for any address on Polymarket, not just your own.Step 2 — Subscribe to live deltas
Two channels matter for portfolio updates:trades (fills) and activity (splits / merges / redemptions). Filter both to the wallet.
A single Polymarket match emits both per-maker and taker-aggregate
order_filled rows. Apply only events where data["user"] equals your wallet to avoid double-counting — see Maker vs Taker emissions.Step 3 — Apply each delta to state
A fill changes a position’s size and cost basis. An activity event (split/merge/redeem) restructures positions. Worth modeling both — but at minimum, the trades handler is the must-have.Step 4 — The main loop
What the UI does with this state
For periodic mark-to-market, the cheapest pattern is batch the latest prices for all unique
token_ids in the positions list and refresh every few seconds.
Variations
- Multi-wallet dashboard: subscribe with
filters: {"users": [w1, w2, ...]}on both channels and keep one state object per wallet; boot each from the same two REST calls. - Alerting: add thresholds — alert on unrealized loss > X, on a new position above $Y, on a redemption event.
- Per-market P&L drill-down: pass
condition_idto Wallet P&L to break out a single market (correctly handles splits/merges). - Historical equity curve: pair with Wallet Volume Chart for cumulative-volume overlays.
Reference
- Wallet Positions — open positions with cost basis,
include_closedfor history - Wallet P&L — summary + realized P&L time series
- WebSocket trades, activity
- Best Practices — WebSocket reconnect
