Report each symbol's next-leg stats to the master; drop per-symbol commission
- lib/leg-estimate: an account's next leg sized on every surveyed candidate (planLegSize, ranked by rankForTarget) — notional, its multiple of the account and the broker's maximum, expected hold, cost and win chance. The dashboard's hold estimate and the reporter share it. - The reporter sends it per DXtrade firm as symbolStats, for one live account from the largest prefix group with a leg left to trade. - The symbol map's per-symbol commission is gone: the firm's applies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a2cd3a94c9
commit
169fe19fad
+48
-2
@@ -18,8 +18,9 @@ import { getClients } from './clients';
|
||||
import { getTradableFirms } from './firm-catalog';
|
||||
import { getAccountConfig } from './account-type-resolver';
|
||||
import { getSchedulerStatus } from './auto-trade';
|
||||
import { botStopsActive, combineCmeSessions, computeDayPlan, currentTradeDateCT, cycleCompletion, endedCycleCompletion, LEG_COMPLETION_EPSILON, projectPerfectPath, resolveEffectiveConfig } from './trading-logic';
|
||||
import type { AccountTypeStats, FirmStats } from './master-protocol';
|
||||
import { botStopsActive, combineCmeSessions, computeDayPlan, currentTradeDateCT, cycleCompletion, endedCycleCompletion, LEG_COMPLETION_EPSILON, projectPerfectPath, resolveEffectiveConfig, DEFAULT_TARGET_HOLD_HOURS } from './trading-logic';
|
||||
import type { AccountTypeStats, FirmStats, SymbolStats } from './master-protocol';
|
||||
import { accountNextLeg } from './leg-estimate';
|
||||
import { historyFresh } from './platform-client';
|
||||
|
||||
function collectFirmStats() {
|
||||
@@ -387,10 +388,55 @@ function collectFirmStats() {
|
||||
// Unknown until the firm has synced, not empty.
|
||||
...(client.syncComplete ? { accounts } : {}),
|
||||
accountTypes,
|
||||
...symbolStatsFor(f, client, rawToday),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A DXtrade firm's next leg on each symbol-map candidate, for the master's
|
||||
* Firms page: one live account from the firm's largest prefix group — the
|
||||
* group a batch fires — with something left to trade today. Nothing for
|
||||
* other platforms, or when no account has a leg to size.
|
||||
*/
|
||||
function symbolStatsFor(
|
||||
f: { name: string; commissionPct?: number; targetHoldHours?: number; financingPctPerDay?: number },
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
client: any,
|
||||
tradeDate: string,
|
||||
): { symbolStats?: SymbolStats } {
|
||||
if (!(client.lastCandidates?.length > 0)) return {};
|
||||
const groups = new Map<string, { id: number; name: string }[]>();
|
||||
for (const acc of client.accountList as { id: number; name: string; active: boolean }[]) {
|
||||
const cfg = getAccountConfig(acc.id).accountType;
|
||||
const floor = client.autoLiqThresholds?.[acc.id] ?? 0;
|
||||
const cash = client.accountCashBalances?.[acc.id];
|
||||
if (!cfg || !acc.active || !cash || (floor !== 0 && cash.amount <= floor)) continue;
|
||||
groups.set(cfg.prefix, [...(groups.get(cfg.prefix) ?? []), acc]);
|
||||
}
|
||||
for (const group of [...groups.values()].sort((a, b) => b.length - a.length)) {
|
||||
for (const acc of group) {
|
||||
const next = accountNextLeg(client, acc, f, tradeDate);
|
||||
if (!next || next.candidates.length === 0) continue;
|
||||
return {
|
||||
symbolStats: {
|
||||
account: acc.name,
|
||||
leg: next.leg,
|
||||
targetHoldHours: f.targetHoldHours || DEFAULT_TARGET_HOLD_HOURS,
|
||||
lastStand: next.lastStand,
|
||||
at: new Date().toISOString(),
|
||||
symbols: next.candidates.map((c) => ({
|
||||
symbol: c.symbol, notional: c.notional, multiplier: c.multiplier, maxMultiplier: c.maxMultiplier,
|
||||
holdHours: c.holdHours, cost: c.cost, winProbability: c.winProbability,
|
||||
volatilityPerDay: c.volatilityPerDay, spreadFraction: c.spreadFraction,
|
||||
})),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
// HMR-safe global to avoid duplicate intervals
|
||||
const _g = globalThis as typeof globalThis & { __reporterInterval?: ReturnType<typeof setInterval> };
|
||||
|
||||
|
||||
Reference in New Issue
Block a user