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,
|
maxLoss: a.maxLoss,
|
||||||
maxPositionSize: a.maxPositionSize,
|
maxPositionSize: a.maxPositionSize,
|
||||||
targetSameEquity: a.targetSameEquity,
|
targetSameEquity: a.targetSameEquity,
|
||||||
|
splitEnabled: a.splitEnabled,
|
||||||
withdrawalStages: a.withdrawalStages,
|
withdrawalStages: a.withdrawalStages,
|
||||||
})),
|
})),
|
||||||
catalogUpdatedAt: firm.updatedAt,
|
catalogUpdatedAt: firm.updatedAt,
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ export async function GET() {
|
|||||||
const equityProfit = cash.amount - cfg.accountSize;
|
const equityProfit = cash.amount - cfg.accountSize;
|
||||||
const plan = computeDayPlan(
|
const plan = computeDayPlan(
|
||||||
acc.id, tradeDate, effective.profitTarget, effective.consistency,
|
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;
|
dailyTarget = plan ? { amount: plan.dayTarget, path: plan.path } : null;
|
||||||
remainingToday = plan?.remainingToday ?? 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 equityProfit = cash.amount - cfg.accountSize;
|
||||||
const plan = computeDayPlan(
|
const plan = computeDayPlan(
|
||||||
acc.id, tradeDate, effective.profitTarget, effective.consistency,
|
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' };
|
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 (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`);
|
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 {
|
return {
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ export interface CatalogAccountType {
|
|||||||
maxLoss: number;
|
maxLoss: number;
|
||||||
maxPositionSize: number;
|
maxPositionSize: number;
|
||||||
targetSameEquity: boolean;
|
targetSameEquity: boolean;
|
||||||
|
/** False = big days trade as one unsplit leg instead of random ≥$800 pieces. */
|
||||||
|
splitEnabled: boolean;
|
||||||
withdrawalStages: { profit: number; consistency: number; minTradingDays: number }[];
|
withdrawalStages: { profit: number; consistency: number; minTradingDays: number }[];
|
||||||
/** ISO. Ties between two matching account types are broken by this. */
|
/** ISO. Ties between two matching account types are broken by this. */
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
|||||||
+2
-1
@@ -85,7 +85,8 @@ function collectFirmStats() {
|
|||||||
const equityProfit = cash.amount - cfg.accountSize;
|
const equityProfit = cash.amount - cfg.accountSize;
|
||||||
const plan = computeDayPlan(
|
const plan = computeDayPlan(
|
||||||
acc.id, currentTradeDateCT(), cfg.profitTarget, cfg.consistency,
|
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 :
|
const targetHit = !plan ? false :
|
||||||
((plan.dayTarget === 0 && Math.abs(cash.realizedPnL) > 0 && (client.daysTraded[acc.id] ?? 0) <= cfg.minTradingDays) ||
|
((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. */
|
/** dayTarget minus what's already realized today; what's left to trade. */
|
||||||
remainingToday: number;
|
remainingToday: number;
|
||||||
path: 'first_day' | 'normal_day' | 'reduced_day';
|
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;
|
splitAllowed: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +265,8 @@ export function computeDayPlan(
|
|||||||
minDayPnL: number,
|
minDayPnL: number,
|
||||||
minTradingDays: number,
|
minTradingDays: number,
|
||||||
equityProfit: number | null | undefined,
|
equityProfit: number | null | undefined,
|
||||||
realizedPnL: number
|
realizedPnL: number,
|
||||||
|
splitEnabled: boolean = true
|
||||||
): DayPlan | null {
|
): DayPlan | null {
|
||||||
if (typeof equityProfit !== 'number' || !Number.isFinite(equityProfit)) return null;
|
if (typeof equityProfit !== 'number' || !Number.isFinite(equityProfit)) return null;
|
||||||
|
|
||||||
@@ -277,7 +279,7 @@ export function computeDayPlan(
|
|||||||
if (!target) return null;
|
if (!target) return null;
|
||||||
|
|
||||||
const qualifyingDays = minDayPnL === 0 ? priorDays : priorDays.filter((d) => d.pnl >= minDayPnL);
|
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 {
|
return {
|
||||||
dayTarget: target.amount,
|
dayTarget: target.amount,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface AccountConfig {
|
|||||||
maxLoss: number; // 0 = no limit; positive = account is "Dead" when loss exceeds this
|
maxLoss: number; // 0 = no limit; positive = account is "Dead" when loss exceeds this
|
||||||
maxPositionSize: number; // 0 = no limit; positive = max contracts per trade
|
maxPositionSize: number; // 0 = no limit; positive = max contracts per trade
|
||||||
targetSameEquity: boolean; // if true, reduce profitTarget by priorProfit after withdrawal
|
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)
|
withdrawalStages: { profit: number; consistency: number; minTradingDays: number }[]; // per-stage fresh profit + consistency (empty = use base values)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user