Sizing: the broker's largest and smallest order bind the leg's size
fireLeg clamped the order to the instrument's max and min size, but the size the pick ranked by (and the Firms page shows) didn't: an instrument whose largest order falls short of the ideal notional ranked on a hold it can't reach. planLegSize now holds the notional to the margin cap and the broker's largest order, then its smallest, so the ranking, the stats and the trade agree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7f55e49755
commit
1782c16145
+19
-4
@@ -1398,6 +1398,9 @@ export function sizeNotional(o: {
|
||||
financingPctPerDay?: number;
|
||||
/** Hard cap on the position (see notionalCap); 0 = none. */
|
||||
maxNotional: number;
|
||||
/** The smallest order the broker takes; 0 = none. It wins over the cap,
|
||||
* as the order does. */
|
||||
minNotional?: number;
|
||||
}): { notional: number; predictedHoldHours: number; winProbability: number | null; swapReserve: number } | null {
|
||||
const sigma = o.volatilityPerHour ?? 0;
|
||||
if (!(sigma > 0)) return null;
|
||||
@@ -1428,7 +1431,7 @@ export function sizeNotional(o: {
|
||||
n = Math.max(nTime, nCost);
|
||||
}
|
||||
if (!Number.isFinite(n) || n <= 0) return null;
|
||||
const notional = o.maxNotional > 0 ? Math.min(n, o.maxNotional) : n;
|
||||
const notional = Math.max(o.maxNotional > 0 ? Math.min(n, o.maxNotional) : n, o.minNotional ?? 0);
|
||||
const { a, b, stopped, swap } = distances(notional);
|
||||
return {
|
||||
notional,
|
||||
@@ -1448,10 +1451,19 @@ export function sizeNotional(o: {
|
||||
* the far side is the firm's own breach. `cost` is what the leg is expected
|
||||
* to spend: spread and both commissions on its notional, plus swap over its
|
||||
* expected hold.
|
||||
*
|
||||
* The size is held to what the order can be — the margin cap and the
|
||||
* broker's largest order, then its smallest — so the pick ranks each
|
||||
* instrument by the hold it can actually reach. `cap` is the margin cap
|
||||
* alone.
|
||||
*/
|
||||
export function planLegSize(o: {
|
||||
leg: number;
|
||||
contract: { stepNotional?: number; volatilityPerHour?: number; spreadFraction?: number; marginRate?: number };
|
||||
contract: {
|
||||
stepNotional?: number; volatilityPerHour?: number; spreadFraction?: number; marginRate?: number;
|
||||
/** The broker's largest and smallest order, in steps. */
|
||||
maxContracts?: number; minContracts?: number;
|
||||
};
|
||||
/** Per side, percent. */
|
||||
commissionPct: number;
|
||||
targetHoldHours: number;
|
||||
@@ -1481,7 +1493,9 @@ export function planLegSize(o: {
|
||||
: dllStopDollars({ room: o.dllRoom, dailyLossLimit: o.dailyLossLimit, entryFee: r * notional, commissionPct: o.commissionPct, notional }),
|
||||
);
|
||||
const cap = notionalCap({ marginRate: o.contract.marginRate, availableFunds: o.availableFunds });
|
||||
const sizing = (o.contract.stepNotional ?? 0) > 0
|
||||
const step = o.contract.stepNotional ?? 0;
|
||||
const orderMax = (o.contract.maxContracts ?? 0) > 0 ? o.contract.maxContracts! * step : 0;
|
||||
const sizing = step > 0
|
||||
? sizeNotional({
|
||||
leg: o.leg,
|
||||
stopDollarsAt: walkAt,
|
||||
@@ -1490,7 +1504,8 @@ export function planLegSize(o: {
|
||||
commissionPct: o.commissionPct,
|
||||
spreadFraction: o.contract.spreadFraction,
|
||||
financingPctPerDay: o.financingPctPerDay,
|
||||
maxNotional: cap,
|
||||
maxNotional: cap > 0 && orderMax > 0 ? Math.min(cap, orderMax) : cap || orderMax,
|
||||
minNotional: Math.max(1, o.contract.minContracts ?? 1) * step,
|
||||
})
|
||||
: null;
|
||||
const cost = sizing
|
||||
|
||||
Reference in New Issue
Block a user