Reporter: catch up completed cycles on reset, report each firm's account list

When a fund transaction starts a new cycle (the days revert to 0), the
cycle it ended is checked against the completion rule for a week after and
named if it stood complete — its final day may never have been reported.
Only for a cycle this instance saw begin: the clients now note where the
ended cycle started as they move last_fund_date forward. Completions carry
the cycle they belong to, and each firm reports its whole account list so
the master can tell erased accounts and spot new funded ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-09-23 13:08:16 -05:00
co-authored by Claude Opus 5.5
parent acb8879575
commit a7e01b0138
6 changed files with 279 additions and 49 deletions
+14 -2
View File
@@ -5,7 +5,7 @@ import type { AccountItem, AuthLoginResponse, Contract } from './tradovate-helpe
import { computeSec, randomUUIDV4 } from './tradovate-helpers';
import { POINT_VALUES } from './trading-logic';
import { getCachedContract, resolveContracts } from './contract-resolver';
import { saveDailyPnL, loadDailyPnL, saveAccountMeta, loadAccountMeta, saveFundTransactions, loadFundTransactions } from './db';
import { saveDailyPnL, loadDailyPnL, saveAccountMeta, loadAccountMeta, saveFundTransactions, loadFundTransactions, saveEndedCycleStart } from './db';
import { brokerWebSocket } from './outbound-proxy';
import { FILLS_FALLBACK_NOTE } from './platform-client';
@@ -267,7 +267,6 @@ export class TradovateClient {
console.error('[requestSync] Received null/undefined response — auth may have failed');
return;
}
// liquidateOnly flag lives in accountRiskStatuses
const riskStatusById: { [accountId: number]: { liquidateOnly?: string } } = (
response.accountRiskStatuses || []
@@ -595,6 +594,19 @@ export class TradovateClient {
// Use the most recent fund transaction as the reset point — persist it so it survives beyond the 28-day window
const lastFundDate = [...Object.keys(fundMap)].sort().pop() ?? null;
if (lastFundDate) {
// A new cycle starts: note where the one it ends began —
// with filterActivePnL's call on that date's own row — for
// the reporter's catch-up. Only from a stored start: the
// first load after a wipe or on a new instance never saw
// the cycle before it begin.
if (storedFundDate && lastFundDate > storedFundDate) {
const prevAmt = this.fundTransactions[account.id]?.find((f) => f.date === storedFundDate)?.amount ?? null;
saveEndedCycleStart(account.id, {
fundDate: storedFundDate,
includesDay: !(prevAmt !== null && prevAmt < 0) || TradovateClient.isWithdrawalBeforeFirstTrade(
fundTimestampMap[storedFundDate] ?? storedFundTimestamp, firstTradeTsMap[storedFundDate] ?? null),
});
}
saveAccountMeta(account.id, 'last_fund_date', lastFundDate);
this.lastFundDates[account.id] = lastFundDate;
if (fundTimestampMap[lastFundDate]) {