Add Random symbol option to trade controls

- Symbol dropdown now includes a "Random" option alongside enabled instruments
- runTrade resolves 'Random' to a random enabled instrument once per batch,
  so all accounts in the same tick trade the same symbol
- Import getInstruments in auto-trade.ts to support the resolution

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Senofy
2026-03-12 03:38:03 -05:00
co-authored by Claude Sonnet 4.6
parent cade280b2d
commit 39d7c5761c
2 changed files with 16 additions and 8 deletions
+15 -8
View File
@@ -7,7 +7,7 @@
* signal but have since exited and are now eligible.
*/
import { getFirms, isSymbolBanned } from './db';
import { getFirms, isSymbolBanned, getInstruments } from './db';
import { getClients } from './clients';
import { computeDailyTarget, POINT_VALUES } from './trading-logic';
import { getSetting } from './db';
@@ -70,12 +70,19 @@ export async function runTrade(action: 'Buy' | 'Sell' | 'Random', symbol: string
console.log('[auto-trade] no-trade window active (35 PM Central) — skipping');
return [];
}
// Resolve Random once per batch so all accounts trade the same direction
// Resolve 'Random' symbol once per batch so all accounts trade the same symbol
let resolvedSymbol = symbol;
if (symbol === 'Random') {
const enabled = getInstruments().filter((i) => i.enabled).map((i) => i.symbol);
resolvedSymbol = enabled.length > 0 ? enabled[Math.floor(Math.random() * enabled.length)] : 'NQ';
console.log(`[auto-trade] random symbol resolved to: ${resolvedSymbol}`);
}
// Resolve Random action once per batch so all accounts trade the same direction
const resolvedAction: 'Buy' | 'Sell' = action === 'Random'
? (Math.random() < 0.5 ? 'Buy' : 'Sell')
: action;
const pointValue = POINT_VALUES[symbol];
if (!pointValue) throw new Error(`Unknown symbol: ${symbol}`);
const pointValue = POINT_VALUES[resolvedSymbol];
if (!pointValue) throw new Error(`Unknown symbol: ${resolvedSymbol}`);
const maxConcurrent = parseInt(getSetting('max_concurrent_accounts') ?? '5', 10);
const firms = getFirms();
@@ -101,14 +108,14 @@ export async function runTrade(action: 'Buy' | 'Sell' | 'Random', symbol: string
if (!client || client.accountList.length === 0) return;
// Skip this firm entirely if the symbol is banned for it
if (isSymbolBanned(firm.id, symbol)) {
console.log(`[auto-trade] ${firm.name}: ${symbol} is banned — skipping firm`);
if (isSymbolBanned(firm.id, resolvedSymbol)) {
console.log(`[auto-trade] ${firm.name}: ${resolvedSymbol} is banned — skipping firm`);
return;
}
const firmConfig = mapFirmConfig(firm);
const contract = await client.findFrontMonthContract(symbol);
const contract = await client.findFrontMonthContract(resolvedSymbol);
if (!contract) return;
for (const acc of client.accountList) {
@@ -228,7 +235,7 @@ export async function runTrade(action: 'Buy' | 'Sell' | 'Random', symbol: string
});
}
console.log(`[auto-trade] ${acc.name} (${item.firmName}) ${resolvedAction} ${contracts}x${symbol} @ ${fill.price} | target $${target.amount} [${target.path}] (+$${totalCommission.toFixed(2)} comm) | exit @ ${exitPrice} (orderId=${exitOrder.orderId})`);
console.log(`[auto-trade] ${acc.name} (${item.firmName}) ${resolvedAction} ${contracts}x${resolvedSymbol} @ ${fill.price} | target $${target.amount} [${target.path}] (+$${totalCommission.toFixed(2)} comm) | exit @ ${exitPrice} (orderId=${exitOrder.orderId})`);
return {
account: acc.name,