33 Commits
Author SHA1 Message Date
SenofyandClaude Opus 4.6 f498594b16 Add configurable trading hours setting
Dropdown on settings page with two options:
- Full CME (5:00 PM – 3:00 PM CT) with 5 min buffer
- Equity Hours (8:30 AM – 3:00 PM CT) with 5 min buffer
Setting is read live each tick, no restart needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 19:57:48 -05:00
SenofyandClaude Opus 4.6 11144612c7 Block trading after 3 PM Central instead of 4 PM
Gives a full hour buffer before the CME daily halt at 4 PM.
No-trade window is now 3:00 PM – 5:00 PM Central (Mon–Thu),
and after 3:00 PM on Fridays.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 14:49:49 -05:00
SenofyandClaude Opus 4.6 c99f6843a7 Fix contract resolver: prefer rolled contract on equal volume
Changes > to >= so when both contracts have 0 volume (e.g. off-hours),
the further-out standard month wins. Fixes SI resolving to SIJ (April,
non-standard) instead of SIK (May, standard delivery month).

Also fixes SI/SIL prefix collision by requiring month+digit after symbol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 03:39:11 -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 15ef2d7adc Auto-reconnect on WebSocket disconnect
- Extract connection logic into connectAndAuth() so it can be called
  on both initial connect and reconnect
- Add ws.onclose handler: if not an intentional disconnect, clear stale
  intervals and retry connectAndAuth() after 5 seconds
- Track sync, heartbeat, and tokenRenewal interval handles so they are
  cleared and recreated cleanly on each reconnect
- Reset syncComplete = false on reconnect so the scheduler waits for
  a fresh sync before trading
- disconnect() sets intentionalDisconnect = true and clears all intervals
  to prevent reconnect loops when a client is removed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 23:21:03 -05:00
SenofyandClaude Sonnet 4.6 d0065ab047 Refresh dailyPnL on a fixed hourly interval instead of throttling
- Replace the reactive throttle with a proactive setInterval in requestSync
  that fires fetchDaysTraded exactly once per hour per client
- Remove post-fill fetchDaysTraded calls from auto-trade.ts — no longer
  needed and were causing bursts of report API requests on simultaneous fills
- Guard against duplicate intervals if requestSync fires more than once

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 20:41:56 -05:00
SenofyandClaude Sonnet 4.6 92b929f4ce Throttle fetchDaysTraded to once per hour per client
Multiple simultaneous fills were triggering concurrent report API calls
to Tradovate for every account in the firm, causing rate limiting.
Added a 1-hour cooldown — the first call always runs (lastDaysFetch=0),
subsequent calls within the same hour are no-ops.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 20:40:17 -05:00
SenofyandClaude Sonnet 4.6 1e1b837cf3 Show daily target below profit target in accounts table
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>
2026-03-12 12:59:50 -05:00
SenofyandClaude Sonnet 4.6 b7952a83ef Fix 400 error when starting scheduler with Random symbol
Skip POINT_VALUES validation for 'Random' — the symbol is resolved
to a real instrument inside runTrade before any point value lookup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 03:52:41 -05:00
SenofyandClaude Sonnet 4.6 245a15666e Add configurable tick interval (time between trades)
- 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>
2026-03-12 03:42:54 -05:00
SenofyandClaude Sonnet 4.6 39d7c5761c Add Random symbol option to trade controls
- 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>
2026-03-12 03:38:03 -05:00
SenofyandClaude Sonnet 4.6 cade280b2d Auto-fetch contract on symbol enable; hide contract when disabled
- POST /api/instruments/contracts now accepts optional { symbols[] } body
  to resolve a subset rather than all enabled instruments
- Settings toggle() fires a targeted resolve when enabling a symbol,
  merging the result into contracts state without a full page refresh
- Active Contract cell is hidden (null) when the instrument is disabled

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 03:34:51 -05:00
SenofyandClaude Sonnet 4.6 6d3e8b6065 Add per-firm banned symbols feature
- 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>
2026-03-12 03:29:16 -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 Opus 4.6 881c210366 Add sidebar navigation with responsive bottom bar
Three pages: AutoTrader, AutoBuyer, AutoRequester. Fixed left sidebar
on desktop (md+), bottom tab bar on mobile.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 15:00:41 -05:00
SenofyandClaude Sonnet 4.6 b990ba0606 Remove autotrader.sqlite from tracking, add to .gitignore
Database should be created fresh on first run, not committed to the repo.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-10 03:38:55 -05:00
SenofyandClaude Sonnet 4.6 a13096ea86 Add Random direction option — picks Buy or Sell once per batch
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>
2026-03-10 03:35:50 -05:00
SenofyandClaude Sonnet 4.6 8848f90b11 Use Cash History report for true after-fee daily P&L, Fills FIFO as fallback
- Primary: Cash History report sums non-Fund-Transaction Deltas per day,
  capturing broker platform fees not present in the Fills report
