Open-source trading infrastructure for running LLM-assisted strategies with deterministic risk enforcement, provider-truth reconciliation, and a typed Convex control plane.
The repository contains the reusable runtime, venue adapters, dashboard, agent tooling, and operational scripts. Live strategies, private rollout plans, broker files, credentials, and deployment notes belong in the ignored private/ overlay.
apps/backend: TypeScript scheduler, strategy orchestration, provider sync, agent runtime, and backend health serverapps/dashboard: Next.js operator dashboard backed by Convexpackages/core: shared types, strategy config parsing, risk gates, accounting helpers, and runtime utilitiespackages/agent: tool contracts, MCP integration, transcript handling, and model provider adapterspackages/convex: schema, queries, mutations, generated API bindings, and backend client helperspackages/alpaca-options,packages/mt5,packages/okx,packages/polymarket: venue-specific clients, adapters, risk rules, and payload mapping
Agents propose intents. Deterministic code owns execution permission, risk validation, account ownership, order lifecycle, accounting, kill switches, provider identity checks, persistence, and reconciliation.
Provider truth remains authoritative for live account state, positions, orders, fills, and reconciliation evidence. Fallbacks must be explicit, logged, bounded, and fail closed for execution, ownership, accounting, credentials, and provider identity.
This repo ignores private/ by default. Use it for operator-local files:
private/strategies.md: account pool and strategy source of truthprivate/plan.md: local rollout and audit planprivate/context.md: private operational context- deployment notes, runbooks, and one-off maintenance scripts tied to your own accounts
Do not commit credentials, broker files, deployment secrets, private strategy prompts, or audit exports.
Install dependencies with Bun:
bun installStart Convex locally when developing Convex functions:
cd packages/convex
bunx convex devStart the backend and dashboard in development:
bun run devRun the main checks:
bun run build
bun run testBackend runtime env:
CONVEX_URLBACKEND_SERVICE_TOKENHEALTH_PORTOPENROUTER_API_KEYfor local fallback when it is not resolved from ConvexMCP_PROVIDER_CONFIGS, orMCP_SERVER_URL/MCP_SERVER_TOKEN/MCP_SERVER_ALLOWED_TOOLS
Dashboard runtime env:
NEXT_PUBLIC_CONVEX_URLBACKEND_URLBACKEND_SERVICE_TOKEN
Convex env must also include BACKEND_SERVICE_TOKEN. Generate machine credentials with high-entropy random values:
openssl rand -hex 32Use distinct values for each machine-auth boundary.
After auth is deployed, create the initial dashboard user from the Convex dashboard Functions page by running seedUserAction:seedUser:
{
"email": "you@example.com",
"password": "your-plain-text-password"
}Accounts are declared in private/strategies.md with a credentialEnvPrefix. Provider secrets are resolved from Convex env vars by combining that prefix with each canonical provider key suffix.
For example, an account with credentialEnvPrefix set to OKX_GPT55_LOW resolves OKX_API_KEY from OKX_GPT55_LOW_API_KEY.
Canonical provider keys:
| App | Keys |
|---|---|
mt5 |
MT5_LOGIN, MT5_PASSWORD, MT5_SERVER, FIVESOCKET_API_KEY, FIVESOCKET_API_BASE_URL, FIVESOCKET_DEFAULT_MAX_VOLUME |
alpaca-options |
ALPACA_API_KEY, ALPACA_SECRET_KEY, ALPACA_ENVIRONMENT, ALPACA_ACCOUNT_ID |
okx-swap |
OKX_API_KEY, OKX_API_SECRET, OKX_API_PASSPHRASE, OKX_BASE_URL, OKX_DEMO_TRADING, OKX_MARGIN_MODE, OKX_POSITION_MODE |
polymarket |
POLYMARKET_PRIVATE_KEY, POLYMARKET_API_KEY, POLYMARKET_API_SECRET, POLYMARKET_API_PASSPHRASE, POLYMARKET_HOST, POLYMARKET_CHAIN_ID, POLYMARKET_FUNDER_ADDRESS |
MT5 connectivity is FiveSocket-only. The Windows worker transport was removed; rollback is via git history, not runtime config.
OKX_DEMO_TRADING must be set explicitly to true or false. OKX_MARGIN_MODE must be cross or isolated. OKX_POSITION_MODE must be net_mode or long_short_mode.
FiveSocket is the MT5 connectivity path for this runtime. Strategy logic, MT5VenueAdapter recovery semantics, and the execution pipeline stay the same; MT5Client construction always creates a FiveSocket client.
Set:
MT5_PRIMARY_LOGIN=
MT5_PRIMARY_PASSWORD=
MT5_PRIMARY_SERVER=
FIVESOCKET_API_KEY=
FIVESOCKET_API_BASE_URL=https://api.fivesocket.com
FIVESOCKET_DEFAULT_MAX_VOLUME=FIVESOCKET_API_KEY and FIVESOCKET_DEFAULT_MAX_VOLUME are required. FIVESOCKET_API_BASE_URL defaults to https://api.fivesocket.com when unset. FIVESOCKET_DEFAULT_MAX_VOLUME is the explicit per-symbol execution-policy max volume (plain positive decimal string). There is no silent volume default.
Account credentials use each account's credentialEnvPrefix: an account with MT5_SECONDARY resolves canonical MT5_LOGIN / MT5_PASSWORD / MT5_SERVER from MT5_SECONDARY_LOGIN / MT5_SECONDARY_PASSWORD / MT5_SECONDARY_SERVER. The OpenAPI contract checked into docs/fivesocket-openapi.json is authoritative for request/response shapes.
Mutation outcomes map into the existing MT5 result model:
accepted/rejectedreturn normalMT5OrderResultvaluescommit_unknownis polled briefly, then surfaced as a retryable commit-unknown error so adapter recovery bycomment/clientOrderIdcan rununresolvedis a terminalMT5OrderResult.unresolvedresult mapped toNEEDS_MANUAL_RECONCILIATION(do not retry the mutation)
POLYMARKET_FUNDER_ADDRESS is required and must be set explicitly. The runtime does not derive it from the private key and does not fall back to another wallet address.
Operator workflow:
- Run
bun run packages/polymarket/src/derive-api-key.ts <private-key>to derive L2 API credentials from the signer key exported for Polymarket. By default, this writesprivate/polymarket-credentials.envwith restrictive file permissions. - Copy
POLYMARKET_API_KEY,POLYMARKET_API_SECRET,POLYMARKET_API_PASSPHRASE, andPOLYMARKET_PRIVATE_KEYinto the account-scoped Convex env vars. - In Polymarket, copy the profile or proxy wallet address shown in the account UI and set that exact value as the account-scoped
POLYMARKET_FUNDER_ADDRESS. - Open Dashboard > Test > Polymarket and verify both the runtime config and authenticated runtime path before enabling scheduled runs.
Keep the strategy document in private/strategies.md. It contains both the account pool and strategies.
| Command | Description |
|---|---|
bun run strategies:diff |
Compare the strategy document against backend state |
bun run strategies:list |
List all strategies in backend with IDs |
bun run strategies:add --name="..." |
Add one strategy from the strategy document |
bun run strategies:add-all |
Add all strategies from the strategy document without deleting existing history |
bun run strategies:delete --name="..." |
Delete one strategy by name and cascade related data |
bun run strategies:delete --id=<id> |
Delete one strategy by Convex ID |
bun run strategies:reset |
Delete all strategies and associated data |
bun run strategies:reset-import |
Delete everything and re-import the strategy document |
bun run provider:identity-preflight |
Refresh and inspect provider identity, freshness, exposure, and active orders |
Examples:
bun run strategies:diff
bun run strategies:add --name="Example Strategy"
bun run provider:identity-preflight -- --app=mt5Force resets are safety-critical. Confirm zero open provider exposure, refresh provider truth through the same scheduled credential path, then run the reset/import command only when the provider-sync evidence is clean.
Dashboard /chat is a global owner chat with the trading agent. It does not require a configured strategy, does not accept strategyId, and does not call scheduled strategy execution. The dashboard API route authenticates the Convex dashboard user first, then proxies the bounded chat request to backend /agent-chat with BACKEND_SERVICE_TOKEN.
The browser sends only the user message, selected modelProvider and modelId, plus optional chat/session metadata. It must not send raw UI message history or tool outputs as trusted execution state.
Backend /agent-chat:
- resolves the selected provider server-side: OpenRouter uses
OPENROUTER_API_KEYfrom Convex-resolved secrets or local backend env, and Codex uses the existing dashboard-managed ChatGPT login with the app-server provider - reports provider availability to the dashboard so Codex can render a bounded model dropdown and OpenRouter can render a free-text model id input
- surfaces OpenRouter model-not-found failures as explicit model selection errors
- persists a trusted server-side transcript for user prompts, assistant responses, tool inputs, tool results, tool errors, and cancelled turns
- reloads follow-up prompts from completed server transcript records
- streams AI SDK UI message parts directly to the dashboard
- aborts provider streaming and tool execution when generation is stopped
Chat tools are separate from scheduled strategy runtime. The current chat registry exposes read-only operational, account, portfolio, run, alert, provider-health, and explicitly configured MCP tools. Execution-capable manual trading tools are intentionally not exposed until a chat-specific typed execution path preserves adapter identity, Convex persistence, deterministic accounting, safety fault recording, and provider-truth reconciliation.
MCP exposure fails closed. Each MCP provider must explicitly allow upstream read-only tool names through allowedTools in MCP_PROVIDER_CONFIGS, or through comma-separated MCP_SERVER_ALLOWED_TOOLS for the single MCP_SERVER_URL provider. Tools annotated by the provider as destructive or open-world are blocked even when named in the allowlist. A failing MCP provider is marked unavailable in chat inventory while local read tools remain available.
Codex strategies use the Codex app-server provider. OpenRouter strategies require OPENROUTER_API_KEY; Codex ChatGPT strategies require an active dashboard-managed ChatGPT login. Missing credentials fail closed before a scheduled strategy run starts.
Codex strategies must use canonical policy shape:
{
"dryRun": true,
"llm": {
"provider": "codex",
"model": "your-codex-model",
"authMode": "chatgpt"
}
}Scheduled Codex strategies must use authMode = "chatgpt". Open Dashboard > Integrations > Codex ChatGPT Login and start the device-code login flow. The backend runs codex login --device-auth against the persisted CODEX_HOME, writes the Codex CLI-compatible auth.json, and scheduled Codex app-server runs read that same login.
Persist CODEX_HOME for backend containers. If it is unset, the backend uses $HOME/.codex. Do not store ChatGPT OAuth cache files, access tokens, or API keys in Convex strategy config or logs.
Run the same app-server and MCP path used by scheduled dry-run strategies before enabling any Codex strategy:
bun run codex:preflight -- --strategy <strategy-id> --dry-run-onlyStored-strategy preflight uses the scheduler provider gate and resolved Convex secrets. It fails closed if the strategy is not dry-run, is not configured for Codex, or lacks the active Codex ChatGPT login.
The Codex app-server path disables inherited apps, plugins, browser/computer/image/multi-agent/workspace tools, shell/unified exec, and web search for strategy runs. Preflight must show only the run-scoped MCP server starting. If any non-run MCP server starts, the run is interrupted and fails closed.
For a synthetic local smoke check that does not load a stored strategy, pass the model and auth mode directly:
bun run codex:preflight -- --model=your-codex-model --auth-mode=chatgptAfter a stored Codex dry-run completes, export audit evidence before enabling rollout:
bun run codex:run-audit -- --strategy <strategy-id>The command writes private/audits/codex-run-audit-<run-id>.json by default and fails closed if provider identity, run/evidence linkage, shared tool logs, canonical strategy tool names, forbidden Codex tool absence, dry-run ledger source run, canonical dry-run accounting state, or provider-sync health cannot be proven. Provider-sync evidence must be healthy, no-drift, and verified at or after the audited run ended.
After at least three scheduled Codex dry-runs complete, export rollout evidence before enabling dashboard creation:
bun run codex:rollout-audit -- --strategy <strategy-id>The rollout audit writes private/audits/codex-rollout-audit-<strategy-id>.json by default and fails closed unless the scheduled dry-run evidence is complete, live Codex strategies remain blocked, run audits pass, summaries/tool logs/accounting diagnostics are comparable, and every enabled non-Codex strategy has post-rollout evidence without provider leakage.
Live Codex execution remains blocked until replay, export audit, and provider-sync evidence has been produced for the intended venue path.
- Dashboard users authenticate with Convex Auth
- Backend machine traffic uses
BACKEND_SERVICE_TOKENfor machine-only Convex actions such as secret resolution - Kill switches live in Convex and are enforced by the backend runtime
Rotate machine secrets by generating a new value, updating the target service first, then updating the caller, and redeploying both ends so there is no mismatch window.
Deployment-specific scripts and secrets belong in private/. The local private deploy script, when configured, can deploy selected surfaces:
bun private/deploy.ts --only=convex,vercel,mt5After deployment, verify the same runtime paths used in production:
bun run strategies:diff
bun run provider:identity-preflightFor MT5, run the dashboard connection test for the target account and confirm FiveSocket health, execution connect, and provider-sync evidence are clean before enabling scheduled runs.
- Bun
- TypeScript
- Turborepo
- Convex
- Next.js
- Vercel AI SDK
This repository is intended to publish reusable platform code. Operator-specific strategies, plans, secrets, broker files, deployment details, and production audit artifacts should remain outside version control in private/.