This box no longer decides what firms exist. It caches the master's catalog
and stores one thing of its own: the Tradovate login for each firm. Creating
firms locally is gone — app/add, POST /api/firms, the account-config routes
and the banned-symbol route with it.
The cache is the point, not an optimisation. The scheduler needs every
account's target and size on each 60s tick, so fetching them per tick would
stop trading with positions open the first time the master rebooted. It is
one JSON blob in settings, replaced only by a complete valid response, and a
response with zero firms is refused outright: a misconfigured FIRMS_DB serves
{"firms":[]} as a healthy 200, and mirroring that would idle the whole fleet
at once.
Accounts bind to an account type by prefix AND size, the size taken from the
opening funding transaction. That does not arrive with the first sync, so an
account sits Unassigned and the resolver tries again next sync rather than
guessing. A type picked by hand is never overwritten by an auto pass. This
replaces the longest-prefix helper that had been copy-pasted into five files,
which could not tell two types with the same prefix apart at all.
firm_credentials and account_assignments deliberately have no foreign key to
the cached catalog. foreign_keys is ON, so a cascade would erase the Tradovate
passwords the moment a firm was removed on the master — routine, not
exceptional. They survive it, and are re-keyed by name if the master's database
is ever rebuilt with fresh ids.
The legacy firms/account_configs/firm_banned_symbols tables are left on disk,
unreferenced. firms is the only table that ever held plaintext credentials and
dropping it would make a rollback unrecoverable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Stage 1 = bg-slate-100 (matches Flat status pill), each subsequent stage
gets a deeper blue. Shared helper in lib/stage-colors.ts used by both
the main dashboard and the account detail page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
State API now returns stage = 1 + number of withdrawals. Both the main
dashboard and the account detail page show a small Stage N pill next to
the profit target value.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
State API now returns effectiveProfitTarget = max(stage profit target,
maxDay/consistency). When a big day forces the consistency rule, this
reflects the actual amount needed to complete the stage — not just the
base profit target.
Main dashboard and account detail page now display this instead of the
raw cfg.profitTarget.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bug fixes:
- Fix computeDailyTarget when consistency is 0% or 100%: treat as no constraint,
letting min-day reservation or full remaining profit drive the target
- Rename 'Random' to 'Auto' across entire codebase (types, API, UI, scheduler)
Features:
- Add "Stop after all eligible" checkbox: auto-stops scheduler when all
configured accounts are dead, inactive, already traded, or challenge complete
- Show position direction in status pill: "Long" (green) / "Short" (red)
instead of generic "In Trade" (blue)
- Add "Copy to Max" button: copies current trade direction to remaining
eligible accounts up to max_concurrent_accounts limit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Display "Auto" instead of "Random" for symbol/action selectors
- Last withdrawal stage always shows "+" suffix (even with one stage)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Displays the server-computed dailyTarget.amount as a secondary line
"$X today" under the profit target in the Target column.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Seed tick_interval_seconds setting (default 60s)
- Expose tick_interval_seconds via GET/PATCH /api/settings
- startScheduler reads the setting at start time; enforces 5s minimum
- getSchedulerStatus returns intervalSeconds for the UI
- Main page: "Every [__] s" input in idle bar — saves on blur, persists across
restarts; running state displays "every Ns" next to symbol/action
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Symbol dropdown now includes a "Random" option alongside enabled instruments
- runTrade resolves 'Random' to a random enabled instrument once per batch,
so all accounts in the same tick trade the same symbol
- Import getInstruments in auto-trade.ts to support the resolution
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- lib/db.ts: new firm_banned_symbols table with getBannedSymbols,
isSymbolBanned, and setBannedSymbol helpers
- app/api/firms/[id]/banned-symbols/route.ts: GET lists banned symbols,
PATCH toggles a ban for a given symbol
- app/api/firms/route.ts: include bannedSymbols[] in firm list response
- app/firms/[id]/settings/page.tsx: Instruments section shows all
globally-enabled symbols with a red toggle to ban/unban; banned
symbols display a "SYMBOL BANNED" pill next to their name
- app/page.tsx: FirmRows shows "ES BANNED" (or current symbol) pill next
to the firm name when the selected trade symbol is banned for that firm
- lib/auto-trade.ts: skip firms entirely when the trade symbol is banned
- types.ts: add bannedSymbols field to FirmConfig
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All accounts in the same batch trade the same resolved direction.
Each new batch (after positions are flat) picks a fresh random direction.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Privacy button: masks account names beyond the first 5 chars with bullets;
eye/eye-off icon toggles the mode in the header toolbar
- computeDailyTarget: accepts minDayPnL + minTradingDays params; when a
positive min floor is set and mandatory days remain, reserves future-day
profit so each day hits the floor (cap = remaining - futureReserve, floor
= minDayPnL); returns effectiveMinDay directly once profit target is met
but days are not yet satisfied
- auto-trade: passes minDayPnL/minTradingDays to computeDailyTarget; for
zero-floor accounts that have met the profit target but still owe trading
days, trades 1 MNQ in-and-out at market (extra-day mode) and bypasses the
normal target=0 skip gate via isMnqExtraDay flag
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Auto-trade scheduler fires every 60s; uses Promise.allSettled batch so no new trades fire while any position from the current batch is open
- Commission gross-up: read entryCommission from cash.realizedPnL after fill (fallback 2.5×contracts), grossTarget = target + 2×entryCommission
- Sync gate: TradovateClient.syncComplete flag; scheduler skips tick until every client finishes initial position/balance sync
- Contracts formula changed to Math.ceil so $1500 target = 2 contracts
- Removed all fee caching (perContractFees, recentFills, fillFee handler) from tradovate-class.ts
- Removed firm_fees table, getFirmFees, upsertFirmFee from db.ts
- Deleted instrument-configs API routes; removed Fees UI from firm settings page
- /api/instruments returns full {symbol, enabled}[] objects; dashboard filters to enabled-only for trade selector
- Added auto-trade, debug, orders, settings, and trade API routes
- Instrument selector on dashboard now driven by enabled instruments from DB
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- SQLite DB (better-sqlite3) with firms, account_configs, firm_fees, instruments tables
- REST API routes: firms CRUD, account configs CRUD, state, accounts, instruments
- Live Tradovate WebSocket client: login, sync, positions, auto-liq thresholds
- Dashboard (app/page.tsx): per-firm account list with balance, day P&L, days traded,
target progress, and Dead/Inactive/Flat status based on Tradovate auto-liq floors
- Account detail page: objectives progress, daily P&L chart, consistency tracking
- Per-firm settings page: account configs and instrument fee management
- Dead detection uses trailingMaxDrawdownLimit - trailingMaxDrawdown from
userAccountAutoLiqs; filters Tradovate sentinel value (999999999 = no limit)
- FIFO P&L engine with commission accounting for daily P&L history
- Removed manual maxLoss fallback in favour of live Tradovate auto-liq data
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>