Vest: a claim names the completed cycle it ends, a day's second and one after the reset too
Two of the cycles a claim ends never got a completion entry. A Vest day's second cycle is one: the auto-claim at the next tick beats the 30 s report, and the payout books into that day's fund row, so the latest fund date never moves for the catch-up. A cycle claimed right after the 20:00 ET reset is the other: the reset puts it back on stage 1, and all of its P&L sits in the previous claim's day row, so endedCycleCompletion reads none of it. Before a claim goes out, claimedCycle (trading-logic) checks whether the cycle stands complete: cycleCompletion 'today' or 'before' on the client's numbers. It keys the cycle the way the final day would (completionPlace on the payout list), so the master dedupes the two. afterClaim keeps the result in account_meta. The reporter names each kept cycle for the catch-up's week. It lists them last in the slice, newest first, under the master's per-slice cap, and adds no counter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
4a8e027056
commit
e02838409b
+35
-6
@@ -19,9 +19,10 @@ import {
|
||||
FALLBACK_COMMISSION_PER_CONTRACT, MAX_COMMISSION_PER_CONTRACT, DLL_MIN_STOP,
|
||||
CME_EVENING_OPEN_MIN, foldReason, withinFirmCaps,
|
||||
fundRowsKey, markFinishedCycle, unbookedPayoutDrop, machineSide, stageInputsFor, floorRoom, shortestNextLeg,
|
||||
type DayPlan, type FinishedCycleMark,
|
||||
claimedCycle, withinEndedCycleWindow,
|
||||
type DayPlan, type FinishedCycleMark, type ClaimedCycle,
|
||||
} from './trading-logic';
|
||||
import { getSetting, setSetting, loadAccountMeta, saveAccountMeta } from './db';
|
||||
import { getSetting, setSetting, loadAccountMeta, saveAccountMeta, loadClaimedCycles, saveClaimedCycles } from './db';
|
||||
import type { LaneTick, TickReason } from './master-protocol';
|
||||
import { isNotionalPlatform } from './master-protocol';
|
||||
import { POINT_VALUES, housekeepingRoot, HOUSEKEEPING_ROOT, MAX_HOLD_HOURS, futuresContracts } from './instrument-specs';
|
||||
@@ -2011,10 +2012,11 @@ async function runClaims(lane: string, ready: FirmClient[]): Promise<void> {
|
||||
const amount = claimDue(client, acc, Date.now());
|
||||
if (amount === null) continue;
|
||||
try {
|
||||
const ends = claimEnds(client, acc);
|
||||
// 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, tradeDateFor(client));
|
||||
afterClaim('[auto-claim]', firm, client, acc, claimed, received, tradeDateFor(client), ends);
|
||||
} 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`);
|
||||
@@ -2062,15 +2064,41 @@ async function claimTick(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
/** The completed cycle a claim about to go out ends (claimedCycle), taken
|
||||
* before the claim books its payout. Not on rows a failed read left behind
|
||||
* — the master keeps it — which is historyFresh's own test for the
|
||||
* account; not its client-wide one, no read in flight, as each claim
|
||||
* starts a read and the next claim of the tick would never name its
|
||||
* cycle. The claim already stands on the account's read (historyReady).
|
||||
* Never throws: a payout isn't held back for its record. */
|
||||
function claimEnds(client: PlatformClient, acc: { id: number; name: string }): ClaimedCycle | null {
|
||||
try {
|
||||
const cfg = getAccountConfig(acc.id).accountType;
|
||||
return cfg && !client.lastFetchErrors?.[acc.name] ? claimedCycle(client, acc.id, cfg) : null;
|
||||
} catch (err) {
|
||||
console.error(`[claim] ${acc.name}: the cycle the claim ends couldn't be read — ${errorMessage(err)}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** A claim went through: the account starts its next stage — the day's leg
|
||||
* count and entry outcome are cleared, as if it hadn't traded today. */
|
||||
* count and entry outcome are cleared, as if it hadn't traded today — and
|
||||
* the completed cycle it ended (claimEnds) is kept for the reporter, which
|
||||
* may never have seen it complete. */
|
||||
function afterClaim(
|
||||
tag: string, firm: TradableFirm, client: PlatformClient, acc: { id: number; name: string },
|
||||
claimed: number, received: number | null, tradeDate: string,
|
||||
claimed: number, received: number | null, tradeDate: string, ends: ClaimedCycle | null,
|
||||
): number {
|
||||
runtime().legCounts.delete(acc.id);
|
||||
runtime().entryOutcomes?.delete(acc.id);
|
||||
runtime().claimFailedAt?.delete(acc.id);
|
||||
if (ends) {
|
||||
try {
|
||||
saveClaimedCycles(acc.id, [...loadClaimedCycles(acc.id).filter((c) => withinEndedCycleWindow(c.date, ends.date)), ends]);
|
||||
} catch (err) {
|
||||
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);
|
||||
console.log(`${tag} ${firm.name} ${acc.name}: claimed $${claimed}${received !== null ? ` (you get $${received})` : ''}`
|
||||
+ ` — trading stage ${stage} next (${tradeDate})`);
|
||||
@@ -2147,8 +2175,9 @@ export async function claimAccountNow(accountId: number, amount: number): Promis
|
||||
if ('reason' in c) throw new ClaimRefusedError(c.reason);
|
||||
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 ends = claimEnds(c.client, c.acc);
|
||||
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, tradeDateFor(c.client));
|
||||
const stage = afterClaim('[claim-now]', c.firm, c.client, c.acc, claimed, received, tradeDateFor(c.client), ends);
|
||||
return { claimed, received, stage };
|
||||
} finally {
|
||||
releaseTradeMutex(lease, lane);
|
||||
|
||||
Reference in New Issue
Block a user