Reporter: name the accounts whose final day completed their cycle
cycleCompletion() says whether today's P&L finished the current cycle (profit target, consistency and minimum days all met) — projectPerfectPath's completion probe run without and with today. The reporter counts those as `completed` (a subset of targetHit) and sends their names, so the master can keep an account a firm erases after it passes. Checked ahead of the lockout branch: a firm locking a passed account is no DLL loss. The local dashboard shows them with a purple Completed pill. Because the master keeps a completion for good, doubtful reads stay 'none': weekends, a Monday with a weekend-dated row, the first minutes after the 5 PM roll, and history that hasn't freshly loaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a47a86a59c
commit
acb8879575
+57
-4
@@ -18,8 +18,9 @@ import { getClients } from './clients';
|
||||
import { getTradableFirms } from './firm-catalog';
|
||||
import { getAccountConfig } from './account-type-resolver';
|
||||
import { getSchedulerStatus } from './auto-trade';
|
||||
import { combineCmeSessions, computeDayPlan, currentTradeDateCT, LEG_COMPLETION_EPSILON, projectPerfectPath, resolveEffectiveConfig } from './trading-logic';
|
||||
import { combineCmeSessions, computeDayPlan, currentTradeDateCT, cycleCompletion, LEG_COMPLETION_EPSILON, projectPerfectPath, resolveEffectiveConfig } from './trading-logic';
|
||||
import type { AccountTypeStats } from './master-protocol';
|
||||
import { historyFresh } from './platform-client';
|
||||
|
||||
function collectFirmStats() {
|
||||
// Only firms this machine has credentials for. A firm it cannot log into
|
||||
@@ -27,13 +28,16 @@ function collectFirmStats() {
|
||||
// the master's table with rows for firms it does not run.
|
||||
const firms = getTradableFirms();
|
||||
const clients = getClients();
|
||||
// One raw trade date for the whole report: the combined views below roll
|
||||
// it forward, the completion check needs it as is.
|
||||
const rawToday = currentTradeDateCT();
|
||||
|
||||
return firms.map((f) => {
|
||||
const client = clients.get(f.id);
|
||||
if (!client || client.accountList.length === 0) {
|
||||
return {
|
||||
firm: f.name, totalAccounts: 0, accountsTraded: 0, inTrade: 0,
|
||||
targetHit: 0, partial: 0, loss: 0, personalDll: 0, accountTypes: [],
|
||||
targetHit: 0, partial: 0, loss: 0, personalDll: 0, completed: 0, accountTypes: [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,6 +48,7 @@ function collectFirmStats() {
|
||||
let partialCount = 0;
|
||||
let lossCount = 0;
|
||||
let personalDllCount = 0;
|
||||
let completedCount = 0;
|
||||
|
||||
// Per account type, so the master can say what the accounts still to
|
||||
// trade actually are. Keyed by account type id; unassigned accounts
|
||||
@@ -91,7 +96,7 @@ function collectFirmStats() {
|
||||
// projects from "on the winning path", which they are not.
|
||||
// (Dead accounts never reach here — the auto-liq check above.)
|
||||
const combined = cfg ? combineCmeSessions(
|
||||
cfg.combineCmeHolidays, client.dailyPnL[acc.id] ?? [], currentTradeDateCT(), cash.realizedPnL,
|
||||
cfg.combineCmeHolidays, client.dailyPnL[acc.id] ?? [], rawToday, cash.realizedPnL,
|
||||
) : null;
|
||||
|
||||
// Stage-resolved config, shared by the payout state and the
|
||||
@@ -208,6 +213,54 @@ function collectFirmStats() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Did today finish the cycle? Checked ahead of the lockout branch:
|
||||
// firms lock a passed account (Tradovate liquidate-only, TopstepX
|
||||
// canTrade=false), and a pass is no loss. Only once the account's
|
||||
// history has loaded — right after a restart the missing rows and
|
||||
// withdrawals would read as a fresh stage-1 cycle — and a 'today'
|
||||
// only on freshly fetched rows, since the master keeps it.
|
||||
const historyLoaded = client.dailyPnL[acc.id] !== undefined
|
||||
&& client.fundTransactions?.[acc.id] !== undefined;
|
||||
if (cfg && combined && effective && historyLoaded) {
|
||||
const completion = cycleCompletion({
|
||||
accountId: acc.id,
|
||||
rawTradeDate: rawToday,
|
||||
cycleDailyPnL: client.dailyPnL[acc.id],
|
||||
rawRealizedPnL: cash.realizedPnL,
|
||||
combineCmeHolidays: cfg.combineCmeHolidays,
|
||||
effective,
|
||||
equityProfit: cash.amount - cfg.accountSize,
|
||||
splitEnabled: cfg.splitEnabled,
|
||||
});
|
||||
if (completion === 'today' && historyFresh(client, acc)) {
|
||||
accountsTraded++;
|
||||
slice.accountsTraded++;
|
||||
targetHitCount++;
|
||||
slice.targetHit = (slice.targetHit ?? 0) + 1;
|
||||
completedCount++;
|
||||
slice.completed = (slice.completed ?? 0) + 1;
|
||||
if (dayEntry) {
|
||||
dayEntry.targetHit++;
|
||||
dayEntry.completed = (dayEntry.completed ?? 0) + 1;
|
||||
}
|
||||
// Same test as projectPerfectPath's `loops`: a cycle that
|
||||
// keeps going pays out, one that stops just passes.
|
||||
const kind = effective.drain ? 'drain'
|
||||
: (cfg.payoutable === true || cfg.withdrawalStages.length > 0) ? 'payout' : 'pass';
|
||||
(slice.completedAccounts ??= []).push({
|
||||
name: acc.name,
|
||||
date: combined.tradeDate,
|
||||
stage: 1 + fundTxns.filter((f) => f.amount < 0).length,
|
||||
kind,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
// Passed on an earlier day and locked since: nothing traded
|
||||
// today, so it reads as untraded — like a finished account
|
||||
// that's still active — not as a DLL loss every day after.
|
||||
if (completion === 'before' && !acc.active && combined.realizedPnL === 0) continue;
|
||||
}
|
||||
|
||||
// DLL lockout: Tradovate flips the account to liquidate-only, so
|
||||
// its day is over at a loss even when the booked realizedPnL
|
||||
// hasn't caught up yet (or the account has no matching config).
|
||||
@@ -269,7 +322,7 @@ function collectFirmStats() {
|
||||
return {
|
||||
firm: f.name, totalAccounts, accountsTraded, inTrade,
|
||||
targetHit: targetHitCount, partial: partialCount, loss: lossCount,
|
||||
personalDll: personalDllCount, accountTypes,
|
||||
personalDll: personalDllCount, completed: completedCount, accountTypes,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user