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:
Brandon Li
2026-09-23 12:28:41 -05:00
co-authored by Claude Opus 5.5
parent a47a86a59c
commit acb8879575
8 changed files with 205 additions and 19 deletions
+21 -1
View File
@@ -3,8 +3,9 @@ import { loadDailyPnL } from '@/lib/db';
import { getClients } from '@/lib/clients';
import { getCachedCatalog } from '@/lib/firm-catalog';
import { getAccountConfig, getInferredSize, matchAccountType } from '@/lib/account-type-resolver';
import { historyFresh } from '@/lib/platform-client';
import {
combineCmeSessions, computeDayPlan, resolveEffectiveConfig, currentTradeDateCT,
combineCmeSessions, computeDayPlan, cycleCompletion, resolveEffectiveConfig, currentTradeDateCT,
BIG_DAY_THRESHOLD, FIRST_DAY_STOP, LEG_COMPLETION_EPSILON, MIN_DAY_STOP_MULT,
} from '@/lib/trading-logic';
@@ -174,6 +175,24 @@ export async function GET() {
}
}
// Today finished the cycle — the reporter's check and guards,
// so this pill and the master's purple count agree.
let completed = false;
const historyLoaded = client.dailyPnL[acc.id] !== undefined
&& client.fundTransactions?.[acc.id] !== undefined;
if (cfg && effective && historyLoaded && historyFresh(client, acc) && !client.positions[acc.id]) {
completed = cycleCompletion({
accountId: acc.id,
rawTradeDate: tradeDate,
cycleDailyPnL: client.dailyPnL[acc.id],
rawRealizedPnL: cash.realizedPnL,
combineCmeHolidays: cfg.combineCmeHolidays,
effective,
equityProfit: cash.amount - cfg.accountSize,
splitEnabled: cfg.splitEnabled,
}) === 'today';
}
return {
id: acc.id,
name: acc.name,
@@ -195,6 +214,7 @@ export async function GET() {
autoLiqThreshold,
totalProfit,
targetHit,
completed,
stage,
// Current stage is a drain stage — dashboards label it "Stage N – Drain".
stageDrain: effective?.drain ?? false,
+13 -10
View File
@@ -10,9 +10,10 @@ type SortDir = 'asc' | 'desc';
function statusRank(account: AccountState): number {
if (isAccountDead(account)) return 0;
if (account.completed) return 5; // Completed — finished its cycle today
if (!account.active) return 1;
if (!account.positionDirection) {
if (account.targetHit) return 4; // Target Hit — most accomplished
if (account.targetHit) return 4; // Target Hit — next to Completed
return 2; // Flat
}
return 3; // In Trade
@@ -384,15 +385,17 @@ function AccountRow({ account, firm, hideDead, privacy, onAssigned }: {
<div className="flex items-center justify-between">
{dead
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-slate-800 text-white">Dead</span>
: !account.active
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-red-100 text-red-700">Hit DLL</span>
: account.positionDirection
? <span className={`inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold ${account.positionDirection === 'long' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>{account.positionDirection === 'long' ? 'Long' : 'Short'}</span>
: account.personalDll
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-amber-100 text-amber-700" title="Booked the day red via its own stop — make-back rides next session">Personal DLL</span>
: account.targetHit
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-green-100 text-green-700">Target Hit</span>
: <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-slate-100 text-slate-500">Flat</span>}
: account.completed
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-purple-100 text-purple-700" title="Finished its cycle today — target, consistency and min days met">Completed</span>
: !account.active
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-red-100 text-red-700">Hit DLL</span>
: account.positionDirection
? <span className={`inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold ${account.positionDirection === 'long' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>{account.positionDirection === 'long' ? 'Long' : 'Short'}</span>
: account.personalDll
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-amber-100 text-amber-700" title="Booked the day red via its own stop — make-back rides next session">Personal DLL</span>
: account.targetHit
? <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-green-100 text-green-700">Target Hit</span>
: <span className="inline-block px-2.5 py-0.5 rounded-full text-xs font-semibold bg-slate-100 text-slate-500">Flat</span>}
<Link
href={`/accounts/${account.id}`}
className="text-slate-400 hover:text-slate-600 hover:bg-slate-200 p-1 rounded-md transition-colors inline-flex"