Overview
v2.1 adds a new operator console to the dashboard and makes the engine more reliable under real conditions: late candles, hung sockets, parallel tool calls and races between the watcher and the model. The model now runs on Claude Opus 5.5 at xhigh effort, and every cycle records its turns, duration, cost and token usage.
Trading is still simulated. Market data is live from CoinSwitch, but no order reaches the exchange.
Live dashboard → https://bitnerve.arjunkrishna.dev
What's new
Operator console
- New pages: Deck (live book, equity, P&L attribution, watcher feed), Record (book and round trips), Replay (per-cycle outcome bars) and Model (per-cycle run table with session tiles)
- Forensic modals: a round-trip autopsy with fee ledger, exit attribution and hold-time outcome, and a full cycle replay
- Live polling with a header refresh control, a ladder strip showing each position's exit levels, and a risk budget and margin allocation view
- A new
/api/v2read-only data layer with a unioned exit timeline - Times are stored in UTC and shown in IST on the dashboard
Cycle telemetry
- Each cycle runs
claude -pwith JSON output and records turns, duration, cost and token usage on its invocation - The cycle passes its invocation id to the MCP server instead of adopting the latest open one
- Model:
claude-opus-5-5at--effort xhigh
Engine and watcher hardening
- Exit levels only fire on bars that start after the level was armed. The watcher can still act on late 1-minute bars, and it logs feed lag
- Levels fill and are checked at a fresh ticker price
- Model trims no longer re-arm the stop, and a rung that closes the whole position is handled cleanly
- Each position's exit fills, rung changes, stop moves and exit events run in one transaction, so a failure rolls back and no longer blocks other positions
create_positionchecks the cut and arms the ladder inside its transaction.adjust_positionapplies add, stop and cut together, under the account lock, so it can't race the watcher- Stop and cut moves that would widen risk are rejected
- Exchange requests time out after 8s (server-time calls after 3s), so a hung socket can't freeze the watcher or a tool call
- Tool calls append to the invocation log inside Postgres, so parallel calls no longer overwrite each other
- The brief flags late or stale 15-minute candles against the board and lists late exits
Symbols in the database
- Traded symbols move from
symbols.jsonto asymbolstable. A migration seeds the basket: ZEC, ENA, PEPE, STRK, WLD, XRP bun run symbols:syncrefreshes exchange constraints.bun run symbols:sync ZECUSDT ENAUSDT ...replaces the basket and keeps any symbol with an open position
Build
- Bun workspace:
bun installfrom the repo root installs everything, and the dashboard now runs on Bun too - The schema is defined once in
packages/dbas@bitnerve/dband shared by the server and the dashboard.schema:syncis gone - Docker images build from the repo root:
docker build -f server/Dockerfile . - The dashboard uses a 10-connection pool on Node and one connection per request on Workers
Upgrading from v2.0.0
- Run
bun installfrom the repo root (this replaces the separate server and client installs). - In
server/, runbun run db:migrate. This applies three migrations:0008: cycle telemetry columns onagent_invocations0009: converts every timestamp column totimestamptz, reading existing values as UTC0010: creates thesymbolstable and seeds the basket
- If you kept a custom
symbols.json, re-create that basket withbun run symbols:sync <SYMBOLS...>. - Update
TRADING_MODELinserver/.envtoclaude-opus-5-5.
Full changelog: v2.0.0...v2.1.0