A local-first Windows trading dashboard and API for Interactive Brokers TWS and IB Gateway.
PersonalTrader brings portfolio monitoring, order entry, broker callbacks, reconciliation, and local automation into one consumer-facing application. It keeps Simulator, IBKR Paper, and explicitly activated IBKR Live sessions isolated from one another. TWS or IB Gateway stays logged in locally as the authenticated broker bridge; the dashboard, cURL/Postman, and the typed .NET client all use one PersonalTrader-owned broker session.
Caution
PersonalTrader is pre-release trading software. IBKR Live can submit real orders using real money. Start with Simulator, complete the full Paper workflow, inspect the code, and set conservative limits before considering Live. Automated tests cannot prove broker connectivity, market-data entitlement, exchange acceptance, or execution safety.
PersonalTrader is an independent project. It is not affiliated with, endorsed by, or supported by Interactive Brokers. See the disclaimer.
- What PersonalTrader is
- What it does
- Modes
- Architecture and order flow
- Current status
- Requirements
- Build and run
- Use the local API
- IBKR Paper and Live boundaries
- Safety model
- Local data and privacy
- Development
- Repository guide
- Community and security
- License
PersonalTrader is a Windows desktop host for a React trading dashboard and a loopback HTTP API. It provides one place to view an account, create orders, follow broker-reported state, reconcile local history with IBKR, and expose the same trading operation to local tools without opening competing TWS API connections.
It is not a brokerage, an IBKR login replacement, a hosted service, or an autonomous trading strategy. Authentication, 2FA, account permissions, market-data subscriptions, and final order handling remain with TWS or IB Gateway and IBKR. PersonalTrader supplies the local workflow around that broker connection.
- Portfolio-first home page with cash by currency, positions, allocation, and unrealized profit and loss.
- Consumer order ticket with contract search, quotes, Market and Limit BUY/SELL actions, optional review, and plain-language results.
- Three isolated modes so Simulator and Paper evidence cannot authorize a Live order.
- One-click Paper order entry with optional review. Direct BUY or SELL journals the command and writes it to the TWS socket without creating a preview or waiting for app-level checks; the reviewed path remains available.
- Direct local IBKR bridge through the official TWS API; no hosted trading service or cloud database is required.
- Callback-aware order states for submitted, partially filled, filled, cancelled, rejected, ambiguous, and review-required outcomes.
- Shared order operation across the dashboard, cURL, Postman, and the typed client because they all use one PersonalTrader broker owner. The Orders page also recovers TWS orders owned by that configured client ID when local history is unavailable. Orders owned by a genuinely different TWS API client ID remain status-only because IBKR enforces client ownership.
- Reconciliation and readiness checks covering account identity, execution target, order IDs, open and completed orders, executions, positions, and local history.
- Fail-closed controls for stale Live quotes, connection loss, account mismatch, uncertain sends, duplicate submissions, and storage failures.
- Local evidence in a per-profile SQLite history and append-only NDJSON activity log.
- API-first access for the dashboard, cURL, and a typed .NET HTTP client through one loopback gateway and one broker-session owner.
| Mode | Broker connection | Funds | Submission behavior |
|---|---|---|---|
| Simulator | None | Deterministic local data | Exercises the order lifecycle without IBKR |
| IBKR Paper | TWS or IB Gateway Paper session | Simulated IBKR funds | Direct submission uses a serialized low-latency queue; reviewed submission remains optional |
| IBKR Live | Separately activated Live TWS or Gateway session | Real money | Requires a Live profile, exact activation phrase, current checks, fresh Live data, and Armed state |
Paper and Live are separate execution targets. They never share profiles, readiness receipts, broker order IDs, or local history. One IBKR Paper account uses one Paper Test profile: Direct submit and optional Review order are actions inside that profile, so both see the same TWS account data, callbacks, fills, positions, and order journal.
Browser dashboard cURL / Postman PersonalTrader.Client
└─────────────────────┼─────────────────────┘
▼
Launcher and public API gateway
http://127.0.0.1:5080
│
▼
Capability-protected child API :5081
REST / OpenAPI │ workflow │ SignalR callback updates
┌────┴───────────────┐
▼ ▼
Per-profile SQLite NDJSON evidence log
│
▼
IBrokerGateway abstraction
├── Fake broker ───────────────► Simulator
└── Official C# TWS adapter ───► TWS / IB Gateway ───► IBKR
The supported integration boundary is http://127.0.0.1:5080/api/v1/*. The browser uses a same-origin control token; local integrations use one generated X-API-Key. The API key never reaches the child process or TWS. Port 5081, its capability token, and its internal readiness headers are implementation details rather than a second public API.
| Component | Responsibility |
|---|---|
PersonalTrader.Web |
React and TypeScript dashboard, order ticket, portfolio, orders, settings, and checks |
PersonalTrader.Launcher |
Single desktop entry point, saved profiles, child-process lifecycle, local settings, API-key management, static UI, and reverse proxy |
PersonalTrader.Api |
Versioned REST endpoints, OpenAPI, authentication boundary, and SignalR events |
Application and Domain |
Request contracts, order lifecycle, policy, idempotency, and trading invariants |
Infrastructure |
SQLite persistence, NDJSON evidence, callback processing, reconciliation, synchronization, and broker-order-ID coordination |
Broker.Fake and Broker.IBKR |
Deterministic Simulator and the concrete official TWS API adapter |
PersonalTrader.Client |
Typed .NET client for the public loopback API; it does not open another TWS socket |
- The launcher listens only on
127.0.0.1:5080and serves the dashboard. - Starting a saved profile launches one child API on
127.0.0.1:5081with the exact execution target, account, broker host, port, client ID, local database, and private capability. - The child owns the one broker socket, current
nextValidIdsequence, workflow state, callback stream, and profile history. - The browser and local API clients send commands through port
5080, so they cannot compete for broker IDs or create separate views of the same session. - Stopping PersonalTrader closes the local session but does not cancel working orders at IBKR.
The speed-oriented Paper route intentionally omits app-level preview, quote/resource admission, check-run, Armed-state, and one-use-permit gates. It still performs the transport and evidence work needed for one controlled broker write:
- Authenticate the request and require a stable
Idempotency-Key. - Validate the execution target, exact
conId, and supported TWS wire values. - Admit the command to a bounded, serialized single-writer queue.
- Reserve a unique order ID from the current TWS session.
- Persist the exact intent and append the pre-send NDJSON evidence.
- Call
placeOrderonce. PersonalTrader never automatically retries an uncertain send.
- Create an immutable preview containing the exact order, broker quote evidence, estimates, warnings, expiry, and confirmation hash.
- Review the preview in the UI or through the API.
- Submit that exact preview with a new
Idempotency-Keyand its acknowledged warnings. - Revalidate the preview at the send boundary. Reviewed and Live paths apply their required readiness, account, quote, resource, and one-use authorization policy before reserving an order ID and writing once to TWS.
- Live adds a separately activated non-Paper profile, current checks, fresh executable-side market data, configured size/value limits, and an explicitly Armed session.
An HTTP 202 Accepted or a successful socket write means the local send completed; it does not prove that IBKR accepted, routed, filled, or cancelled the order. TWS callbacks are authoritative for submitted, partially filled, filled, cancelled, rejected, execution, commission, and error state. The broker event pump serializes and persists those callbacks, then publishes low-latency SignalR updates to the dashboard. HTTP polling and reconciliation recover state when a browser event is missed or a session reconnects.
Reconciliation compares the selected account, broker order-ID state, open and completed orders, executions, positions, balances, and local history. The dashboard, cURL, Postman, and the .NET client are interoperable because they share the same broker owner through port 5080. Orders created in TWS under the configured API client ID can be recovered and operated when local history is missing. Orders owned by another TWS API client ID can be shown account-wide, but IBKR keeps them status-only for PersonalTrader.
See the API and client-library architecture for the trust boundaries and endpoint design.
IBKR credentials and 2FA remain inside TWS or IB Gateway. PersonalTrader remembers local connection preferences but does not store the IBKR username, password, or 2FA response.
This repository is under active development and is not yet a signed or audited public release. The Windows package is produced locally under artifacts\win-x64 and is intentionally excluded from Git.
Implemented today:
- Windows launcher and local web dashboard
- Simulator, IBKR Paper, and guarded IBKR Live targets
- Official C# TWS API adapter
- Portfolio summary and reconciled positions
- Market and limit orders; Paper direct accepts positive fractional quantities and outside-RTH DAY requests, while reviewed and Live policy remains restricted
- Optional review and direct submission
- Loopback API-key access, generated OpenAPI, and a typed .NET HTTP client
- Order callbacks, cancellation, reconciliation, and emergency global cancel
- Per-profile SQLite history, NDJSON evidence, diagnostics, and automated tests
Known scope limits:
- Windows-first packaging
- Stocks and ETFs denominated in USD
- Paper direct orders are DAY orders; other time-in-force values are not supported
- Reviewed and Live orders remain whole-share and regular-hours only
- No options, futures, FX order entry, bracket orders, or algorithmic strategies
- No guarantee of market-data entitlement, broker availability, acceptance, or fills
To build the repository or create the Windows package:
- Windows 10 or 11
- .NET 10 SDK
- A currently supported Node.js release with npm (Node 20 or newer is recommended)
- The official TWS API C# assembly. The standard detected path is
C:\TWS API\source\CSharpClient\client\bin\Release\net8.0\CSharpAPI.dll; setIBKR_CSHARP_API_DLLwhen it is installed elsewhere
To run the framework-dependent package:
- Windows 10 or 11
- .NET 10 ASP.NET Core Runtime
For an IBKR Paper or Live session:
- Trader Workstation or IB Gateway
- An authenticated IBKR session with the appropriate account permissions and market-data entitlement
- Socket API enabled on the matching Paper or Live port
Clone the repository, verify the IBKR C# API assembly, and create the Windows package:
git clone https://github.com/github4me/live-trading.git
Set-Location live-trading
.\eng\verify-ibkr-api.ps1
.\eng\publish-win-x64.ps1The publish script installs the locked frontend dependencies, builds the React dashboard, and publishes the API and launcher. If the TWS API is installed elsewhere, point the build at its assembly first:
$env:IBKR_CSHARP_API_DLL = 'C:\path\to\CSharpAPI.dll'
.\eng\verify-ibkr-api.ps1 -ApiAssembly $env:IBKR_CSHARP_API_DLL
.\eng\publish-win-x64.ps1Then open artifacts\win-x64 and double-click PersonalTrader.Launcher.exe. The launcher opens http://127.0.0.1:5080; routine setup and use stay inside the UI.
For a first run:
- Choose Simulator.
- Start the default Simulator profile.
- Open Tests and run the safe checks and disposable scenarios.
- Build a small order using Review or direct BUY/SELL.
- Inspect its lifecycle in Orders.
Continue with the IBKR Windows setup guide only after Simulator is working. The guide moves from read-only connectivity to a supervised Paper order and finally describes the separate Live activation path.
For local integrations, start the intended profile in the dashboard and then open Settings → Developer access to copy the API key. The API and cURL guide covers direct and reviewed orders, idempotent retries, polling, and the .NET client.
Start the intended profile in the dashboard, open Settings → Developer access, and copy the generated key. Send it as X-API-Key to the public loopback API. Begin with a read-only status check:
curl.exe --fail-with-body http://127.0.0.1:5080/api/v1/system/status -H "X-API-Key: <API_KEY>"
Verify executionTarget and maskedAccountFingerprint before any order request. The generated OpenAPI document is available at http://127.0.0.1:5080/openapi/v1.json while a profile is running. API keys can use the active profile's trading endpoints but cannot start, edit, or delete profiles, open TWS, or bypass Live policy.
For exact contract search, direct Paper submission, reviewed submission, idempotent retry rules, order polling, cancellation, and .NET examples, follow the local API and cURL guide. Never create a new idempotency key merely because an earlier order response was lost or timed out.
The broker transport is:
PersonalTrader dashboard → local API → official TWS API socket → TWS or IB Gateway → IBKR
Default ports are TWS 7497 / Gateway 4002 for Paper and TWS 7496 / Gateway 4001 for Live. PersonalTrader cross-checks the configured target, account, host, port, client ID, and broker-reported account instead of inferring the environment from the port alone.
Paper direct submission does not use the app-level Armed switch, check run, quote/preview policy, cash/position admission policy, or one-use permit. It still requires an authenticated matching Paper TWS/Gateway socket, a valid contract and wire-valid order, an Idempotency-Key, durable intent and NDJSON writes, a unique TWS order ID, and available queue capacity. Live remains separate and guarded: it requires a non-DU profile, the exact phrase START LIVE TRADING, current checks, and Armed state.
Do not retry an uncertain submission. A socket write or HTTP response is not broker acceptance—the broker callbacks and later reconciliation are authoritative. Stopping PersonalTrader does not cancel working broker orders.
Key invariants shared by all submission paths include:
- Persist the exact intent before the first broker send.
- Reserve a unique broker order ID from the current broker session.
- Require an idempotency key and return the original intent for an exact replay.
- Serialize Paper direct socket writes through a bounded single-writer queue.
- Never retry an ambiguous send automatically.
- Treat broker callback persistence as financial state; storage failure blocks further submission.
- Keep the dashboard and APIs on loopback by default.
Reviewed and Live submission add immutable previews, policy checks, and one-use transmission permits. Live additionally requires a fresh ask for a Market buy or bid for a Market sell, account/resource admission, explicit arming, and fail-closed reconciliation behavior.
CANCEL ALL · ESC uses IBKR global cancel. Its scope can include TWS-entered orders and orders in linked accounts visible to the same TWS session. A returned request is not proof that every order was cancelled; verify callbacks and reconciliation.
There is no database server to configure. Each saved profile automatically gets a separate local history file:
%LOCALAPPDATA%\PersonalTrader\data\<profile-id>.<generation>.sqlite
Order and callback evidence is also written under %LOCALAPPDATA%\PersonalTrader\logs. The current fresh-build schema is intentionally not migrated from incompatible local histories. PersonalTrader reuses an existing compatible generation so its orders remain visible; otherwise it creates a new generated filename automatically and preserves the older file. The user does not need to recreate the saved profile. You do not need a new database for every test—each saved profile owns one automatically managed database. Settings, account data, local databases, logs, and generated packages are excluded from Git. Read PRIVACY.md before sharing diagnostics or local data files.
Run the release-oriented checks with the concrete IBKR adapter:
dotnet build PersonalTrader.sln --configuration Release -p:RequireIbkrTwsApi=true
dotnet test PersonalTrader.sln --configuration Release -p:RequireIbkrTwsApi=true
npm --prefix src/PersonalTrader.Web test
npm --prefix src/PersonalTrader.Web run buildAutomated tests exercise local policy, persistence, callbacks, idempotency, failure handling, and UI behavior. They must never place a Live order as a software test.
| Path | Purpose |
|---|---|
src/PersonalTrader.Web |
React and TypeScript consumer dashboard |
src/PersonalTrader.Launcher |
Windows launcher, profile controls, diagnostics, and local reverse proxy |
src/PersonalTrader.Api |
Local HTTP API and trading endpoints |
src/PersonalTrader.Client |
Typed .NET HTTP client for the loopback API |
src/PersonalTrader.Application |
Trading workflow, policy, and contracts |
src/PersonalTrader.Broker.IBKR |
Official TWS API adapter and callback handling |
src/PersonalTrader.Broker.Fake |
Deterministic Simulator broker |
src/PersonalTrader.Infrastructure |
Persistence, synchronization, runtime state, and activity logging |
tests/PersonalTrader.Domain.Tests |
Backend, policy, adapter, persistence, and failure-path tests |
docs |
Architecture, operations, safety lessons, and public-release guidance |
Useful reading:
- Changelog
- IBKR setup and staged validation
- Consumer test and trading runbook
- Local history architecture
- API and client-library architecture
- Local API, cURL, and .NET client guide
- Engineering lessons and invariants
- Read CONTRIBUTING.md before proposing a change.
- Use SUPPORT.md to decide whether to open a question, bug, or feature request.
- Report vulnerabilities privately as described in SECURITY.md.
- Participation is governed by CODE_OF_CONDUCT.md.
No public license has been selected yet. Until the repository owner adds a LICENSE file, the source is publicly viewable if published but no permission to copy, modify, or redistribute it is granted. The public release checklist records this as a required owner decision.