8 Commits
Author SHA1 Message Date
Brandon LiandClaude Opus 5 4288d8c298 Auto-start both processes at logon and self-update from master
Instances were started by hand and updated by hand, so they drifted behind
master silently. Now: PM2 supervises the dashboard and the clicker, a logon
task brings them up, and a 5-minute task pulls, rebuilds and restarts when
master moves.

Restarting on every push is only safe because the scheduler now survives it.
It was pure in-memory state (_global.__autoTrader), so any restart silently
stopped automated trading with the dashboard simply showing it as off. It now
mirrors running/action/symbol/stopAfterAll to the settings table, and
resumeSchedulerIfPersisted() picks it back up from the getClients() bootstrap.
No sync-wait was needed there: tick() already skips while a client reports
!syncComplete and while any account holds a position.

A failed build is never deployed — the build runs before anything restarts, so
a broken push leaves the previous build serving.

start-all and update-check both warm the app with a request afterwards. That is
load-bearing: getClients() is lazily bootstrapped, so until something makes an
HTTP request the Tradovate clients, the reporter and the resumed schedule never
start. That was already true of manual restarts.

Logic lives in Node so a macOS or Linux port only needs an equivalent of
install-autostart.ps1. Python deps are hash-guarded, so the common path is one
hash and one import with no network, and failure is non-fatal since only the
clicker needs them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 17:36:25 -05:00
Brandon LiandClaude Opus 5 fc08a41c4b Fix seven type errors that broke next build
`npm run build` failed on a clean checkout, so nothing on master could be
built for production. `npm run dev` does not hard-fail on type errors, which
is why it went unnoticed.

- state route returned client.perContractFees, which has never existed on
  TradovateClient on any branch; nothing consumed it
- mapFirmConfig omitted bannedSymbols. Type gap only: the trade path calls
  isSymbolBanned() against the DB directly, so bans were always enforced
- initClient's sync callback was sync where the constructor wants
  () => Promise<void>
- accessInfo and ws are assigned during async connect/auth, never in the
  constructor, so they take definite-assignment assertions
- the socket payload's inline entityType union had drifted five members
  behind the indirect-callback union above it, making the 'position' and
  'cashBalance' branches unreachable to the compiler. Both now share a
  TradovateEntityType alias. Type-only: those handlers ran fine at runtime

Behaviour is unchanged throughout.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 16:16:06 -05:00
Brandon LiandClaude Opus 4.6 4025ed2f41 Fix contract resolver: use Yahoo continuous contract price matching
Replace volume-based contract selection with Yahoo Finance continuous
contract price matching ({PRODUCT}=F). The old approach compared volumes
across front/roll candidates, which failed when serial months had
deceptive volume (6EJ26 > 6EM26) or Yahoo was rate-limited (all 0s).

Now fetches the continuous contract price and matches it against
candidates within 0.1% tolerance. Falls back to roll1 if Yahoo fails.
Also adds User-Agent header to avoid 429 rate limiting.

Verified: GC=F price matches GCM26, 6E=F price matches 6EM26.

Also fixes stale 'Random' comment in auto-trade.ts and cleans up
frontVolume/rolledVolume references from settings page.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 18:19:51 -05:00
SenofyandClaude Opus 4.6 f112118090 Add master dashboard reporter and settings UI
- New reporter module that pushes firm stats (total accounts, accounts
  traded, in trade) to a configurable master dashboard every 30 seconds
- Add Instance Name and Dashboard URL fields to the settings page
- Register master_dashboard_url and instance_name in settings API
- Seed default (empty) values for new settings in db

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:01:48 -05:00
SenofyandClaude Sonnet 4.6 d945e0038f Add volume-based contract auto-resolver and CLAUDE.md
- New lib/contract-resolver.ts: picks the best contract month for each
  symbol by comparing Yahoo Finance volume between the front month
  (Tradovate suggest API) and the roll target (rollcontract API)
- lib/clients.ts: auto-resolves all enabled instruments 15s after startup
  and again daily at midnight via a setInterval check
- lib/tradovate-class.ts: findFrontMonthContract checks resolver cache
  first before falling back to the suggest API
- app/api/instruments/contracts/route.ts: GET returns cached contracts,
  POST triggers a fresh resolve
- app/settings/page.tsx: shows active contract + rolled badge per symbol;
  auto-resolves on load if cache is empty; removed manual Resolve button
- app/api/debug/route.ts: include entity data in recentEntityEvents
- CLAUDE.md: instructs Claude to always work on main

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 03:17:09 -05:00
SenofyandClaude Sonnet 4.6 b2a1bdd1c3 Add auto-trade scheduler with batch locking, commission gross-up, and sync gate
- 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>
2026-03-09 03:31:47 -05:00
SenofyandClaude Sonnet 4.6 dd18f91584 Add full Next.js autotrader app with SQLite persistence and live Tradovate data
- 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>
2026-03-08 15:03:21 -05:00
Senofy a9b6acd479 Initial Commit 2026-03-07 22:07:02 -06:00