// Deterministic mock data so equity curves, trades, events all line up. const COINS = ['BTC','ETH','BNB','ADA','SOL','XRP','AVAX','DOT']; const ACCOUNTS = [ { id: 'binance-main', exchange: 'binance', mode: 'paper', bridge: 'USDT', current_coin: 'BTC' }, { id: 'paribu-try', exchange: 'paribu', mode: 'testnet', bridge: 'TRY', current_coin: 'ETH' }, { id: 'binance-live', exchange: 'binance', mode: 'live', bridge: 'USDT', current_coin: 'SOL' }, ]; // Mulberry32 PRNG so output is stable across reloads. function rng(seed) { let s = seed >>> 0; return () => { s |= 0; s = s + 0x6D2B79F5 | 0; let t = Math.imul(s ^ s >>> 15, 1 | s); t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t; return ((t ^ t >>> 14) >>> 0) / 4294967296; }; } const NOW = Date.now(); const HOUR = 3600 * 1000; // Equity: 24h, 1-min ticks function buildEquity(seed, base, hours = 168) { const r = rng(seed); const points = hours * 6; // every 10 min const out = []; let v = base; for (let i = points; i >= 0; i--) { const t = NOW - i * 10 * 60 * 1000; v = v * (1 + (r() - 0.49) * 0.0035); out.push({ t, v: +v.toFixed(2) }); } return out; } function buildPairs(seed, currentCoin) { const r = rng(seed); const out = []; for (const a of COINS) { for (const b of COINS) { if (a === b || a === 'USDT' || b === 'USDT') continue; const baseline = +(0.5 + r() * 80).toFixed(4); const drift = (r() - 0.5) * 0.12; const current = +(baseline * (1 + drift)).toFixed(4); const raw = +drift.toFixed(4); const eff = +(raw - 0.0025 - r() * 0.003).toFixed(4); out.push({ from: a, to: b, baseline, current, raw_score: raw, eff_score: eff, margin: 0.005, multiplier: 1.05, ema_alpha: 0.05, last_decision: eff > 0.01 ? 'jump_candidate' : eff < -0.01 ? 'reject_below_threshold' : 'hold', }); } } return out; } function buildTrades(seed, n = 80) { const r = rng(seed); const states = ['FILLED','FILLED','FILLED','PARTIALLY_FILLED','CANCELED','REJECTED']; const out = []; let coin = 'BTC'; for (let i = 0; i < n; i++) { const next = COINS.filter(c => c !== coin && c !== 'USDT')[Math.floor(r() * 6)]; const ts = NOW - (n - i) * (HOUR / 2 + r() * HOUR); const qty = +(0.05 + r() * 1.5).toFixed(4); const price = +(50 + r() * 70000).toFixed(2); const fee = +(qty * price * 0.001).toFixed(4); const state = states[Math.floor(r() * states.length)]; const cid = `pb-${i}-${coin}-${next}-${Math.floor(r()*0xfffff).toString(16).padStart(5,'0')}`; const fills = []; if (state === 'FILLED' || state === 'PARTIALLY_FILLED') { const m = 1 + Math.floor(r() * 3); let left = qty; for (let k = 0; k < m; k++) { const part = k === m - 1 ? left : +(qty / m * (0.7 + r() * 0.6)).toFixed(4); left -= part; fills.push({ price: +(price * (1 + (r()-0.5)*0.001)).toFixed(2), qty: part, commission: +(part*price*0.001).toFixed(4), isMaker: r() > 0.5 }); } } out.push({ id: i + 1, ts, account: r() > 0.3 ? 'binance-main' : 'paribu-try', from: coin, to: next, qty, price, fee, state, client_order_id: cid, side: r() > 0.5 ? 'BUY' : 'SELL', symbol: `${next}/USDT`, fills, outbox_id: 1000 + i, }); if (state === 'FILLED') coin = next; } return out.reverse(); } function buildEvents(seed) { const r = rng(seed); const kinds = ['strategy_decision','tick','dispatch','reconcile','risk_check','outbox_state','depeg_check']; const out = []; for (let i = 0; i < 600; i++) { const ts = NOW - (600 - i) * (60 * 1000) * (0.4 + r() * 0.8); const kind = kinds[Math.floor(r() * kinds.length)]; out.push({ id: i + 1, kind, at: ts, payload: { account: r() > 0.5 ? 'binance-main' : 'paribu-try', score: +(r()*0.05 - 0.025).toFixed(4), coin: COINS[Math.floor(r() * 6)], } }); } return out; } function buildLogs(seed) { const r = rng(seed); const sevs = ['debug','info','info','info','warn','error']; const kinds = ['scout','dispatcher','outbox','reconcile','risk','ws','rest']; const msgs = [ 'tick received', 'jump candidate evaluated', 'order acknowledged by exchange', 'reconcile diff detected', 'depeg guard cleared', 'order failed: insufficient balance', 'ws reconnect', 'partial fill received', 'kill-switch armed', 'baseline updated', ]; const out = []; for (let i = 0; i < 200; i++) { const ts = NOW - (200 - i) * 8000 - r() * 2000; const sev = sevs[Math.floor(r() * sevs.length)]; const kind = kinds[Math.floor(r() * kinds.length)]; const msg = msgs[Math.floor(r() * msgs.length)]; out.push({ ts, sev, kind, msg, account: r() > 0.5 ? 'binance-main' : 'paribu-try', data: { coin: COINS[Math.floor(r()*7)], score: +(r()*0.1 - 0.05).toFixed(5), latency_ms: Math.floor(r() * 220), nonce: Math.floor(r() * 9999999), } }); } return out; } const KILL_TRIP_AT = NOW - 9 * HOUR; const ALERTS = [ { kind: 'risk_halt', severity: 'error', reason: 'bridge_depeg_low: USDT mid 0.9962 (<0.998)', at: KILL_TRIP_AT, account: 'binance-live' }, { kind: 'dead_letter', severity: 'warn', reason: 'order failed 3× — moved to dead-letter', at: NOW - 2*HOUR, account: 'binance-main', cid: 'pb-58-ETH-SOL-9a17c' }, { kind: 'reconcile_diff', severity: 'info', reason: 'local qty 1.2034 vs exchange 1.2030', at: NOW - 30*60*1000, account: 'binance-main' }, { kind: 'flash_crash', severity: 'warn', reason: 'BTC -4.2% over 60s; pause 5min', at: NOW - 70*60*1000, account: 'binance-main' }, ]; const TICKER = COINS.filter(c => c !== 'USDT').map((c, i) => ({ symbol: `${c}/USDT`, last: [62800, 3120, 580, 0.42, 142, 0.51, 31.8, 7.9][i] || 100, change: ((i % 3) - 1) * 0.01 * (i + 1) * 0.4, })); const CONFIG_YAML = `app: name: project-bad-v1 log_level: info http_addr: ":8088" metrics_addr: ":9090" accounts: - id: binance-main exchange: binance mode: paper bridge: USDT api_key: ***REDACTED*** api_secret: ***REDACTED*** coins: [BTC, ETH, BNB, ADA, SOL, XRP, AVAX, DOT] notifications: webhook: ***REDACTED*** - id: paribu-try exchange: paribu mode: testnet bridge: TRY api_key: ***REDACTED*** api_secret: ***REDACTED*** token: ***REDACTED*** coins: [BTC, ETH, AVAX, DOT] risk: bridge_depeg_lower: 0.998 bridge_depeg_upper: 1.002 flash_crash_pct: 0.04 flash_crash_window_s: 60 max_consecutive_errors: 3 kill_switch_persist: true strategy_config: binance-main: margin: 0.005 multiplier: 1.05 ema_alpha: 0.05 fee_pct: 0.001 safety_pct: 0.001 anti_whipsaw_window_s: 300 paribu-try: margin: 0.0075 multiplier: 1.05 ema_alpha: 0.04 fee_pct: 0.0015 safety_pct: 0.0012 anti_whipsaw_window_s: 420`; const Mock = { COINS, ACCOUNTS, TICKER, CONFIG_YAML, ALERTS, KILL_TRIP_AT, NOW, HOUR, equity: buildEquity(7, 12500, 168), equityShort: buildEquity(13, 12500, 24), pairs: buildPairs(101, 'BTC'), trades: buildTrades(33, 90), events: buildEvents(55), logs: buildLogs(77), }; window.Mock = Mock;