- Fallback: Fills + FIFO used when Cash History 404s (passed/completed accounts)
- Extracts requestReport() as shared helper to reduce duplication
- debug PATCH endpoint now accepts optional `name` param to test any report

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 20:37:05 -05:00
SenofyandClaude Sonnet 4.6 570a54fe60 Fix fetchDaysTraded to use reports API with bearer auth and correct daysTraded counting
- Replace fill/ldeps and fill/list approaches with Tradovate reports API
- Add bearer auth to getreport polling (root cause of prior 404s)
- Use endDate = tomorrow to ensure current-session fills are included
- Count all traded days when minDayPnL is 0, otherwise count days >= minDayPnL
- Add PATCH /api/debug endpoint for proxying raw Tradovate API calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 18:57:12 -05:00
SenofyandClaude Sonnet 4.6 95e7433941 Simplify min-day amount expression, remove extra variable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 17:38:04 -05:00
SenofyandClaude Sonnet 4.6 68075059d0 Fix min-day target for 0% consistency accounts + daysTraded consistency
trading-logic: when baseAmount=0 (consistency=0%), target cappedByFuture
directly instead of collapsing to minDayPnL. For a $4000 target with $150
min-day and 5 days, day 1 now correctly targets $3400 ($4000 - 4×$150)
then $150 for each remaining mandatory day.

tradovate-class: make fetchDaysTraded() public so auto-trade can call it
immediately after a trade exits. Fix daysTraded to count only positive-P&L
days from the FIFO results, consistent with computeDailyTarget's
positiveDays.length — previously counted all raw fill dates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 17:33:55 -05:00
SenofyandClaude Sonnet 4.6 5cba4ef175 Block new trades during 3–5 PM Central no-trade window
isInNoTradeWindow() checks the current hour in America/Chicago (handles
CST/CDT automatically) and returns true from 15:00–16:59. runTrade()
returns early if the window is active, blocking all entries regardless of
whether the scheduler is running or a manual trade is triggered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 14:24:37 -05:00
SenofyandClaude Sonnet 4.6 1902322627 Update README for Windows VPS setup
Switch from Ubuntu to Windows Server instructions: winget for Git/Node,
Visual Studio Build Tools for better-sqlite3 native compilation, PM2 with
pm2-windows-startup for persistence, and Windows Firewall rules.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 13:59:25 -05:00
SenofyandClaude Sonnet 4.6 c19dde7079 Replace Next.js boilerplate README with VPS setup guide
Covers Node.js install, build-tools for native SQLite module, clone,
install, build, run, PM2 process management, firewall, and update steps.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 13:58:24 -05:00
SenofyandClaude Sonnet 4.6 563554c58f Remove hardcoded firm credentials from DB seed
Plaintext usernames and passwords for Alpha and TakeProfitTrader have
been removed from the startup seed block. Firms must now be added
manually through the UI or API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 13:52:25 -05:00
SenofyandClaude Sonnet 4.6 ce2075f603 Add privacy toggle, min-day P&L reservation, and extra-day MNQ trades
- 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>
2026-03-09 13:45:26 -05:00
SenofyandClaude Sonnet 4.6 49580c6bb4 Add max_position_size to account configs
- 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>
2026-03-09 03:51: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 532c2e2279 Add daily target logic and consistency reference line to equity curve
- lib/trading-logic.ts: computeDailyTarget() computes the next trading
  day's profit target via two paths:
  • No positive days yet → profitTarget × consistency (first day)
  • Positive days exist → maxDay / consistency gives the total profit
    needed to satisfy the consistency rule; target maxDay when far away,
    or the exact remaining amount when close
- Account detail page: display "Next Trading Day Amount" in Objectives card
- Equity curve: add indigo dashed reference line for the consistency target
  (maxDay / consistency), labelled top-left to avoid overlapping the amber
  profit-target line (top-right)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:26:40 -05:00
SenofyandClaude Sonnet 4.6 645041c600 Add .gitignore entries for local runtime artifacts
Ignore *.sqlite, dev.log, dev.err, and nul.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:03:59 -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
Senofy b33c43aa0c Initial commit from Create Next App 2026-03-07 21:13:43 -06:00