- lib/instrument-specs.ts (pure, tested): the CME specs — point value,
tick size, one-tick spread, Yahoo ticker — replacing POINT_VALUES; the
draw's maths; the 12-hour hold cap; the micro for drain and extra-day
legs; reading a firm's list (the master's, or the old rules against an
older master: this machine's enabled set less bans, the symbol map).
- lib/instruments.ts: the one module the trading paths ask. Measures every
future's daily move from Yahoo's hourly candles once per trade date, and
shows entry cost (a tick of spread plus Tradovate's fee parameters or
TopstepX's last measured fill) without ever choosing by it.
- Futures Auto draws one root per batch from the batch firm's list: movement
per dollar of spread early in the session with a 10% floor each, sliding
to the fastest movers by the last entry; nothing expected to hold 12h or
more; micros only if nothing else is listed. Every draw logs its odds.
- The batch is chosen before its instrument, and a group that can't trade
anything yields to the next. Copy trade matches the held contract against
the listed roots and won't copy an instrument it can't identify. Manual
legs, manual orders and drain/extra-day legs follow the lists.
- DXtrade firms rank their own list whatever root was drawn.
- Capabilities, the dashboard's trade bar and contract resolves follow the
lists; the trade bar and scheduler default to Auto. The master link
reconnects when master_dashboard_url changes, and the catalog drops
?since after a switch so two masters' versions can't collide.
- Reports carry each futures firm's instrumentStats for the master's Firms
page; GET /api/instruments shows them (?simulate=N runs the draw, no
orders); the Settings page shows the lists read-only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
- Add withdrawal stage system: each stage defines profit target, consistency,
and min trading days for post-withdrawal challenge cycles
- Target Same Equity mode accounts for withdrawn amounts when computing
effective profit target (profitTarget - remainingProfit)
- Store fund transaction timestamps for time-aware cycle filtering
(withdrawals before 9 AM CT include that day in new cycle)
- Expose full P&L history (fullDailyPnL) for calendar/equity curve display
across all cycles, with DB fallback for pre-restart data
- Show stage number (#1, #2, etc.) on calendar cells
- Hide consistency reference line when consistency is 0% or 100%
- Settings UI: "After First W/D" column with same-equity checkbox,
expandable stage sub-rows with profit/consistency/days inputs
- Default target_same_equity to 1 for new and existing account configs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DB migration: ALTER TABLE account_configs ADD COLUMN max_position_size INTEGER NOT NULL DEFAULT 0
- Added max_position_size to AccountConfigRow, createAccountConfig, updateAccountConfig in lib/db.ts
- Added maxPositionSize to AccountConfig type in types.ts (0 = no limit)
- GET /api/firms/[id] now returns maxPositionSize per account
- POST /api/firms/[id]/accounts and PUT /api/account-configs/[id] accept maxPositionSize
- Firm settings page: new Max Contracts column (blank = no limit)
- auto-trade: contracts capped at maxPositionSize when > 0
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>