Vest: a crypto leg's stop holds back the engine's default slippage, not NDX's
Crypto (exchangeInfo asset "crypto": BTC, ETH, SOL, HYPE) trades on weekends when NDX, SPX and GC are shut, but its stop slippage on Vest is unmeasured, and its book is a fraction of NDX's: about $10M an hour on a weekend against $600M, with a batch's stops firing together. Its stops now leave 0.1% of the position unspent (the engine's default) instead of the 0.02% measured on NDX stop-outs; every other symbol keeps 0.02%. The share rides on the picked contract and is used wherever a Vest leg's stop is sized: the batch's plan, the leg's own stop, the dashboard's next stop, and the 7:55 PM ET reset guard, which now sums each open position's own share. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
618976bf5f
commit
10da0ca83e
+12
-5
@@ -53,7 +53,7 @@ import { vestSessionFor, dropVestSession, listVestSessions, refuseVestSession }
|
||||
import {
|
||||
vestAccountId, vestAccountName, vestDayOf, lastVestResetMs, nextVestResetMs, parseCapitalAccount, parsePosition, parseOpenOrder,
|
||||
parseTxn, bookTxns, awaitingLegs, unknownOpenFill, unrealizedPnl, hourlyVolatility, marketOpen, longClosure, num, toMs, formatDecimal, resetSafeStop,
|
||||
parseHistoryPosition, jwtClaimStrings, accountScopedToken, VEST_STATUS_ACTIVE, VEST_STOP_SLIPPAGE_FRACTION,
|
||||
parseHistoryPosition, jwtClaimStrings, accountScopedToken, VEST_STATUS_ACTIVE, VEST_STOP_SLIPPAGE_FRACTION, vestStopSlippageFraction,
|
||||
vestStatusName, awaitingActivation,
|
||||
VestApiError, VestNotSentError, nothingWentIn, tokenForRequest, settleClaims, readClaims, payoutDaysOf, payoutsSince,
|
||||
} from './vest-helpers';
|
||||
@@ -155,6 +155,9 @@ interface SymbolSpec {
|
||||
marginRate: number;
|
||||
tradingStatus: string;
|
||||
capitalTradingStatus: string;
|
||||
/** exchangeInfo's asset class: "crypto", "forex", "stock" (indices and
|
||||
* commodities too). */
|
||||
asset: string;
|
||||
}
|
||||
|
||||
export interface VestConfig {
|
||||
@@ -558,6 +561,7 @@ export class VestClient implements PlatformClient {
|
||||
marginRate: capitalIm && capitalIm > 0 ? capitalIm : 0,
|
||||
tradingStatus: String(s.tradingStatus ?? ''),
|
||||
capitalTradingStatus: String(s.capitalTradingStatus ?? s.tradingStatus ?? ''),
|
||||
asset: String(s.asset ?? ''),
|
||||
});
|
||||
}
|
||||
if (next.size > 0) {
|
||||
@@ -1230,13 +1234,15 @@ export class VestClient implements PlatformClient {
|
||||
|| (x.currentStop !== null && y.currentStop !== null ? lossAt(x.pos, x.currentStop) - lossAt(y.pos, y.currentStop) : 0)
|
||||
|| x.pos.openedAt - y.pos.openedAt || x.pos.positionId.localeCompare(y.pos.positionId));
|
||||
let committed = 0;
|
||||
let notionalSoFar = 0;
|
||||
// The slippage reserve the positions so far hold together, in
|
||||
// dollars: each its own symbol's share of its notional.
|
||||
let slippageSoFar = 0;
|
||||
for (const { pos, currentStop } of held) {
|
||||
const spec = specs.get(pos.symbol);
|
||||
if (!spec) {
|
||||
// Can't be fitted without its tick, but it still holds
|
||||
// its loss against the room the others share.
|
||||
notionalSoFar += pos.quantity * pos.openPrice;
|
||||
slippageSoFar += this.stopSlippageFraction * pos.quantity * pos.openPrice;
|
||||
if (currentStop !== null) committed += lossAt(pos, currentStop);
|
||||
else if (!guard.unfittable.has(pos.positionId)) {
|
||||
guard.unfittable.add(pos.positionId);
|
||||
@@ -1248,13 +1254,13 @@ export class VestClient implements PlatformClient {
|
||||
const mark = this.marks.get(pos.symbol)?.mark ?? NaN;
|
||||
const stopLeg = pos.stopLosses.find((l) => l.status === 'awaiting') ?? null;
|
||||
const notional = pos.quantity * (Number.isFinite(mark) ? mark : pos.openPrice);
|
||||
notionalSoFar += notional;
|
||||
slippageSoFar += vestStopSlippageFraction(spec.asset) * notional;
|
||||
const exitFee = spec.takerFee * notional;
|
||||
const decision = resetSafeStop({
|
||||
side: pos.side, quantity: pos.quantity, openPrice: pos.openPrice, mark,
|
||||
balance: cash.amount - committed, dailyLossPct: a.maxDailyLossPct, maxDrawdownFloor: a.maxDrawdownLimit,
|
||||
floorBalance: cash.amount,
|
||||
reserve: dllReserve(cash.amount * a.maxDailyLossPct, notionalSoFar, this.stopSlippageFraction),
|
||||
reserve: dllReserve(cash.amount * a.maxDailyLossPct, slippageSoFar, 1),
|
||||
exitFeeRate: spec.takerFee, currentStop, tick: spec.tick,
|
||||
});
|
||||
const stopAt = decision.action === 'stop' ? decision.price : decision.action === 'none' ? currentStop : null;
|
||||
@@ -2022,6 +2028,7 @@ export class VestClient implements PlatformClient {
|
||||
minContracts: 1,
|
||||
marginRate: spec.marginRate || undefined,
|
||||
closesAt: gateAt ?? undefined,
|
||||
stopSlippageFraction: vestStopSlippageFraction(spec.asset),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user