Vest: the payout projection runs on Vest's day, and stages count each payout
projectPerfectPath takes the raw trade date (default: the Central one): the reporter passes its tradeDateFor day and the account page the one /api/state now gives each account. From 5 PM CT to 20:00 ET it took tomorrow as today while every input was Vest's, so the day's claim moved a day late, the next day's stage-1 payout dropped, and an open Vest-day row counted twice. Without same-day stages, the stage comes from the client's payout list (payoutDays, one per payout) when it has read one, not the negative fund rows: Vest books a day's two claims as one row, so the engine, claimDue, the stage label and the projection stayed a stage behind the report. StageInputs.payouts carries the count; a client with no list counts rows as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
032ba1ca9c
commit
4a8e027056
@@ -14,7 +14,7 @@ import {
|
||||
projectPerfectPath, cycleCompletion, endedCycleCompletion, DLL_RESERVE_FRACTION, DLL_MIN_STOP, notionalCap, expectedSwapToWin, MARGIN_HEADROOM,
|
||||
dllReserve, DLL_SLIPPAGE_FRACTION, maxLossRoom, lastStand, breachDistance, LAST_STAND_FRACTION, planLegSize, rankForTarget,
|
||||
currentTradeDateCT, foldReason, withinFirmCaps, personSizeFactor, personHoldHours, PERSON_SIZE_SPREAD, machineSide,
|
||||
resolveEffectiveConfig, stageInputsFor, floorRoom, resetClearStop, shortestNextLeg, computeDayPlan, clearsClose, RESET_CLEAR_HOLDS,
|
||||
resolveEffectiveConfig, stageInputsFor, stagePayouts, floorRoom, resetClearStop, shortestNextLeg, computeDayPlan, clearsClose, RESET_CLEAR_HOLDS,
|
||||
legCloseNote,
|
||||
} from '../lib/trading-logic.ts';
|
||||
|
||||
@@ -1337,6 +1337,61 @@ test('projectPerfectPath: a same-day type trades each projected day from the bas
|
||||
assert.deepEqual(projectPerfectPath({ ...opts, stageInputs: { dailyLossLimit: 1229, stagesSameDay: false, sameDayWithdrawals: 0 } }), lifetime);
|
||||
});
|
||||
|
||||
test('projectPerfectPath: today is the raw trade date it is given — Vest\'s, still the day before from 5 PM CT to 20:00 ET', () => {
|
||||
const firstOf = (path, n) => path.slice(0, n).map((d) => [d.date, d.stage, d.withdrawal]);
|
||||
// Claimed once on Vest day 10-27 and $1,000 made since.
|
||||
const claimed = {
|
||||
accountId: 7, cfg: vestFunded, cycleDailyPnL: [], fundTransactions: [{ date: '2026-10-20', amount: 50000 }, { date: '2026-10-27', amount: -1500 }],
|
||||
balance: 51000, realizedPnL: 1000, payout: { withdrawalPct: 1 }, stageInputs: { stagesSameDay: true, sameDayWithdrawals: 1 },
|
||||
};
|
||||
const before = projectPerfectPath({ ...claimed, now: cdt('2026-10-27T16:30:00') });
|
||||
assert.deepEqual(firstOf(before, 3), [['2026-10-27', 2, -3000], ['2026-10-28', 1, -1500], ['2026-10-28', 2, -3000]]);
|
||||
// 5:30 PM CT: the Central date has rolled, Vest's hasn't — the day's
|
||||
// claim stays on it, and 10-28 keeps its stage-1 payout.
|
||||
assert.deepEqual(projectPerfectPath({ ...claimed, now: cdt('2026-10-27T17:30:00'), rawTradeDate: '2026-10-27' }), before);
|
||||
// No date given: the Central one, as before.
|
||||
assert.equal(projectPerfectPath({ ...claimed, now: cdt('2026-10-27T17:30:00') })[0].date, '2026-10-28');
|
||||
|
||||
// No claim yet, Vest day 10-27's row already booked: counted once, as today's.
|
||||
const open = {
|
||||
...claimed, fundTransactions: claimedBefore, cycleDailyPnL: [{ date: '2026-10-27', pnl: 1000 }],
|
||||
stageInputs: { stagesSameDay: true, sameDayWithdrawals: 0 },
|
||||
};
|
||||
const earlier = projectPerfectPath({ ...open, now: cdt('2026-10-27T16:30:00') });
|
||||
assert.deepEqual(firstOf(earlier, 2), [['2026-10-27', 1, -1500], ['2026-10-27', 2, -3000]]);
|
||||
assert.deepEqual(projectPerfectPath({ ...open, now: cdt('2026-10-27T17:30:00'), rawTradeDate: '2026-10-27' }), earlier);
|
||||
});
|
||||
|
||||
test('stages without the same-day reset count each payout, where one fund row holds a day\'s two (Vest)', () => {
|
||||
// Two listed stages; claims of $1,500 and $3,000 on Vest day 10-27 share its row.
|
||||
const stages = [{ profit: 3000, consistency: 0, minTradingDays: 0 }, { profit: 2000, consistency: 0, minTradingDays: 0 }];
|
||||
const rows = [{ date: '2026-10-20', amount: 50000 }, { date: '2026-10-27', amount: -4500 }];
|
||||
const resolve = (inputs) => resolveEffectiveConfig(1500, 0, 0, false, stages, 0, rows, 0, inputs);
|
||||
assert.equal(resolve({ payouts: 2 }).profitTarget, 2000);
|
||||
// No payout list: one per negative fund row, as always.
|
||||
assert.equal(resolve({}).profitTarget, 3000);
|
||||
// A same-day type still counts only today's.
|
||||
assert.equal(resolve({ stagesSameDay: true, sameDayWithdrawals: 0, payouts: 2 }).profitTarget, 1500);
|
||||
|
||||
// stageInputsFor takes the count from the client's payout list, when it has read one.
|
||||
const client = { sameDayClaims: () => 2, payoutDays: () => ['2026-10-27', '2026-10-27'] };
|
||||
assert.deepEqual(stageInputsFor(client, 7, {}), { dailyLossLimit: 0, stagesSameDay: false, sameDayWithdrawals: 0, payouts: 2 });
|
||||
assert.deepEqual(stageInputsFor({ payoutDays: () => undefined }, 7, {}), { dailyLossLimit: 0, stagesSameDay: false, sameDayWithdrawals: 0 });
|
||||
assert.deepEqual(stageInputsFor(client, 7, { stagesSameDay: true }), { dailyLossLimit: 0, stagesSameDay: true, sameDayWithdrawals: 2 });
|
||||
// The state route's stage label counts the same way.
|
||||
assert.equal(stagePayouts(rows, stageInputsFor(client, 7, {})), 2);
|
||||
assert.equal(stagePayouts(rows, stageInputsFor({}, 7, {})), 1);
|
||||
|
||||
// The projection starts from the same count: stage 3's $2,000 next, then it repeats.
|
||||
const opts = {
|
||||
accountId: 7, cfg: { ...vestFunded, withdrawalStages: stages }, cycleDailyPnL: [], fundTransactions: rows,
|
||||
balance: 50000, realizedPnL: 0, payout: { withdrawalPct: 1 }, now: cdt('2026-10-27T12:00:00'),
|
||||
};
|
||||
const firstOf = (path, n) => path.slice(0, n).map((d) => [d.date, d.stage, d.withdrawal]);
|
||||
assert.deepEqual(firstOf(projectPerfectPath({ ...opts, stageInputs: stageInputsFor(client, 7, {}) }), 2), [['2026-10-27', 3, -2000], ['2026-10-28', 4, -2000]]);
|
||||
assert.deepEqual(firstOf(projectPerfectPath(opts), 2), [['2026-10-27', 2, -3000], ['2026-10-28', 3, -2000]]);
|
||||
});
|
||||
|
||||
test('endedCycleCompletion: a same-day type\'s ended cycle is judged on its day\'s base stage', () => {
|
||||
// 2026-10-26 made $1,500 and the auto-claim took it before the reporter
|
||||
// saw the final day; the account had claimed the day before too. The
|
||||
|
||||
Reference in New Issue
Block a user