DXtrade: an entry never closes a hand trade, and a flatten never opens one

DXtrade dropped the intent the engine now passes, so on the live
Tradeify247 accounts an entry could still close a hand position as the
"entry" and the leg's flatten then OPEN a position with no exits. The
open/close decision moves out of vest-helpers into platform-client's
orderEffect, which both clients now follow to pick OPEN or CLOSE.

A flatten's flat read is "nothing to flatten" only when the client's own
record agrees. One empty read just after a fill the client saw may be the
gateway lagging, so it stays a plain refusal and keeps the FLATTEN FAILED
alarm. A check now fails if an engine order drops its intent or a client
stops going by orderEffect.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-10-27 14:13:07 -05:00
co-authored by Claude Opus 5.5
parent e90f21ed91
commit 378530595e
7 changed files with 147 additions and 94 deletions
+3 -40
View File
@@ -1,6 +1,5 @@
// Checks for the Vest client's pure helpers (lib/vest-helpers.ts), the
// relayed-session store (lib/vest-session.ts) and the order refusals it
// throws (lib/platform-client.ts).
// Checks for the Vest client's pure helpers (lib/vest-helpers.ts) and the
// relayed-session store (lib/vest-session.ts).
//
// npm run check
//
@@ -13,10 +12,9 @@ import {
isVestWalletAddress, vestAccountId, num, toMs, formatDecimal, vestDayOf, lastVestResetMs, parseCapitalAccount,
vestAccountName, parsePosition, awaitingLegs, parseOpenOrder, unrealizedPnl, parseTxn, bookTxns, txnKind, VEST_TXN,
hourlyVolatility, marketOpen, MIN_HOURLY_RETURNS, nextVestResetMs, resetSafeStop, parseHistoryPosition, jwtClaimStrings,
accountScopedToken, vestOrderEffect,
accountScopedToken,
} from '../lib/vest-helpers.ts';
import { putVestSession, vestSessionFor, dropVestSession, listVestSessions, refuseVestSession } from '../lib/vest-session.ts';
import { OrderNotPlacedError, NothingToCloseError, isOrderNotPlaced, isNothingToClose } from '../lib/platform-client.ts';
const iso = (s) => Date.parse(s);
@@ -144,41 +142,6 @@ test('positions, their legs and unrealized P&L', () => {
assert.equal(parseOpenOrder({ symbol: 'x' }), null);
});
test('an entry never closes a position, a flatten never opens one', () => {
const effect = (held, side, intent) => vestOrderEffect({ symbol: 'NDX-USD-PERP', held, side, intent });
// No intent: the position decides, as before (the manual order route).
assert.deepEqual(effect(null, 'long'), { effect: 'open' });
assert.deepEqual(effect('short', 'long'), { effect: 'close' });
assert.match(effect('long', 'long').refused, /adding to an open NDX-USD-PERP position/);
// An entry on an account that already holds the symbol — a hand short the
// engine's synced positions didn't show yet — is refused, not turned into
// a close of that short.
assert.deepEqual(effect(null, 'long', 'open'), { effect: 'open' });
const entry = effect('short', 'long', 'open');
assert.match(entry.refused, /short NDX-USD-PERP position is already open/);
assert.equal(entry.nothingToClose, undefined);
assert.match(effect('long', 'long', 'open').refused, /adding to an open/);
// A flatten closes the leg it was sent for; on a flat account it opens
// nothing and says there is nothing to close.
assert.deepEqual(effect('long', 'short', 'close'), { effect: 'close' });
const flat = effect(null, 'short', 'close');
assert.match(flat.refused, /no NDX-USD-PERP position to close/);
assert.equal(flat.nothingToClose, true);
// Holding the flatten's own side is not the leg: refused, and not "flat".
const wrong = effect('short', 'short', 'close');
assert.match(wrong.refused, /holds a short NDX-USD-PERP position, not one to close/);
assert.equal(wrong.nothingToClose, undefined);
// The refusal the client throws for it: still "never placed" (the leg is
// un-counted), and told apart from every other refusal.
const nothing = new NothingToCloseError('no NDX-USD-PERP position to close — nothing sent');
assert.equal(isOrderNotPlaced(nothing), true);
assert.equal(isNothingToClose(nothing), true);
assert.equal(isNothingToClose(new OrderNotPlacedError('Vest refused the order: 400')), false);
assert.equal(isNothingToClose(new Error('outcome unknown')), false);
assert.equal(isNothingToClose(undefined), false);
});
test('transactions book into daily P&L and fund rows by Vest day', () => {
assert.equal(txnKind(VEST_TXN.FEE), 'trade');
assert.equal(txnKind(VEST_TXN.REALIZED_PNL), 'trade');