Add per-account-type splitEnabled flag from the catalog
When the master marks an account type splitEnabled=false, big days trade as one unsplit leg (the legacy one-and-done behavior); min-day bumps are unaffected. Missing field — older master or pre-toggle cached catalog — defaults to enabled. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
3ef9486977
commit
a36e227e74
@@ -36,6 +36,7 @@ export async function GET() {
|
||||
maxLoss: a.maxLoss,
|
||||
maxPositionSize: a.maxPositionSize,
|
||||
targetSameEquity: a.targetSameEquity,
|
||||
splitEnabled: a.splitEnabled,
|
||||
withdrawalStages: a.withdrawalStages,
|
||||
})),
|
||||
catalogUpdatedAt: firm.updatedAt,
|
||||
|
||||
@@ -69,7 +69,8 @@ export async function GET() {
|
||||
const equityProfit = cash.amount - cfg.accountSize;
|
||||
const plan = computeDayPlan(
|
||||
acc.id, tradeDate, effective.profitTarget, effective.consistency,
|
||||
dailyPnL, cfg.minDayPnL, effective.minTradingDays, equityProfit, cash.realizedPnL
|
||||
dailyPnL, cfg.minDayPnL, effective.minTradingDays, equityProfit, cash.realizedPnL,
|
||||
cfg.splitEnabled
|
||||
);
|
||||
dailyTarget = plan ? { amount: plan.dayTarget, path: plan.path } : null;
|
||||
remainingToday = plan?.remainingToday ?? null;
|
||||
|
||||
+2
-1
@@ -79,7 +79,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
|
||||
dailyPnL, cfg.minDayPnL, effective.minTradingDays, equityProfit, cash.realizedPnL,
|
||||
cfg.splitEnabled
|
||||
);
|
||||
if (!plan) return { ...base, eligible: false, reason: 'invalid balance' };
|
||||
|
||||
|
||||
+3
-1
@@ -154,7 +154,9 @@ function validatePayload(raw: unknown): FirmCatalogPayload {
|
||||
if (typeof type[key] !== 'number') throw new Error(`account type ${j} is missing ${key}`);
|
||||
}
|
||||
if (!isStages(type.withdrawalStages)) throw new Error(`account type ${j} has bad withdrawalStages`);
|
||||
return type as unknown as CatalogAccountType;
|
||||
// Lenient like platform: a master from before the split toggle
|
||||
// doesn't send the field, and those account types all split.
|
||||
return { ...type, splitEnabled: type.splitEnabled !== false } as unknown as CatalogAccountType;
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -70,6 +70,8 @@ export interface CatalogAccountType {
|
||||
maxLoss: number;
|
||||
maxPositionSize: number;
|
||||
targetSameEquity: boolean;
|
||||
/** False = big days trade as one unsplit leg instead of random ≥$800 pieces. */
|
||||
splitEnabled: boolean;
|
||||
withdrawalStages: { profit: number; consistency: number; minTradingDays: number }[];
|
||||
/** ISO. Ties between two matching account types are broken by this. */
|
||||
updatedAt: string;
|
||||
|
||||
+2
-1
@@ -85,7 +85,8 @@ function collectFirmStats() {
|
||||
const equityProfit = cash.amount - cfg.accountSize;
|
||||
const plan = computeDayPlan(
|
||||
acc.id, currentTradeDateCT(), cfg.profitTarget, cfg.consistency,
|
||||
dailyPnL, cfg.minDayPnL, cfg.minTradingDays, equityProfit, cash.realizedPnL
|
||||
dailyPnL, cfg.minDayPnL, cfg.minTradingDays, equityProfit, cash.realizedPnL,
|
||||
cfg.splitEnabled
|
||||
);
|
||||
const targetHit = !plan ? false :
|
||||
((plan.dayTarget === 0 && Math.abs(cash.realizedPnL) > 0 && (client.daysTraded[acc.id] ?? 0) <= cfg.minTradingDays) ||
|
||||
|
||||
@@ -242,7 +242,8 @@ export interface DayPlan {
|
||||
/** dayTarget minus what's already realized today; what's left to trade. */
|
||||
remainingToday: number;
|
||||
path: 'first_day' | 'normal_day' | 'reduced_day';
|
||||
/** False for strict-consistency accounts past their first trade ever — single unsplit trade. */
|
||||
/** False when the account type disables splitting, or for strict-consistency
|
||||
* accounts past their first trade ever — single unsplit trade. */
|
||||
splitAllowed: boolean;
|
||||
}
|
||||
|
||||
@@ -264,7 +265,8 @@ export function computeDayPlan(
|
||||
minDayPnL: number,
|
||||
minTradingDays: number,
|
||||
equityProfit: number | null | undefined,
|
||||
realizedPnL: number
|
||||
realizedPnL: number,
|
||||
splitEnabled: boolean = true
|
||||
): DayPlan | null {
|
||||
if (typeof equityProfit !== 'number' || !Number.isFinite(equityProfit)) return null;
|
||||
|
||||
@@ -277,7 +279,7 @@ export function computeDayPlan(
|
||||
if (!target) return null;
|
||||
|
||||
const qualifyingDays = minDayPnL === 0 ? priorDays : priorDays.filter((d) => d.pnl >= minDayPnL);
|
||||
const splitAllowed = consistency === 0 || consistency >= 1 || qualifyingDays.length === 0;
|
||||
const splitAllowed = splitEnabled && (consistency === 0 || consistency >= 1 || qualifyingDays.length === 0);
|
||||
|
||||
return {
|
||||
dayTarget: target.amount,
|
||||
|
||||
@@ -11,6 +11,7 @@ export interface AccountConfig {
|
||||
maxLoss: number; // 0 = no limit; positive = account is "Dead" when loss exceeds this
|
||||
maxPositionSize: number; // 0 = no limit; positive = max contracts per trade
|
||||
targetSameEquity: boolean; // if true, reduce profitTarget by priorProfit after withdrawal
|
||||
splitEnabled: boolean; // false = big days trade as one unsplit leg instead of random ≥$800 pieces
|
||||
withdrawalStages: { profit: number; consistency: number; minTradingDays: number }[]; // per-stage fresh profit + consistency (empty = use base values)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user