Overview
openportfolio is a self-hosted portfolio tracker with three jobs: hold every account as one book, keep the flows behind the price, and score the calls you made before the fact.
It is not a trading bot. The backend has no function that places an order, both shipped
adapters declare canPlaceOrders: false, and PlaceOrderRequest requires an
OrderConfirmation field that has no default. Aggregate, watch, keep score.
The pieces
| Piece | What it is |
|---|---|
convex/ |
The backend. Schema, tenancy gate, net worth, flows, forecasts, decisions, catalysts, audit, and the resolver cron. |
packages/core |
Money, dates and order primitives. No I/O. |
packages/domain |
The vocabulary: enums, Brier scoring, resolution criteria, the adapter contract. |
packages/node |
Anything that touches the network: Convex transport, keyless FX, the venue adapters. |
sync-worker.mts |
Reads balances through the adapters, re-quotes, converts, writes one snapshot. |
agent-worker.mts |
Dispatches work to an agent CLI. No provider key. |
mcp/ |
Stdio MCP server, 25 tools over one tenant's book. |
browser/ |
Four views: net worth, flows, track record, decisions. |
How a number gets on the page
- An account is linked with
accounts:link, naming the venue that serves it. - The sync worker asks that venue's adapter for balances.
- Rows with no usable price are re-quoted through the configured quote venue.
- Every row is converted into the tenant's base currency, and the rate is stored on the row it converted, so a snapshot records what the book was worth then rather than what today's rates say.
- One
netWorthSnapshotsrow is written, and the mutation appends to the audit log.
What is deliberately absent
- No provider API key. Model calls go to an agent CLI you are already signed in to. See MCP and agents.
- No keyed broker adapter in the repo. Credentials belong in your worker process, not in a public tree. See Venue adapters.
- No order path. Not disabled by a flag, absent from the backend.
Next: Quick start.