Vest: stops reserve 0.02% of the position for slippage, not 0.1%

A platform may now state its own stop slippage share
(PlatformClient.stopSlippageFraction); the daily-loss reserve is the
larger of 10% of the limit and that share of the position. Vest's 9
measured stop-outs filled 0.9 points past the trigger on average and
2.25 at worst, against the ~30 points 0.1% held back. On a $1,400 day
with ~$495k of NDX the stop goes from ~$880 to ~$1,230, and the leg
sizes up for the same hold. Sizing, the placed stop, the dashboard's
next stop and the reset guard all use it; other platforms keep 0.1%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-10-27 11:34:27 -05:00
co-authored by Claude Opus 5.5
parent f0c1569d96
commit beddbdcf6c
11 changed files with 75 additions and 18 deletions
+39
View File
@@ -419,6 +419,21 @@ test('the daily-loss reserve grows with the position past 10% of the limit', ()
assert.equal(dllStopDollars({ room: 3000, dailyLossLimit: 3000, entryFee: 0, commissionPct: 0 }), 2699.99);
});
test('a platform whose stops fill closer reserves its own share of the position', () => {
// Me's Vest eval on 2026-10-27: $1,400 of room on $495,439 of NDX. At the
// 0.1% default the reserve is $495.44; at 0.02% the flat $140 binds.
const n = 495439;
assert.ok(Math.abs(dllReserve(1400, n) - 495.439) < 1e-9);
assert.equal(dllReserve(1400, n, 0.0002), 140);
assert.ok(Math.abs(dllReserve(1400, 900000, 0.0002) - 180) < 1e-9, 'past $700k the share binds again');
// Left out, or not a share at all: the default.
for (const bad of [undefined, NaN, -0.0002, Infinity]) assert.equal(dllReserve(1400, n, bad), dllReserve(1400, n), String(bad));
assert.equal(dllReserve(1400, n, 0), 140, 'no slippage at all still keeps the flat 10%');
const stop = (slippageFraction) => dllStopDollars({ room: 1400, dailyLossLimit: 1400, entryFee: 12.45, commissionPct: 0, notional: n, slippageFraction });
assert.ok(Math.abs(stop(undefined) - (1400 - 495.439 - 24.9 - 0.01)) < 1e-9);
assert.ok(Math.abs(stop(0.0002) - (1400 - 140 - 24.9 - 0.01)) < 1e-9);
});
test('max-drawdown room: the static floor, the broker floor, the higher', () => {
assert.equal(maxLossRoom({ balance: 99757.39, accountSize: 100000, maxLoss: 6000 }), 5757.39);
assert.equal(maxLossRoom({ balance: 99757.39, accountSize: 100000, maxLoss: -6000 }), 5757.39);
@@ -531,6 +546,30 @@ test('planLegSize: a split day\'s next leg, with the day\'s gain on its stop, si
assert.ok(widened.walkAt(n) > 2604.24 && widened.walkAt(n) < 4004.24, `stop ${widened.walkAt(n)}`);
});
test('planLegSize: a platform\'s own slippage share widens the stop and sizes the leg up for the same hold', () => {
// Me's first-day Vest eval leg on 2026-10-27: $5,000 to pass, $1,400 of
// room, NDX at ~$29.8k, sized for 2.6 h.
const ndx = { stepNotional: 2.98, volatilityPerHour: 0.0131 / Math.sqrt(24), spreadFraction: 0.0000085, marginRate: 0.02 };
const leg = {
leg: 5000, contract: ndx, commissionPct: 0.0025, targetHoldHours: 2.6, financingPctPerDay: 0,
dailyLossLimit: 1400, dllRoom: 1400, obfuscationDollars: Infinity, availableFunds: 50000, maxLossRoom: 3000,
};
const deflt = planLegSize(leg);
const vest = planLegSize({ ...leg, slippageFraction: 0.0002 });
assert.equal(planLegSize({ ...leg, slippageFraction: undefined }).sizing.notional, deflt.sizing.notional);
for (const p of [deflt, vest]) {
assert.equal(p.lastStand, false);
assert.ok(Math.abs(p.sizing.predictedHoldHours - 2.6) < 0.05, `hold ${p.sizing.predictedHoldHours}`);
}
const r = 0.0025 / 100;
const nd = deflt.sizing.notional, nv = vest.sizing.notional;
assert.ok(Math.abs(deflt.walkAt(nd) - (1400 - 0.001 * nd - 2 * r * nd - 0.01) / (1 + r)) < 1e-9);
assert.ok(Math.abs(vest.walkAt(nv) - (1400 - 140 - 2 * r * nv - 0.01) / (1 + r)) < 1e-9, 'the flat $140 binds');
assert.ok(vest.walkAt(nv) > 1200 && deflt.walkAt(nd) < 950, `stops ${vest.walkAt(nv)} vs ${deflt.walkAt(nd)}`);
assert.ok(nv > 1.1 * nd, `${nv} vs ${nd}`);
assert.ok(vest.sizing.winProbability > deflt.sizing.winProbability);
});
test('personSizeFactor: one draw per person and trade date, within the spread', () => {
const people = Array.from({ length: 300 }, (_, i) => `0b6f${i.toString(16).padStart(4, '0')}-5c1e-4a7e-9d2b-${i}`);
const draws = people.map((p) => personSizeFactor(p, '2026-10-20'));