Report each live account's payout state to the master
payoutStates: one entry per live account (negative included, dead not) with its current-cycle progress — qualifying days, full equity profit, max qualifying day, P&L sum, and the cycle's end-of-day high-water mark — plus the withdrawal count and the cycle's effective target/consistency/ min-days from resolveEffectiveConfig. client.dailyPnL is already the active-cycle slice, so a withdrawal resets the reported path on its own. Feeds the master's payout calendar; an older master ignores the field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
abfb703f0e
commit
79ee5773cb
+40
-1
@@ -17,7 +17,7 @@ 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 } from './trading-logic';
|
||||
import { combineCmeSessions, computeDayPlan, currentTradeDateCT, LEG_COMPLETION_EPSILON, resolveEffectiveConfig } from './trading-logic';
|
||||
import type { AccountTypeStats } from './master-protocol';
|
||||
|
||||
function collectFirmStats() {
|
||||
@@ -95,6 +95,45 @@ function collectFirmStats() {
|
||||
hist[combined.daysTraded] = (hist[combined.daysTraded] ?? 0) + 1;
|
||||
}
|
||||
|
||||
// Exact payout state for every live account — negative ones
|
||||
// included, since the master sims their real required profit.
|
||||
// client.dailyPnL is already the active-cycle slice, so a
|
||||
// withdrawal resets days/maxDay/sum here automatically.
|
||||
if (cfg && combined) {
|
||||
const r2 = (n: number) => Math.round(n * 100) / 100;
|
||||
const equityProfit = r2(cash.amount - cfg.accountSize);
|
||||
const qualifying = cfg.minDayPnL === 0
|
||||
? combined.dailyPnL
|
||||
: combined.dailyPnL.filter((d) => d.pnl >= cfg.minDayPnL);
|
||||
const sum = r2(combined.dailyPnL.reduce((s, d) => s + d.pnl, 0));
|
||||
// End-of-day equity-profit high-water mark for this cycle,
|
||||
// floored at the $0 start: walk the P&L from the cycle base.
|
||||
let run = r2(equityProfit - sum);
|
||||
let highWater = Math.max(0, run);
|
||||
for (const d of combined.dailyPnL) {
|
||||
run = r2(run + d.pnl);
|
||||
if (run > highWater) highWater = run;
|
||||
}
|
||||
// Effective target for this cycle: withdrawal stages applied.
|
||||
const fundTxns = client.fundTransactions?.[acc.id] ?? [];
|
||||
const effective = resolveEffectiveConfig(
|
||||
cfg.profitTarget, cfg.consistency, cfg.minTradingDays,
|
||||
cfg.targetSameEquity, cfg.withdrawalStages,
|
||||
client.priorProfit?.[acc.id] ?? 0, fundTxns,
|
||||
);
|
||||
(slice.payoutStates ??= []).push({
|
||||
days: qualifying.length,
|
||||
profit: equityProfit,
|
||||
maxDay: qualifying.length > 0 ? Math.max(...qualifying.map((d) => d.pnl)) : 0,
|
||||
sum,
|
||||
high: highWater,
|
||||
withdrawals: fundTxns.filter((f) => f.amount < 0).length,
|
||||
target: effective.profitTarget,
|
||||
consistency: effective.consistency,
|
||||
minDays: effective.minTradingDays,
|
||||
});
|
||||
}
|
||||
|
||||
if (client.positions[acc.id]) {
|
||||
inTrade++;
|
||||
accountsTraded++;
|
||||
|
||||
Reference in New Issue
Block a user