Count CME holiday sessions as one combined trading day when the type opts in
Account types with the catalog's new combineCmeHolidays flag are read through a combined-day view: holiday-session P&L entries fold into the next full trading day (computed from the federal-holiday rules, so any year works), the day count matches how the firm records it (Apex: Sun/ Mon/Tue around a Monday holiday is ONE day), and on the later sessions of the stretch the earlier sessions' booked P&L carries into realized — so day targets, already-traded gates, target-hit status and the panel's day P&L all treat the stretch as a single day. Off by default; older masters that don't send the flag behave exactly as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
57846d2b5f
commit
f07721019b
+21
-10
@@ -12,7 +12,7 @@ import { getClients } from './clients';
|
||||
import { getTradableFirms } from './firm-catalog';
|
||||
import { getAccountConfig } from './account-type-resolver';
|
||||
import {
|
||||
computeDayPlan, pickLegAmount, resolveEffectiveConfig, currentTradeDateCT,
|
||||
combineCmeSessions, computeDayPlan, pickLegAmount, resolveEffectiveConfig, currentTradeDateCT,
|
||||
LEG_COMPLETION_EPSILON, MAX_LEGS_PER_DAY, POINT_VALUES,
|
||||
type DayPlan,
|
||||
} from './trading-logic';
|
||||
@@ -62,8 +62,18 @@ function evaluateAccountForTrade(client: any, acc: { id: number; name: string; a
|
||||
|
||||
const cash = client.accountCashBalances[acc.id] ?? { amount: 0, realizedPnL: 0 };
|
||||
const autoLiqThreshold = client.autoLiqThresholds[acc.id] ?? 0;
|
||||
const dailyPnL: { date: string; pnl: number }[] = client.dailyPnL[acc.id] ?? [];
|
||||
const daysTraded: number = client.daysTraded[acc.id] ?? 0;
|
||||
|
||||
// A combining firm records holiday sessions with the next full trading day,
|
||||
// so the plan and the already-traded gates below must see the whole stretch
|
||||
// as one day: Sunday's booked P&L folds into Tuesday's realized, and the
|
||||
// day target stays anchored to the combined (clearing) trade date. `cash`
|
||||
// itself stays raw — the commission delta in the fire path compares live
|
||||
// Tradovate values.
|
||||
const combined = combineCmeSessions(
|
||||
cfg.combineCmeHolidays, client.dailyPnL[acc.id] ?? [], tradeDate, cash.realizedPnL,
|
||||
);
|
||||
const dailyPnL = combined.dailyPnL;
|
||||
const daysTraded = combined.daysTraded;
|
||||
|
||||
const base = { plan: null, isExtraDay: false, cash, dailyPnL, daysTraded };
|
||||
if (isAccountDead(cash.amount, autoLiqThreshold)) return { ...base, eligible: false, reason: 'dead' };
|
||||
@@ -78,8 +88,8 @@ function evaluateAccountForTrade(client: any, acc: { id: number; name: string; a
|
||||
|
||||
const equityProfit = cash.amount - cfg.accountSize;
|
||||
const plan = computeDayPlan(
|
||||
acc.id, tradeDate, effective.profitTarget, effective.consistency,
|
||||
dailyPnL, cfg.minDayPnL, effective.minTradingDays, equityProfit, cash.realizedPnL,
|
||||
acc.id, combined.tradeDate, effective.profitTarget, effective.consistency,
|
||||
dailyPnL, cfg.minDayPnL, effective.minTradingDays, equityProfit, combined.realizedPnL,
|
||||
cfg.splitEnabled
|
||||
);
|
||||
if (!plan) return { ...base, eligible: false, reason: 'invalid balance' };
|
||||
@@ -92,9 +102,10 @@ function evaluateAccountForTrade(client: any, acc: { id: number; name: string; a
|
||||
const evaluated = { plan, isExtraDay, cash, dailyPnL, daysTraded };
|
||||
|
||||
if (isExtraDay || !plan.splitAllowed) {
|
||||
// Legacy one-and-done gate: any realized PnL today means this account is finished.
|
||||
if (cash.realizedPnL !== 0) {
|
||||
return { ...evaluated, eligible: false, reason: `already traded today (realizedPnL=${cash.realizedPnL})` };
|
||||
// Legacy one-and-done gate: any realized PnL today means this account is
|
||||
// finished — for a combining account, "today" spans the holiday stretch.
|
||||
if (combined.realizedPnL !== 0) {
|
||||
return { ...evaluated, eligible: false, reason: `already traded today (realizedPnL=${combined.realizedPnL})` };
|
||||
}
|
||||
if (!isExtraDay && plan.remainingToday <= 0) {
|
||||
return { ...evaluated, eligible: false, reason: `target=$${plan.dayTarget} (challenge complete)` };
|
||||
@@ -102,9 +113,9 @@ function evaluateAccountForTrade(client: any, acc: { id: number; name: string; a
|
||||
} else {
|
||||
// Split-leg mode: keep trading until the day's remaining target is used up.
|
||||
// The epsilon only applies once a leg has completed, so tiny day-start targets still trade.
|
||||
const doneThreshold = cash.realizedPnL === 0 ? 0 : LEG_COMPLETION_EPSILON;
|
||||
const doneThreshold = combined.realizedPnL === 0 ? 0 : LEG_COMPLETION_EPSILON;
|
||||
if (plan.remainingToday <= doneThreshold) {
|
||||
const reason = cash.realizedPnL === 0
|
||||
const reason = combined.realizedPnL === 0
|
||||
? `target=$${plan.dayTarget} (challenge complete)`
|
||||
: `day done ($${plan.remainingToday} left of $${plan.dayTarget})`;
|
||||
return { ...evaluated, eligible: false, reason };
|
||||
|
||||
Reference in New Issue
Block a user