Live futures spreads off one client, and the master's max entry spread
One quote feed per machine: a TopstepX client's market hub, else a Tradovate client's market-data socket, subscribed to every listed root's front month and the drain micro. A supervisor keeps it on a working client, dropping one that fails or goes quiet while the market trades. The Auto draw weighs each instrument by its live spread (the typical tick when no fresh quote is at hand). No futures entry pays more than the master's max entry spread ($15 until set) to cross the book: the draw leaves such an instrument out, an explicit symbol sits the tick out, and fireLeg and the extra-day trade check it last before sending. The Settings page and the master's stats show the live spreads and the feed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
1782c16145
commit
db1d12327a
@@ -13,6 +13,7 @@ import { startBackupSync } from './backup-sync';
|
||||
import { applyBrokerHttpDefaults, applyBrokerProxy } from './outbound-proxy';
|
||||
import { startMasterLink } from './master-link';
|
||||
import { resumeSchedulerIfPersisted } from './auto-trade';
|
||||
import { superviseQuotes, SUPERVISE_INTERVAL_MS, type QuoteClient } from './live-quotes';
|
||||
|
||||
// Use global to persist the client pool across HMR reloads in dev mode.
|
||||
// Keyed by the master's firm id, which is a uuid string.
|
||||
@@ -31,6 +32,7 @@ const g = global as typeof globalThis & {
|
||||
__contractResolvedRoots?: Set<string>;
|
||||
__clientSupervisorTimer?: ReturnType<typeof setInterval>;
|
||||
__clientSupervision?: Map<string, SupervisionEntry>;
|
||||
__quoteSupervisorTimer?: ReturnType<typeof setInterval>;
|
||||
};
|
||||
|
||||
function ensureMap(): Map<string, PlatformClient> {
|
||||
@@ -218,6 +220,10 @@ export function getClients(): Map<string, PlatformClient> {
|
||||
// Rebuild any client that has been wedged for too long.
|
||||
startClientSupervisor();
|
||||
|
||||
// Live quotes off one futures client, for the spread every entry
|
||||
// pays and the Auto draw.
|
||||
startQuoteSupervisor();
|
||||
|
||||
// Start master dashboard reporter
|
||||
startReporter();
|
||||
|
||||
@@ -388,6 +394,30 @@ function supervisionMap(): Map<string, SupervisionEntry> {
|
||||
return g.__clientSupervision;
|
||||
}
|
||||
|
||||
/** Keep the live quote feed on a futures client, subscribed to every root
|
||||
* this machine may trade (lib/live-quotes.ts). */
|
||||
function superviseLiveQuotes(): void {
|
||||
// Runs from a timer: nothing may escape.
|
||||
try {
|
||||
const map = ensureMap();
|
||||
const candidates = getTradableFirms().filter(isFuturesFirm).flatMap((firm) => {
|
||||
const client = map.get(firm.id);
|
||||
return client ? [{ firmId: firm.id, firmName: firm.name, platform: firm.platform, client: client as unknown as QuoteClient }] : [];
|
||||
});
|
||||
superviseQuotes(candidates, resolveRootsHere())
|
||||
.catch((err) => console.error(`[quotes] supervision failed: ${errorMessage(err)}`));
|
||||
} catch (err) {
|
||||
console.error(`[quotes] supervision failed: ${errorMessage(err)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function startQuoteSupervisor(): void {
|
||||
if (g.__quoteSupervisorTimer) clearInterval(g.__quoteSupervisorTimer);
|
||||
g.__quoteSupervisorTimer = setInterval(superviseLiveQuotes, SUPERVISE_INTERVAL_MS);
|
||||
// The clients log in within seconds; the first look shouldn't wait 30.
|
||||
setTimeout(superviseLiveQuotes, 10_000);
|
||||
}
|
||||
|
||||
function startClientSupervisor(): void {
|
||||
// HMR-safe, and safe when resetClients() re-runs the bootstrap.
|
||||
if (g.__clientSupervisorTimer) clearInterval(g.__clientSupervisorTimer);
|
||||
|
||||
Reference in New Issue
Block a user