openportfolio

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

  1. An account is linked with accounts:link, naming the venue that serves it.
  2. The sync worker asks that venue's adapter for balances.
  3. Rows with no usable price are re-quoted through the configured quote venue.
  4. 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.
  5. One netWorthSnapshots row 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.