Vest: no leg opens into a market close, and accounts plan on Vest's day
Market close: a Vest entry now needs its symbol's market to stay open for RESET_CLEAR_HOLDS holds of the leg (clearsClose), the clearance the 8 PM ET reset already gets: at the target hold, and at the leg's sized hold when a leverage cap stretches it. That covers the weekly close and the daily maintenance hour as Vest's market-hours periods list them. Before a closure that runs past an 8 PM ET reset (the weekend, a holiday: longClosure), the bot's own legs still open in the last 5 minutes are closed at market, loudly; a position the bot didn't open is named in the log and left alone. Vest's day: Vest accounts are planned, and their legs and entries counted, on Vest's day (20:00 ET) instead of the Central date (tradeDateFor, PlatformClient.tradeDate). Between 5 PM CT and the reset the Central date counted the open Vest day as a prior day and as today's realized P&L both ($3,000 to go, $800 made: $2,050 left, not $1,900) and started the leg count over. Other platforms keep the Central date. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
beddbdcf6c
commit
ec3e6ea388
+11
-9
@@ -11,7 +11,7 @@ import { getClients } from './clients';
|
||||
import { getCachedFirm, getTradableFirms } from './firm-catalog';
|
||||
import { ensureRulesEvidence, getAccountConfig } from './account-type-resolver';
|
||||
import {
|
||||
combineCmeSessions, computeDayPlan, groupLegFraction, pickLegAmount, resolveEffectiveConfig, currentTradeDateCT,
|
||||
combineCmeSessions, computeDayPlan, groupLegFraction, pickLegAmount, resolveEffectiveConfig, tradeDateFor,
|
||||
obfuscationStopDollars, takeProfitPlan, onTick, percentFee, dllRoom, dllStopDollars, dllViable, stopTicks,
|
||||
expectedSwapToWin, planLegSize, maxLossRoom, breachDistance,
|
||||
isNoTradeTime, isPastSessionClose,
|
||||
@@ -1043,7 +1043,10 @@ async function runTradeLocked(
|
||||
// operator's pick; 'Auto' is drawn per batch from the batch firm's list.
|
||||
const explicit = futuresLane && symbol !== 'Auto' ? symbol : null;
|
||||
|
||||
const tradeDate = currentTradeDateCT();
|
||||
// The lane's own day (tradeDateFor): a notional lane is one firm — a
|
||||
// Vest lane's day turns at 20:00 ET, its rows and realized P&L with it —
|
||||
// and the futures lane's clients all keep the Central trade date.
|
||||
const tradeDate = tradeDateFor(open[0]?.client);
|
||||
const maxConcurrent = maxConcurrentAccounts();
|
||||
|
||||
// ── Phase 1: the eligible accounts across the lane's firms ──
|
||||
@@ -1742,7 +1745,8 @@ async function copyTradeLocked(lease: number, lane: string): Promise<unknown[]>
|
||||
return [];
|
||||
}
|
||||
|
||||
const tradeDate = currentTradeDateCT();
|
||||
// The lane's own day, as in runTrade.
|
||||
const tradeDate = tradeDateFor(ready[0]?.client);
|
||||
|
||||
// Collect eligible accounts (same logic as Phase 1 of runTrade)
|
||||
const eligible: LegItem[] = [];
|
||||
@@ -1860,7 +1864,7 @@ export async function fireManualLeg(accountId: number, action: 'Buy' | 'Sell' |
|
||||
const lease = acquireTradeMutex('[manual-leg]', lane);
|
||||
if (lease === null) throw new Error('another batch is in flight in this lane');
|
||||
try {
|
||||
const tradeDate = currentTradeDateCT();
|
||||
const tradeDate = tradeDateFor(client);
|
||||
const ev = evaluateAccountForTrade(client, acc, tradeDate);
|
||||
if (!ev || !ev.plan) throw new Error(ev?.reason || 'account has no account type');
|
||||
if (!ev.eligible && !ev.reason.startsWith('already traded today')) throw new Error(ev.reason);
|
||||
@@ -1986,7 +1990,6 @@ async function runClaims(lane: string, ready: FirmClient[]): Promise<void> {
|
||||
const lease = acquireTradeMutex('[auto-claim]', lane);
|
||||
if (lease === null) return;
|
||||
try {
|
||||
const tradeDate = currentTradeDateCT();
|
||||
for (const { firm, client, acc } of due) {
|
||||
if (!holdsTradeMutex(lease, lane)) return;
|
||||
// Settled since, or a different amount now: claim what is due now.
|
||||
@@ -1996,7 +1999,7 @@ async function runClaims(lane: string, ready: FirmClient[]): Promise<void> {
|
||||
// In flight while it claims: a batch that takes over a wedged
|
||||
// lane, or a Claim now, leaves the account alone.
|
||||
const { claimed, received } = await withAccountInFlight(acc.id, () => client.claimProfit!(acc.id, amount));
|
||||
afterClaim('[auto-claim]', firm, client, acc, claimed, received, tradeDate);
|
||||
afterClaim('[auto-claim]', firm, client, acc, claimed, received, tradeDateFor(client));
|
||||
} catch (err) {
|
||||
(runtime().claimFailedAt ??= new Map()).set(acc.id, Date.now());
|
||||
console.error(`[auto-claim] ${firm.name} ${acc.name}: claim of $${Math.floor(amount * 100) / 100} failed — ${errorMessage(err)}; retrying in ${CLAIM_RETRY_MS / 60_000}m`);
|
||||
@@ -2130,7 +2133,7 @@ export async function claimAccountNow(accountId: number, amount: number): Promis
|
||||
if (!(amount >= 1)) throw new ClaimRefusedError(`$${amount} is below the $1 minimum claim`);
|
||||
if (amount > c.amount + 0.005) throw new ClaimRefusedError(`only $${c.amount.toFixed(2)} is claimable now`);
|
||||
const { claimed, received } = await withAccountInFlight(c.acc.id, () => c.client.claimProfit!(c.acc.id, amount));
|
||||
const stage = afterClaim('[claim-now]', c.firm, c.client, c.acc, claimed, received, currentTradeDateCT());
|
||||
const stage = afterClaim('[claim-now]', c.firm, c.client, c.acc, claimed, received, tradeDateFor(c.client));
|
||||
return { claimed, received, stage };
|
||||
} finally {
|
||||
releaseTradeMutex(lease, lane);
|
||||
@@ -2142,7 +2145,6 @@ export async function claimAccountNow(accountId: number, amount: number): Promis
|
||||
/** Returns true if any configured account could still trade today (eligible for a next leg / extra-day, or has an open position). */
|
||||
function hasRemainingConfiguredAccounts(): boolean {
|
||||
const { ready, unready } = firmClients();
|
||||
const tradeDate = currentTradeDateCT();
|
||||
|
||||
// A client that isn't ready can't say whether its accounts are done — its
|
||||
// snapshot is missing or stale — so while one might hold any of ours, the
|
||||
@@ -2175,7 +2177,7 @@ function hasRemainingConfiguredAccounts(): boolean {
|
||||
// Order being placed right now = still in play (evaluation calls it ineligible)
|
||||
if (runtime().accountsInFlight.has(acc.id)) return true;
|
||||
|
||||
const ev = evaluateAccountForTrade(client, acc, tradeDate);
|
||||
const ev = evaluateAccountForTrade(client, acc, tradeDateFor(client));
|
||||
if (ev?.eligible) return true;
|
||||
// Waiting on its history (or its day-start balance), not done: it may
|
||||
// still owe today's trade — during the session and before it opens
|
||||
|
||||
Reference in New Issue
Block a user