diff --git a/lib/auto-trade.ts b/lib/auto-trade.ts index 6eb90df..fdb25d6 100644 --- a/lib/auto-trade.ts +++ b/lib/auto-trade.ts @@ -18,7 +18,7 @@ import { BIG_DAY_THRESHOLD, LEG_COMPLETION_EPSILON, MAX_LEGS_PER_DAY, FALLBACK_COMMISSION_PER_CONTRACT, MAX_COMMISSION_PER_CONTRACT, DLL_MIN_STOP, CME_EVENING_OPEN_MIN, foldReason, withinFirmCaps, - fundRowsKey, markFinishedCycle, unbookedPayoutDrop, machineSide, stageInputsFor, floorRoom, shortestNextLeg, + fundRowsKey, markFinishedCycle, unbookedPayoutDrop, machineSide, stageInputsFor, stagePayouts, floorRoom, shortestNextLeg, claimedCycle, withinEndedCycleWindow, type DayPlan, type FinishedCycleMark, type ClaimedCycle, } from './trading-logic'; @@ -2099,7 +2099,9 @@ function afterClaim( console.error(`${tag} ${firm.name} ${acc.name}: the completed cycle the claim ended wasn't saved — ${errorMessage(err)}`); } } - const stage = 1 + (client.sameDayClaims?.(acc.id) ?? 0); + // The stage the engine trades next, counted as it counts it (stagePayouts). + const cfg = getAccountConfig(acc.id).accountType; + const stage = 1 + stagePayouts(client.fundTransactions?.[acc.id] ?? [], cfg ? stageInputsFor(client, acc.id, cfg) : {}); console.log(`${tag} ${firm.name} ${acc.name}: claimed $${claimed}${received !== null ? ` (you get $${received})` : ''}` + ` — trading stage ${stage} next (${tradeDate})`); return stage; diff --git a/lib/vest-class.ts b/lib/vest-class.ts index b0af2a9..83d4d8e 100644 --- a/lib/vest-class.ts +++ b/lib/vest-class.ts @@ -777,6 +777,13 @@ export class VestClient implements PlatformClient { return vestDayOf(this.numbersAt > 0 ? Math.min(now, this.numbersAt) : now); } + /** Past 8 PM ET with the numbers still the ended day's: a leg opened now + * would be planned and counted on that day, so none opens until a sync + * has read the new one. */ + private newDayUnread(now: number): boolean { + return this.tradeDate(now) !== vestDayOf(now); + } + /** * See PlatformClient: the gain since the day's base that is still in the * account — since this client's own claim today, else since the reset, @@ -1766,6 +1773,10 @@ export class VestClient implements PlatformClient { console.log(`${this.tag} ${root} → nothing tradable — Vest's 8 PM ET reset in ${Math.ceil(toReset / 60_000)} min`); return null; } + if (root !== 'survey' && this.newDayUnread(now)) { + console.log(`${this.tag} ${root} → nothing tradable — Vest's day has turned and no sync has read it yet`); + return null; + } for (const symbol of symbols) { const spec = specs.get(symbol); if (!spec) { board.push({ symbol, score: null, note: 'unknown symbol' }); continue; } @@ -1963,6 +1974,9 @@ export class VestClient implements PlatformClient { if (toReset <= RESET_ENTRY_BLOCK_MS) { throw new OrderNotPlacedError(`Vest's 8 PM ET reset is ${Math.ceil(toReset / 60_000)} min away — no new position until it passes`); } + if (this.newDayUnread(Date.now())) { + throw new OrderNotPlacedError(`Vest's day has turned and no sync has read it yet — no new position until one has`); + } const opposite = side === 'long' ? 'short' : 'long'; const hedged = [...this.positionsDetail.values()].flat().some((p) => p.symbol === symbol && p.side === opposite) || this.openingSides.get(symbol)?.side === opposite; diff --git a/scripts/check-vest-client.mjs b/scripts/check-vest-client.mjs index 95b09cd..7db0e47 100644 --- a/scripts/check-vest-client.mjs +++ b/scripts/check-vest-client.mjs @@ -58,7 +58,7 @@ const { const { vestDayOf, vestAccountId, VestApiError, VEST_STATUS_ACTIVE } = await import('../lib/vest-helpers.ts'); const { encodeContractName } = await import('../lib/dxtrade-helpers.ts'); const { tradeDateFor, stageInputsFor, resolveEffectiveConfig, claimedCycle, endedCycleCompletion } = await import('../lib/trading-logic.ts'); -const { isClientReady } = await import('../lib/platform-client.ts'); +const { isClientReady, isOrderNotPlaced } = await import('../lib/platform-client.ts'); const iso = (s) => Date.parse(s); const WALLET = '0x7ce10771819f80130e204ddb5ca1522e48a9b451'; @@ -383,6 +383,10 @@ test("the client's Vest day turns with its numbers, and a sync that stalls stops assert.equal(vestDayOf(Date.now()), '2026-10-28'); assert.equal(engineDay(), '2026-10-27'); assert.equal(isClientReady(client), true); + // Nothing opens on the ended day's numbers. + const opening = await client.sendOrder(A, encodeContractName('NDX-USD', 0.001), 500, 'Buy', 'Market', undefined, 'open').catch((err) => err); + assert.equal(isOrderNotPlaced(opening), true); + assert.match(opening.message, /no sync has read it yet/); await client.requestSync(); assert.equal(engineDay(), '2026-10-28'); // No sync after the next reset: the day holds back only while the