Merge branch 'vest-fix-display' into vest-fixes
# Conflicts: # package.json # scripts/check-trading-logic.mjs
This commit is contained in:
@@ -11,7 +11,7 @@ import assert from 'node:assert/strict';
|
||||
import {
|
||||
percentFee, takeProfitPlan, onTick, obfuscationStopDollars, dllRoom, dllStopDollars, dllViable, stopTicks,
|
||||
botStopsActive, sizeNotional, isNoTradeTime, isPastSessionClose, nextTradingDate, effectiveCombine, DEFAULT_TARGET_HOLD_HOURS,
|
||||
projectPerfectPath, cycleCompletion, DLL_RESERVE_FRACTION, DLL_MIN_STOP, notionalCap, expectedSwapToWin, MARGIN_HEADROOM,
|
||||
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,
|
||||
@@ -306,6 +306,22 @@ test('dllViable and botStopsActive', () => {
|
||||
assert.equal(botStopsActive({ firstDayStop: true, minDayStop: false, dailyLossLimit: 0 }), true);
|
||||
});
|
||||
|
||||
test('botStopsActive: the current stage\'s daily loss limit, which a stage may set on a type with none', () => {
|
||||
const cfg = { firstDayStop: false, minDayStop: false, dailyLossLimit: 0 };
|
||||
const stages = [{ profit: 3000, consistency: 0, minTradingDays: 0, dailyLossLimit: 3000 }];
|
||||
const paidOnce = [{ date: '2026-10-25', amount: -1500 }];
|
||||
// Stage 2 places its $3,000 stop: a red day there is the personal DLL.
|
||||
const stage2 = resolveEffectiveConfig(1500, 0, 0, false, stages, 0, paidOnce, 0, { dailyLossLimit: 0 });
|
||||
assert.equal(botStopsActive(cfg, stage2), true);
|
||||
// Stage 1 of the same type places none.
|
||||
assert.equal(botStopsActive(cfg, resolveEffectiveConfig(1500, 0, 0, false, stages, 0, [], 0, { dailyLossLimit: 0 })), false);
|
||||
// A stage that sets 0 lifts the type's limit.
|
||||
const lifted = resolveEffectiveConfig(1500, 0, 0, false, [{ ...stages[0], dailyLossLimit: 0 }], 0, paidOnce, 0, { dailyLossLimit: 1229 });
|
||||
assert.equal(botStopsActive({ ...cfg, dailyLossLimit: 1229 }, lifted), false);
|
||||
// The obfuscation stops count whatever the stage.
|
||||
assert.equal(botStopsActive({ ...cfg, minDayStop: true }, lifted), true);
|
||||
});
|
||||
|
||||
// ── sizing ───────────────────────────────────────────────────────────────────
|
||||
|
||||
const btcSigma = 0.03 / Math.sqrt(24); // 3%/day
|
||||
@@ -1268,3 +1284,77 @@ test('the engine says what each order is for, and both position-based clients go
|
||||
assert.match(src, /= orderEffect\(\{[^}]*\bintent\b[^}]*\}\) === 'close' \? held : undefined;/, `${file}: orderEffect doesn't pick the route`);
|
||||
}
|
||||
});
|
||||
|
||||
// The Vest 50k Funded type: $1,500 and claim it all, then $3,000 on the room
|
||||
// the claim freed — and every new day back at $1,500.
|
||||
const vestFunded = {
|
||||
profitTarget: 1500, consistency: 0, minDayPnL: 0, minTradingDays: 0, accountSize: 50000,
|
||||
targetSameEquity: false, splitEnabled: true, payoutable: true, tradesEveryDay: true, combineCmeHolidays: false,
|
||||
withdrawalStages: [{ profit: 3000, consistency: 0, minTradingDays: 0, dailyLossLimit: 3000 }],
|
||||
};
|
||||
const claimedBefore = [{ date: '2026-10-20', amount: 50000 }, { date: '2026-10-25', amount: -1500 }];
|
||||
|
||||
test('projectPerfectPath: a same-day type trades each projected day from the base stage, then its next stages that day', () => {
|
||||
const opts = {
|
||||
accountId: 7, cfg: vestFunded, cycleDailyPnL: [], fundTransactions: claimedBefore,
|
||||
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]);
|
||||
|
||||
// An earlier day's claim doesn't count: today and every day after it
|
||||
// make $1,500 on stage 1 and claim it, then $3,000 on stage 2 and claim
|
||||
// that — once through the stages a day.
|
||||
const fresh = projectPerfectPath({ ...opts, stageInputs: { dailyLossLimit: 1229, stagesSameDay: true, sameDayWithdrawals: 0 } });
|
||||
assert.deepEqual(firstOf(fresh, 5), [
|
||||
['2026-10-27', 1, -1500], ['2026-10-27', 2, -3000],
|
||||
['2026-10-28', 1, -1500], ['2026-10-28', 2, -3000],
|
||||
['2026-10-29', 1, -1500],
|
||||
]);
|
||||
|
||||
// Claimed once already today: today's cycle is stage 2's $3,000, tomorrow $1,500 and $3,000 again.
|
||||
const claimedToday = projectPerfectPath({ ...opts, stageInputs: { dailyLossLimit: 1229, stagesSameDay: true, sameDayWithdrawals: 1 } });
|
||||
assert.deepEqual(firstOf(claimedToday, 3), [['2026-10-27', 2, -3000], ['2026-10-28', 1, -1500], ['2026-10-28', 2, -3000]]);
|
||||
|
||||
// A cycle that stood complete yesterday is claimed today, so today trades stage 2.
|
||||
const unclaimed = projectPerfectPath({
|
||||
...opts, cycleDailyPnL: [{ date: '2026-10-26', pnl: 1500 }], balance: 51500,
|
||||
stageInputs: { dailyLossLimit: 1229, stagesSameDay: true, sameDayWithdrawals: 0 },
|
||||
});
|
||||
assert.deepEqual(firstOf(unclaimed, 3), [['2026-10-26', 1, -1500], ['2026-10-27', 2, -3000], ['2026-10-28', 1, -1500]]);
|
||||
|
||||
// Two listed stages: three payouts a day, and the day after starts over.
|
||||
const twoStages = projectPerfectPath({
|
||||
...opts, cfg: { ...vestFunded, withdrawalStages: [...vestFunded.withdrawalStages, { profit: 2000, consistency: 0, minTradingDays: 0 }] },
|
||||
maxWithdrawals: 10, stageInputs: { stagesSameDay: true, sameDayWithdrawals: 0 },
|
||||
});
|
||||
assert.deepEqual(firstOf(twoStages, 4).map(([date, stage]) => [date, stage]), [
|
||||
['2026-10-27', 1], ['2026-10-27', 2], ['2026-10-27', 3], ['2026-10-28', 1],
|
||||
]);
|
||||
|
||||
// Any other type counts every withdrawal, as it always has.
|
||||
const lifetime = projectPerfectPath(opts);
|
||||
assert.deepEqual(firstOf(lifetime, 3), [['2026-10-27', 2, -3000], ['2026-10-28', 3, -3000], ['2026-10-29', 4, -3000]]);
|
||||
assert.deepEqual(projectPerfectPath({ ...opts, stageInputs: { dailyLossLimit: 1229, stagesSameDay: false, sameDayWithdrawals: 0 } }), lifetime);
|
||||
});
|
||||
|
||||
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
|
||||
// claim ended that day's stage 1, not a $3,000 stage 2.
|
||||
const opts = {
|
||||
accountId: 7, rawTradeDate: '2026-10-26',
|
||||
fullDailyPnL: [{ date: '2026-10-25', pnl: 1500 }, { date: '2026-10-26', pnl: 1500 }],
|
||||
cycleDailyPnL: [],
|
||||
fundTransactions: [...claimedBefore, { date: '2026-10-26', amount: -1500 }],
|
||||
lastFundDate: '2026-10-26',
|
||||
endedCycleStart: { fundDate: '2026-10-25', includesDay: false },
|
||||
rawRealizedPnL: 0, equityProfit: 0,
|
||||
cfg: { ...vestFunded, stagesSameDay: true },
|
||||
now: cdt('2026-10-26T12:00:00'),
|
||||
};
|
||||
// Its stage stays the payout's number among the account's withdrawals,
|
||||
// which the master clears the entry by.
|
||||
assert.deepEqual(endedCycleCompletion(opts), { date: '2026-10-26', stage: 2, drain: false, cycle: '2026-10-25' });
|
||||
// Any other type: judged on stage 2's $3,000, as before.
|
||||
assert.equal(endedCycleCompletion({ ...opts, cfg: vestFunded }), null);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user