import { TradovateClient } from './tradovate-class'; import { getFirms, upsertFirmFee } from './db'; const SYMBOLS = ['NQ', 'MNQ', 'ES', 'MES', 'YM', 'MYM', 'RTY', 'M2K', 'GC', 'MGC', 'SI', 'CL', 'MCL', 'NG', 'ZB', 'ZN', 'ZF', '6E', '6J', '6B']; // Use global to persist the client pool across HMR reloads in dev mode const g = global as typeof globalThis & { __tradovateClients?: Map; __tradovateClientsInitialized?: boolean; }; function ensureMap(): Map { if (!g.__tradovateClients) { g.__tradovateClients = new Map(); } return g.__tradovateClients; } export function initClient(id: number, username: string, password: string, firmName: string): TradovateClient { const map = ensureMap(); let feesInitialized = false; const client = new TradovateClient(username, password, async () => { console.log(`[${firmName}] sync complete — ${client.accountList.length} account(s)`); if (!feesInitialized) { feesInitialized = true; try { const fees = await client.fetchInstrumentFees(SYMBOLS); for (const [symbol, fee] of Object.entries(fees)) { upsertFirmFee(id, symbol, fee, parseFloat((fee * 2).toFixed(4))); } const count = Object.keys(fees).length; if (count > 0) console.log(`[${firmName}] Auto-fetched fees for ${count} symbol(s)`); } catch (err) { console.error(`[${firmName}] Failed to auto-fetch fees`, err); } } }); map.set(id, client); return client; } export function removeClient(id: number): void { ensureMap().delete(id); } export function getClients(): Map { const map = ensureMap(); if (!g.__tradovateClientsInitialized) { g.__tradovateClientsInitialized = true; try { const firms = getFirms(); for (const firm of firms) { initClient(firm.id, firm.username, firm.password, firm.name); } console.log(`[clients] Initialized ${firms.length} Tradovate client(s)`); } catch (err) { console.error('[clients] Failed to initialize clients', err); } } return map; }