Merge branch 'vest-fix-intent' into vest-fixes

This commit is contained in:
Brandon Li
2026-10-27 14:51:36 -05:00
5 changed files with 186 additions and 26 deletions
+14 -9
View File
@@ -46,8 +46,8 @@ import {
} from './db';
import { getCachedFirm } from './firm-catalog';
import { firmInstruments } from './instruments';
import type { PlatformClient, PlatformAccount, PlatformContract, ClientHealth, PickContext } from './platform-client';
import { OrderNotPlacedError, isOrderNotPlaced, errorMessage } from './platform-client';
import type { PlatformClient, PlatformAccount, PlatformContract, ClientHealth, PickContext, OrderIntent } from './platform-client';
import { OrderNotPlacedError, isOrderNotPlaced, errorMessage, orderEffect } from './platform-client';
import { encodeContractName, decodeContractName, roundToStep, scoreCandidate } from './dxtrade-helpers';
import { vestSessionFor, dropVestSession, listVestSessions, refuseVestSession } from './vest-session';
import {
@@ -1792,10 +1792,11 @@ export class VestClient implements PlatformClient {
/**
* Place an order and wait for its fill: an open when the account is flat,
* a close (or reduce) of the position when it holds the opposite side.
* Adding to a position is refused, and so is an open against another
* account's opposite position in the same symbol (no hedging). Resolves
* with the fill `price`.
* a close (or reduce) of the position when it holds the opposite side —
* only the one `intent` names, when given (orderEffect). Adding to a
* position is refused, and so is an open against another account's
* opposite position in the same symbol (no hedging). Resolves with the
* fill `price`.
*/
public async sendOrder(
accountId: number,
@@ -1804,9 +1805,10 @@ export class VestClient implements PlatformClient {
action: 'Buy' | 'Sell',
orderType: 'Market' | 'Limit',
price?: number,
intent?: OrderIntent,
): Promise<Record<string, unknown>> {
try {
return await this.sendOrderAndWait(accountId, contractSymbol, quantity, action, orderType, price);
return await this.sendOrderAndWait(accountId, contractSymbol, quantity, action, orderType, price, intent);
} catch (err) {
if (!isOrderNotPlaced(err)) this.suspectAccounts.set(accountId, Date.now());
throw err;
@@ -1820,6 +1822,7 @@ export class VestClient implements PlatformClient {
action: 'Buy' | 'Sell',
orderType: 'Market' | 'Limit',
price?: number,
intent?: OrderIntent,
): Promise<Record<string, unknown>> {
const { uuid, symbol, step, spec } = this.orderContext(accountId, contractSymbol);
const side: 'long' | 'short' = action === 'Buy' ? 'long' : 'short';
@@ -1829,8 +1832,10 @@ export class VestClient implements PlatformClient {
} catch (err) {
throw new OrderNotPlacedError(`Vest position check failed — order not sent: ${errorMessage(err)}`);
}
const existing = positions.find((p) => p.symbol === symbol);
if (existing && existing.side === side) throw new OrderNotPlacedError(`adding to an open ${symbol} position is not supported`);
const held = positions.find((p) => p.symbol === symbol);
const recorded = this.positionsDetail.get(accountId)?.find((p) => p.symbol === symbol)?.side ?? null;
// orderEffect picks open or close; `existing` is the position a close closes.
const existing = orderEffect({ symbol, held: held?.side ?? null, recorded, side, intent }) === 'close' ? held : undefined;
const units = roundToStep(contracts * step, step);
const qty = (n: number) => formatDecimal(n, spec.sizeDecimals);