openportfolio
openportfolio
Jedes Konto als ein Buch. Jede Prognose aktenkundig.
Open-Source-, selbst gehosteter Portfolio-Tracker. Er zieht jede Brokerage, jede Rente, jede Wallet und jedes Bankkonto in einen einzigen Nettovermögenswert zusammen, speichert die Anlegerflüsse hinter dem Preis und bewertet die Prognosen, die du vorab registriert hast, nach Brier. Kein Provider-API-Schlüssel, nirgendwo darin.
Dashboard und Backend mit einem Klick. Der Sync-Worker läuft auf deiner Maschine, by design: siehe Deploying.
Screenshots zeigen das Demo-Buch. Jede Zahl darin ist erfunden.
Status: Vorabversion. Es läuft und das Setup unten funktioniert. Schnittstellen werden sich noch ändern.
Es ist kein Trading-Bot. Das Backend hat keine Funktion, die einen Auftrag platziert, die mitgelieferten Adapter deklarieren canPlaceOrders: false, und PlaceOrderRequest erfordert eine OrderConfirmation, die keinen Standardwert hat. Was es tut, ist aggregieren, beobachten und Buch führen.
Warum
Zwei Probleme, die nicht zusammenhängen und dasselbe Problem sind.
Ein Portfolio ist per Konstruktion verstreut. Ein Broker hier, eine Pension dort, eine ISA, ein Exchange-Konto, ein Bankguthaben, eine Beteiligung, die keine API je zurückgeben wird. Jede dieser Apps zeigt dir eine Zahl, und keine zeigt dir deine. Also sind die Zahlen, die tatsächlich Entscheidungen bestimmen – die Gesamtsumme, die Konzentration auf einen Namen, der Anteil des Buches in einer Währung, die du nicht ausgibst – die Zahlen, die niemand hat. Sie werden geschätzt, und die Schätzung ist großzügig in die Richtung, die eine Entscheidung vermeidet.
Marktkommentare sind nicht rechenschaftspflichtig, und wurden es noch mehr, sobald ein Modell zu allem, was du fragst, eine selbstbewusste Richtungsmeinung produzieren würde. Das Problem ist nicht, dass die Meinungen falsch sind. Es ist, dass falsch zu sein nichts kostet und keine Spur hinterlässt, sodass ein Prognostiker, der es wert ist, gelesen zu werden, und ein Prognostiker, der nur fließend spricht, von außen und auch von innen nicht zu unterscheiden sind.
Beides sind Buchhaltungsfehler, also behandelt openportfolio sie als Buchhaltung.
Ein Nettovermögen | Konten werden über Venue-Adapter in eine einzige Basiswährung gezogen, wobei der Kurs auf der Zeile gespeichert wird, die er umgerechnet hat, sodass ein Snapshot festhält, was das Buch damals wert war, und nicht, was die heutigen Kurse sagen. Positionen, die an drei Orten gehalten werden, sind eine einzige Exposition. |
Flüsse, nicht nur Preise | Der Preis ist das Ergebnis davon, wer gekauft hat und wer zum Verkauf gezwungen wurde. Netto-Käufe nach Anlegertyp, Umsatz und ein Kalender datierter zukünftiger Ereignisse werden als erstklassige Serien gespeichert, nicht abgeleitet, wenn jemand sich erinnert zu fragen. Ein Zwangsverkäufer hat einen Zeitplan, und der Zeitplan ist öffentlich. Die Positionierung nach Teilnehmerklasse kommt schlüssellos aus den wöchentlichen Commitments of Traders der CFTC. |
Eine bewertete Erfolgsbilanz | Ein Aufruf wird vor der Tatsache mit einer Wahrscheinlichkeit, einem Horizont und der Bedingung, die ihn beendet, registriert. Wenn der Horizont überschritten ist, erledigen sich die maschinenauflösbaren selbst und werden nach Brier bewertet. Das Zuverlässigkeitsdiagramm ist das Produkt: Es zeigt, was du gesagt hast, was passiert ist und die Lücke dazwischen. |
Es gibt eine vierte Tabelle, die aus einem einzigen Grund existiert. Eine Empfehlung, die als „warte auf den Druck, dann entscheide“ formuliert ist, verdampft in dem Moment, in dem sie laut ausgesprochen wird. decisions ist eine Warteschlange dieser, jede mit einer Auslösebedingung und einem Ergebnis, und sie bleiben auf dem Board, bis sich eine von ihnen ändert.
Related MCP server: FinChat
Kein Provider-API-Key
Ein Buch zu beobachten ist nur nützlich, wenn tatsächlich etwas beobachtet: nach dem Schluss abgleichen, einen Aufruf am Tag seines Horizonts erledigen, bemerken, dass eine aufgeschobene Entscheidung vor drei Wochen fällig wurde.
Metered Inference ist die falsche Form dafür. Wenn jede Ausführung pro Token abgerechnet wird, wird jede autonome Prüfung zu einem Kauf, und ein Produkt, das das Geld des Betreibers unaufgefordert ausgibt, muss zuerst fragen, oder bündeln, oder rationieren. Alle drei verwandeln ein Portfolio, das sich selbst beobachtet, in ein Portfolio, das um Erlaubnis zum Hinsehen bittet.
Also wird jeder Modellaufruf stattdessen an eine Agent-CLI gesendet, bei der du bereits angemeldet bist: codex, antigravity oder claude, mit einer pro-Aufgabe-Fallback-Reihenfolge. Es gibt keinen Provider-Key in diesem Repo und kein Feld, um einen einzutragen. Das macht einen Lauf nicht kostenlos: Abonnementpläne haben Rate-Limits, und die Fallback-Kette existiert teilweise, weil ein Provider vor den anderen ausgeht. Was sich ändert, ist die Art des Limits. Agentenarbeit ist durch Kontingent und Wanduhr begrenzt, nicht durch Ausgaben, also muss sie nie einzeln gerechtfertigt werden.
Die Konsequenz ist, dass openportfolio by design selbst gehostet ist. Deine Bereitstellung führt deine Syncs auf deiner Maschine unter deinen eigenen Logins gegen deine eigenen Konten aus.
Was es tut
Oberfläche | |
Nettovermögen | Konten, Salden, Aufschlüsselung nach Anbieter und Anlageklasse, Snapshots in einer Basiswährung, schlüsselloses FX |
Venues | Adaptervertrag mit deklarierten Fähigkeiten; schlüssellose Kurs-Adapter für börsennotierte Instrumente und für Coins, plus ein manueller |
Flows | Netto-Käufe und Umsatz nach Anlegertyp pro Sitzung, pro Markt oder pro Symbol |
Prognosen | Wahrscheinlichkeit, Horizont und Auflösungskriterium; automatische Auflösung bei Horizontablauf; Brier-Score und Zuverlässigkeits-Buckets |
Entscheidungen | Die Warteschlange der aufgeschobenen Entscheidungen, mit Auslösebedingungen und Ergebnissen |
Katalysatoren | Datierte zukünftige Ereignisse und die Vermögenswerte, die sie berühren |
Audit | Append-only-Aufzeichnung jeder zustandsändernden Mutation, einschließlich dessen, was der Cron unbeaufsichtigt tat |
MCP | 25 Tools, damit |
Multi-Tenancy | jede Tabelle auf einen Mandanten begrenzt, jeder Index führt mit ihm, ein Service-Key pro Mandant |
Schnellstart
Node 22+, pnpm und ein Convex-Konto. Der kostenlose Tarif reicht aus.
git clone https://github.com/seonglae/openportfolio.git
cd openportfolio
pnpm install
cp .env.example .env.local
npx convex dev --once # creates the deployment
# create the first book
npx convex env set OPENPORTFOLIO_DEV_TENANT home
npx convex run tenants:create '{"slug":"home","name":"Home","baseCurrency":"GBP"}'
# the UI, then the sync loop
pnpm --filter openportfolio-browser dev # http://localhost:6101
npx tsx sync-worker.mts --onceMit nichts verknüpft registriert es die Venues, die es bedienen kann, und zeichnet einen Nettovermögenswert von null auf, was korrekt ist. Füge eine manuelle Bestandsdatei hinzu, um einen echten zu erhalten:
[
{ "accountKey": "isa", "symbol": "VWRL", "assetClass": "etf", "qty": 40, "price": 118.2, "currency": "GBP" },
{ "accountKey": "wallet", "symbol": "BTC", "assetClass": "crypto", "qty": 0.15, "price": 0, "currency": "USD" }
]export OPENPORTFOLIO_MANUAL_HOLDINGS=$PWD/holdings.json
npx convex run accounts:link '{"accountKey":"isa","venue":"manual","kind":"brokerage","label":"ISA","currency":"GBP"}'
npx convex run accounts:link '{"accountKey":"wallet","venue":"manual","kind":"wallet","label":"Wallet","currency":"USD"}'
npx tsx sync-worker.mts --oncePreise in der Datei sind ein Ausgangspunkt, nicht die Aufzeichnung: Der Worker bewertet jede Zeile, die er kann, über eine schlüssellose Quelle neu, leitet sie nach Anlageklasse, konvertiert sie in GBP und schreibt eine Gesamtsumme. Aktien, ETFs und Fonds gehen an Yahoo, Coins an CoinGecko. Eine Zeile, deren aufgezeichneter Preis ist die Aufzeichnung, eine Pension oder eine Immobilie, erhält die Klasse other, nach der keine Kursquelle gefragt wird.
Vollständige Anleitung: openportfolio.app/docs/quickstart
Oder deploye es
Dieser Ablauf klont dieses Repository in dein eigenes Git-Konto, installiert die Convex-Integration aus dem Vercel-Marketplace und stellt ein Convex-Projekt unter deinem eigenen Convex-Team bereit, fragt dich nach einem Wert und baut beide Hälften in einem einzigen Befehl:
npx convex deploy --cmd-url-env-var-name VITE_CONVEX_URL --cmd 'pnpm --filter openportfolio-browser build'Der Marketplace-Schritt ist der einzige Grund, warum das ein Klick ist statt zwei: Vercel kann das Backend während des Imports erstellen, statt dich wegzuschicken, um zuerst eines zu machen, und es übergibt dem Build einen Deploy-Key. vercel.json schützt den Befehl auf CONVEX_DEPLOY_KEY und fällt auf einen einfachen Browser-Build zurück, sodass dieselbe Datei auch eine Bereitstellung abdeckt, die du selbst bereitgestellt hast und für die du jetzt eine gehostete Seite möchtest. Ohne den Schutz würde dieser Fall seinen Build fehlschlagen.
Es fragt dich nach nichts. Die Anmeldung benötigt keinen Schlüssel, weil sie innerhalb der gerade erstellten Bereitstellung läuft: Die Authentifizierung ist Convex Auth mit einem Passwort-Provider, also prägt und verifiziert deine Bereitstellung ihre eigenen Token und eine Anmeldung verlässt sie nie. Kein Auth-Unternehmen im Pfad, kein Konto, das du woanders erstellen musst. Convex Auth ist upstream in Beta, was der ehrliche Preis der Wahl ist.
Dann ein einziger Befehl auf der Convex-Seite, um die Signaturschlüssel des Deployments zu generieren und das erste Buch zu erstellen. Die erste Anmeldung besitzt es:
npx @convex-dev/auth
npx convex run tenants:create '{"slug":"home","name":"Home","baseCurrency":"GBP"}'Anmeldungen schließen sich dann von selbst: Ein Aufrufer, der zu keinem Mandanten gehört, darf nur das allererste Buch erstellen, sodass eine öffentliche URL nicht zum Backend eines anderen wird. OPENPORTFOLIO_OPEN_SIGNUP=1 öffnet es wieder.
Der Sync-Worker ist nicht Teil davon und kann es nicht sein. Er liest deine Konten über die Adapter und weist Modellarbeit einer Agent-CLI zu, bei der du angemeldet bist, und es gibt keine angemeldete CLI innerhalb einer serverlosen Funktion. Die bereitgestellte Hälfte löst weiterhin Prognosen auf und bewertet sie auf Convexs eigenen Crons; führe den Worker aus, wenn du möchtest, dass sich Salden aktualisieren. Details: Deploying.
Es gibt keinen Cloudflare-Button: Dieser Button unterstützt nur Workers, und sein Monorepo-Modus verlangt, dass die App vollständig in ihrem Unterverzeichnis isoliert ist, was browser/ nicht ist.
Bevor du sie freigibst
Zwei Dinge sind auf localhost offen und müssen geschlossen werden, bevor das Deployment aus dem Internet erreichbar ist.
Der Dev-Mandant. Solange
OPENPORTFOLIO_DEV_TENANTgesetzt ist, wird jeder nicht authentifizierte Aufrufer auf diesen Mandanten beschränkt. Setze ihn zurück. Die Anmeldung ist bereits vorhanden und benötigt keine Konfiguration.Service-Schlüssel. Worker und der MCP-Server haben keine Browser-Sitzung, daher präsentieren sie einen Schlüssel. Generiere ihn lokal und sende nur seinen Hash.
npx @convex-dev/auth # once, generates this deployment's signing keys
npx convex env unset OPENPORTFOLIO_DEV_TENANT
KEY="$(openssl rand -hex 32)"
npx convex run tenants:issueServiceKey "{\"key\":\"$KEY\",\"label\":\"sync-worker\",\"role\":\"member\"}"
echo "OPENPORTFOLIO_SERVICE_KEY=$KEY" >> .env.localMulti-Tenancy
Ein Deployment enthält viele Bücher. Die Invariante ist, dass ein Aufrufer niemals sagt, welcher Mandant er ist.
tenantId wird aus den Mitgliedschaftszeilen des Aufrufers oder aus der eigenen Zeile des Service-Schlüssels abgeleitet, sodass es kein Argument gibt, das ein Client setzen kann, um ein anderes Buch zu erreichen. Die öffentliche API akzeptiert tenantSlug, und nur als Disambiguator für einen Aufrufer, der zu mehreren Mandanten gehört; die Mitgliedschaft entscheidet weiterhin. Eine Dokument-ID, die zu einem anderen Mandanten gehört, wird als fehlend statt als verboten gelesen, weil „verboten" bestätigt, dass die Zeile existiert, was selbst der mandantenübergreifende Lesezugriff ist.
Jeder Index beginnt mit tenantId, sodass eine Abfrage, die den Geltungsbereich vergisst, überhaupt keinen Index verwenden kann. Eine Ausnahme ist absichtlich und markiert: Der Resolver-Cron durchläuft die fälligen Aufrufe jedes Buchs über einen mandantenlosen Index und ist aus genau diesem Grund eine internalMutation. Er ist von keinem Client erreichbar.
Details: openportfolio.app/docs/multi-tenancy
Venue-Adapter
Ein Adapter deklariert, was er kann, und implementiert nur das:
type VenueAdapter = {
venue: string;
kind: AccountKind;
capabilities: { canReadBalances: boolean; canReadQuotes: boolean; canPlaceOrders: boolean };
readBalances(request: ReadBalancesRequest): Promise<AdapterBalance[]>;
readQuote(request: ReadQuoteRequest): Promise<AdapterQuote>;
placeOrder?(request: PlaceOrderRequest): Promise<OrderReceipt>;
};Vier werden mitgeliefert, keiner davon schlüsselbasiert. yahoo bepreist alles, was irgendwo notiert ist, in der Währung, in der die Notierung gehandelt wird, sodass ein Buch mit US-Aktien, LSE-ETFs und KRX-Namen aktuell bleibt, ohne ein Konto bei einem von ihnen. coingecko bepreist Coins. Beide verweigern Salden, weil eine Preisquelle nicht weiß, was du hältst, und die Rückgabe einer leeren Liste wie „du hältst nichts" gelesen würde. manual liest eine JSON-Datei, die du pflegst – so gelangt eine Pension oder eine nicht börsennotierte Beteiligung in die Summe, statt davon ausgeschlossen zu sein. csv liest einen eigenen Export des Brokers: Zeige mit OPENPORTFOLIO_CSV_DIR auf einen Ordner und lege <accountKey>.csv hinein. Spalten werden nach Namen abgeglichen, sodass die meisten Exporte unverändert funktionieren, und es deckt die Konten ab, die niemals eine API haben werden.
Welche Quelle welche Zeile bepreist, entscheidet die bereits darauf befindliche Anlageklasse, und nichts fällt auf die andere zurück. Beide beantworten das falsche Instrument mit einem HTTP 200: Frag Yahoo nach BTC und es gibt einen Grayscale-Trust bei etwa 30 $ zurück statt Bitcoin bei etwa 68.000 $, und CoinGecko hat einen Token mit der ID aapl, der etwa 18 Cent wert ist. Eine falsche Zahl in der Summe ist schlimmer als eine fehlende, daher wird eine Klasse, nach der keine Quelle gefragt werden sollte, einfach nicht neu bepreist.
Es wird kein schlüsselbasierter Broker-Adapter mitgeliefert. Einen hinzuzufügen bedeutet, ein Modul in packages/node/src/adapters/ zu schreiben, seine Anmeldedaten aus der Umgebung des Workers zu nehmen und es in defaultRegistry() zu registrieren. Behalte die Anmeldedaten im Worker-Prozess: Das Backend sieht sie nie, und dieses Repo auch nicht.
Details: openportfolio.app/docs/adapters
Anforderungen
Node 22+, pnpm
Ein Convex-Konto (der kostenlose Tarif reicht)
Mindestens eine angemeldete Agent-CLI, wenn du den Agent-Worker möchtest:
codex,antigravity(agy) oderclaudeSonst nichts. Die Authentifizierung ist Convex Auth, das in deinem eigenen Deployment läuft, sodass es keinen Identitätsanbieter gibt, bei dem du dich anmelden musst
Entwicklung
pnpm typecheck # every workspace, src and test alike
pnpm test # vitest across packages, convex handlers, browser helpers
# the demo build used for the screenshots and the hosted demo
pnpm --filter openportfolio-browser exec vite build --config vite.demo.config.ts
# the marketing site and docs are static; regenerate the docs pages after editing
python3 site/build-docs.pyKonventionen, die Mandanten-Invariante in voller Länge und Hinweise für Agent-CLIs, die in diesem Repo arbeiten, findest du in AGENTS.md.
Lizenz
Apache-2.0. Siehe LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to manage and analyze personal investment portfolios, including fund and stock holdings, net value tracking, XIRR calculations, penetration analysis, and backtesting.Apache 2.0
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to manage personal finances through MCP tools for transaction management, spending analytics, and goal tracking.1
- FlicenseNot gradedqualityBmaintenanceSelf-hosted household finance app for shared expenses, budgets, investments, loans, and zakat, exposing MCP tools for AI agents to manage finances via natural language.3
- FlicenseNot gradedqualityCmaintenanceAn MCP server that exposes personal financial data — transaction ledger, portfolio holdings, live/historical market prices, and quantitative risk metrics — as standardized tools, resources, and prompts, enabling natural language reasoning over real computed numbers.
Related MCP Connectors
Real SEC, 13F, insider, congress & macro data your AI agent can cite. Hosted MCP, 24 tools.
The financial MCP for AI agents - 90+ financial tables, SEC filings, signals, alt-data.
Shared long-term memory vault for AI agents with 20 MCP tools.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/seonglae/openportfolio'
If you have feedback or need assistance with the MCP directory API, please join our Discord server