/** * Worker config. Loaded from `.env.local` (gitignored) with safe defaults so the * loop runs out-of-the-box in dry-run *paper* mode even with zero configuration. * * Everything here is intentionally paper-only: this process never signs or sends a * real order. Live execution is the genuinely-risky 20% we deliberately skip — the * `mode` is fixed to 'dry-run' so the credibility comes from an honest, verifiable * paper track record, not from putting an LLM/agent in the money-losing path. */ // Node 21+ — load .env.local into process.env without any dependency. try { process.loadEnvFile('.env.local') } catch { /* no .env.local — fall back to real env / defaults */ } const num = (v: string | undefined, d: number) => v != null && v !== '' && isFinite(+v) ? +v : d const list = (v: string | undefined, d: string[]) => v ? v.split(',').map((s) => s.trim()).filter(Boolean) : d export const CONFIG = { // ── universe / cadence coins: list(process.env.QUANT_COINS, ['BTC', 'ETH', 'SOL']), interval: process.env.QUANT_INTERVAL ?? '1h', lookback: num(process.env.QUANT_LOOKBACK, 120), pollMs: num(process.env.QUANT_POLL_MS, 60_000), // ── paper trading equityStart: num(process.env.QUANT_EQUITY_START, 10_000), leverage: num(process.env.QUANT_LEVERAGE, 5), confFloor: num(process.env.QUANT_CONF_FLOOR, 0.55), maxOpenPerCoin: num(process.env.QUANT_MAX_OPEN_PER_COIN, 1), // ── telegram (optional — worker logs to stdout if unset) tgToken: process.env.TELEGRAM_BOT_TOKEN ?? '', tgChat: process.env.TELEGRAM_CHAT_ID ?? '', // ── execution mode — paper only. 'live' is intentionally not implemented. mode: 'dry-run' as const, // ── persistence dataFile: process.env.QUANT_DATA_FILE ?? 'worker/data/state.json', } export type Config = typeof CONFIG