Merge branch 'vest-fix-intent' into vest-fixes
This commit is contained in:
+18
-7
@@ -28,7 +28,7 @@ import { POINT_VALUES, housekeepingRoot, HOUSEKEEPING_ROOT, MAX_HOLD_HOURS, futu
|
||||
import { firmInstruments, drawFuturesInstrument, spreadBlock, type LegShape } from './instruments';
|
||||
import { recordEntry } from './trade-mix';
|
||||
import { sizingHoldHours } from './person-size';
|
||||
import { errorMessage, isClientReady, isOrderNotPlaced, type PlatformClient, type PlatformContract, type PickContext } from './platform-client';
|
||||
import { errorMessage, isClientReady, isNothingToClose, isOrderNotPlaced, type PlatformClient, type PlatformContract, type PickContext } from './platform-client';
|
||||
|
||||
// ── process-wide state ───────────────────────────────────────────────────────
|
||||
|
||||
@@ -260,7 +260,10 @@ function unrecordLeg(accountId: number, tradeDate: string, legAmount: number): v
|
||||
* (OrderNotPlacedError). Anything ambiguous, like an ack or fill timeout,
|
||||
* keeps the leg: the order may well have filled, and a leg counted that never
|
||||
* happened only costs a leg, while one forgotten that did can trade the
|
||||
* account twice.
|
||||
* account twice. Open-only: where the platform checks (Vest, DXtrade), an
|
||||
* account that already holds the symbol — a hand trade the synced positions
|
||||
* don't show yet — is refused rather than having that position closed as the
|
||||
* "entry".
|
||||
*/
|
||||
async function sendEntry(
|
||||
tag: string,
|
||||
@@ -277,7 +280,7 @@ async function sendEntry(
|
||||
const at = Date.now();
|
||||
const realizedBefore = client.accountCashBalances[acc.id]?.realizedPnL ?? 0;
|
||||
try {
|
||||
const fill = await client.sendOrder(acc.id, contractName, contracts, action, 'Market');
|
||||
const fill = await client.sendOrder(acc.id, contractName, contracts, action, 'Market', undefined, 'open');
|
||||
outcomes.set(acc.id, { tradeDate, state: 'filled', at, realizedBefore, legAmount });
|
||||
return fill;
|
||||
} catch (err) {
|
||||
@@ -1240,10 +1243,10 @@ async function runTradeLocked(
|
||||
const mnqContract = await client.findFrontMonthContract(microRoot);
|
||||
if (!mnqContract) throw new Error(`${microRoot} contract not found for extra-day trade`);
|
||||
|
||||
const fill = await client.sendOrder(acc.id, mnqContract.name, 1, resolvedAction, 'Market');
|
||||
const fill = await client.sendOrder(acc.id, mnqContract.name, 1, resolvedAction, 'Market', undefined, 'open');
|
||||
recordEntry(item.firmName, microRoot, resolvedAction, 1, mnqContract.id);
|
||||
const exitAction: 'Buy' | 'Sell' = resolvedAction === 'Buy' ? 'Sell' : 'Buy';
|
||||
const exitFill = await client.sendOrder(acc.id, mnqContract.name, 1, exitAction, 'Market');
|
||||
const exitFill = await client.sendOrder(acc.id, mnqContract.name, 1, exitAction, 'Market', undefined, 'close');
|
||||
|
||||
console.log(`[auto-trade] ${acc.name} (${item.firmName}) extra-day: ${resolvedAction} 1x${mnqContract.name} @ ${fill.price} | exited @ ${exitFill.price} (market)`);
|
||||
|
||||
@@ -1303,7 +1306,11 @@ const round2 = (n: number) => Math.round(n * 100) / 100;
|
||||
* Close a just-filled position at market because it must not stay open — its
|
||||
* daily-loss stop has no room, or the broker refused its exit bracket — and
|
||||
* report the leg as failed. A flatten that fails too is the worst case: a
|
||||
* position with no stop, so it is shouted about.
|
||||
* position with no stop, so it is shouted about. Close-only: on an account
|
||||
* that turned out flat it must not open a fresh position with no exits, and
|
||||
* where the platform checks (Vest, DXtrade) and its own record agrees, that
|
||||
* flat account has nothing riding — the leg still fails, but without the
|
||||
* alarm. A flat read the record contradicts still gets the alarm.
|
||||
*/
|
||||
async function flattenAndFail(
|
||||
tag: string,
|
||||
@@ -1317,9 +1324,13 @@ async function flattenAndFail(
|
||||
why: string,
|
||||
): Promise<never> {
|
||||
try {
|
||||
const exit = await client.sendOrder(acc.id, contractName, contracts, exitAction, 'Market');
|
||||
const exit = await client.sendOrder(acc.id, contractName, contracts, exitAction, 'Market', undefined, 'close');
|
||||
console.warn(`${tag} ${acc.name}: flattened @ ${exit.price} — ${why}`);
|
||||
} catch (err) {
|
||||
if (isNothingToClose(err)) {
|
||||
console.warn(`${tag} ${acc.name}: nothing to flatten — ${errorMessage(err)} (${why})`);
|
||||
throw new Error(`entry filled @ ${entryPrice}; ${why}; already flat — nothing to flatten`);
|
||||
}
|
||||
console.error(`${tag} ${acc.name}: FLATTEN FAILED (${errorMessage(err)}) — the position may be open WITHOUT A STOP; close it at the broker (${why})`);
|
||||
throw new Error(`entry filled @ ${entryPrice}; ${why}; flatten failed — ${errorMessage(err)}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user