Unknown entries: judge only on a fresh good sync; all live orders count as working

Seventh review round (57835c0):

- An entry of unknown outcome is judged — filled after all, or never
  filled — only on a good sync that started after its settle window and
  with no order still working. A partial pass (position read failed or
  predated the fill, trades read after it) can no longer release it as
  "filled and flat" into a second entry.
- Tradovate counts every order not Filled/Canceled/Rejected/Expired/
  Completed as working (PendingCancel, Unknown included).
- TopstepX: an account whose order ended with its outcome unknown gets its
  open orders checked (Order/searchOpen) on each sync until none show, and
  counts as holding a working order until then.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-09-24 22:13:47 -05:00
co-authored by Claude Opus 5.5
parent 57835c01f0
commit 809f337055
3 changed files with 53 additions and 10 deletions
+7 -6
View File
@@ -158,19 +158,20 @@ function unknownEntryHolds(client: any, accountId: number, tradeDate: string): b
const outcome = entryOutcomeToday(accountId, tradeDate);
if (!outcome || outcome.state !== 'unknown') return false;
const cash = client.accountCashBalances[accountId];
// Nothing is judged before a good sync that started after the window:
// until then a position read can predate the fill (or have failed) while
// the trades read after it already show the P&L it booked.
const syncedFrom = client.lastSyncStartedAt ?? client.lastSyncAt;
if (syncedFrom < (outcome.unknownAt ?? outcome.at) + UNKNOWN_ENTRY_SETTLE_MS || cash === undefined) return true;
if (client.hasWorkingOrders?.(accountId)) return true;
// The broker shows the fill (the position, or the P&L it booked): it
// filled after all. From here it's an ordinary filled entry — the
// position gate holds it while open, one-and-done is done for the day.
if (client.positions[accountId] || (cash && Math.abs(cash.realizedPnL - outcome.realizedBefore) >= 0.005)) {
if (client.positions[accountId] || Math.abs(cash.realizedPnL - outcome.realizedBefore) >= 0.005) {
outcome.state = 'filled';
console.log(`[auto-trade] account ${accountId}: the entry of unknown outcome filled after all`);
return false;
}
const syncedFrom = client.lastSyncStartedAt ?? client.lastSyncAt;
const settled = syncedFrom >= (outcome.unknownAt ?? outcome.at) + UNKNOWN_ENTRY_SETTLE_MS
&& cash !== undefined
&& !client.hasWorkingOrders?.(accountId);
if (!settled) return true;
runtime().entryOutcomes?.delete(accountId);
unrecordLeg(accountId, tradeDate, outcome.legAmount);
console.log(`[auto-trade] account ${accountId}: the entry of unknown outcome never filled — free to trade again`);