Tradeify247: each person sizes a little apart from everyone else
Every machine sized a like account in a like state to the same position as every other person's, so two people's positions could match to the unit. Each person now draws a size factor in [0.85, 1.15] per trade date, seeded by the master's uuid for them; all of one person's accounts share it. The factor moves the hold a DXtrade leg is sized for (hold / factor², since size goes as 1/√hold), so the instrument pick, the dashboard's next leg and the Firms page's reach test all see the hold the size was made for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ed56e306d1
commit
6dd2528fe2
@@ -13,7 +13,7 @@ import {
|
||||
botStopsActive, sizeNotional, isNoTradeTime, isPastSessionClose, nextTradingDate, effectiveCombine, DEFAULT_TARGET_HOLD_HOURS,
|
||||
projectPerfectPath, cycleCompletion, 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,
|
||||
currentTradeDateCT, foldReason, withinFirmCaps, personSizeFactor, personHoldHours, PERSON_SIZE_SPREAD,
|
||||
} from '../lib/trading-logic.ts';
|
||||
|
||||
// Deterministic PRNG so a failure reproduces.
|
||||
@@ -475,6 +475,49 @@ test('planLegSize: the stop, a last stand, the margin cap and the cost, as fireL
|
||||
assert.equal(planLegSize({ ...base, maxLossRoom: null, contract: {} }).sizing, null);
|
||||
});
|
||||
|
||||
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'));
|
||||
for (const f of draws) assert.ok(f >= 1 - PERSON_SIZE_SPREAD && f <= 1 + PERSON_SIZE_SPREAD, `factor ${f}`);
|
||||
// Spread over the whole range, not bunched at 1.
|
||||
assert.ok(Math.min(...draws) < 0.88 && Math.max(...draws) > 1.12, `${Math.min(...draws)}–${Math.max(...draws)}`);
|
||||
// Repeatable, so every sizing of the day agrees.
|
||||
assert.equal(personSizeFactor(people[0], '2026-10-20'), draws[0]);
|
||||
// Two people land within half a percent of each other about as often as
|
||||
// uniform draws do (2 × 0.005 / 0.3 ≈ 3%), not bunched together.
|
||||
const close = draws.filter((f, i) => i > 0 && Math.abs(f - draws[i - 1]) < 0.005).length;
|
||||
assert.ok(close < draws.length * 0.08, `${close} near-identical neighbours`);
|
||||
// A new trade date, a new draw: a month of one person's days covers the
|
||||
// range too, not a slow drift (the next date differs in its last digit).
|
||||
const days = Array.from({ length: 30 }, (_, i) => personSizeFactor(people[0], `2026-11-${String(i + 1).padStart(2, '0')}`));
|
||||
assert.ok(Math.max(...days) - Math.min(...days) > PERSON_SIZE_SPREAD, `days span ${Math.min(...days)}–${Math.max(...days)}`);
|
||||
const steps = days.slice(1).map((f, i) => Math.abs(f - days[i]));
|
||||
assert.ok(steps.reduce((a, b) => a + b, 0) / steps.length > 0.05, 'day to day the draw should jump, not creep');
|
||||
});
|
||||
|
||||
test('personHoldHours: the size comes out the person\'s factor times the plan, at the hold it was sized for', () => {
|
||||
const eth = { stepNotional: 26.86, volatilityPerHour: 0.022 / Math.sqrt(24), spreadFraction: 0.00004, marginRate: 0.2 };
|
||||
const base = {
|
||||
leg: 12239, contract: eth, commissionPct: 0.04, targetHoldHours: 12, financingPctPerDay: 0.033,
|
||||
dailyLossLimit: 3000, dllRoom: 2757.39, maxLossRoom: 5757.39, obfuscationDollars: Infinity, availableFunds: 99757.39,
|
||||
};
|
||||
const plan = planLegSize(base).sizing;
|
||||
for (const person of ['me-uuid', 'nik-uuid', 'ahmad-uuid', 'ziad-uuid']) {
|
||||
const factor = personSizeFactor(person, '2026-10-20');
|
||||
const hold = personHoldHours(12, person, '2026-10-20');
|
||||
const sized = planLegSize({ ...base, targetHoldHours: hold }).sizing;
|
||||
// Fees and the daily-loss stop move a little with the size, so the
|
||||
// ratio sits a touch nearer 1 than the factor.
|
||||
const ratio = sized.notional / plan.notional;
|
||||
assert.ok(Math.abs(ratio - factor) < 0.02, `${person}: ×${ratio.toFixed(4)} vs factor ${factor.toFixed(4)}`);
|
||||
assert.ok((ratio - 1) * (factor - 1) > 0, `${person}: moved the wrong way`);
|
||||
// The pick ranks against this hold, and the size reaches it.
|
||||
assert.ok(Math.abs(sized.predictedHoldHours - hold) < 0.1, `${person}: ${sized.predictedHoldHours}h vs ${hold}h`);
|
||||
}
|
||||
// No firm hold: the default, moved the same way.
|
||||
assert.equal(personHoldHours(0, 'me-uuid', '2026-10-20'), personHoldHours(DEFAULT_TARGET_HOLD_HOURS, 'me-uuid', '2026-10-20'));
|
||||
});
|
||||
|
||||
test('planLegSize: the broker\'s order size limits bind the sizing, so the pick sees the real hold', () => {
|
||||
const eth = { stepNotional: 26.86, volatilityPerHour: 0.022 / Math.sqrt(24), spreadFraction: 0.00004, marginRate: 0.2 };
|
||||
const base = {
|
||||
|
||||
Reference in New Issue
Block a user