// Mock dati per il prototipo — rispecchiano gli schema di stocks.db // (results_tool2 / results_tool3 / tool4 JSON) senza alterare i campi. const WATCHLIST = [ { symbol: "AMZN", name: "Amazon.com Inc.", price: 218.42, base: 215.10 }, { symbol: "INTC", name: "Intel Corporation", price: 24.93, base: 24.30 }, { symbol: "NOK", name: "Nokia Oyj", price: 4.58, base: 4.55 }, { symbol: "MU", name: "Micron Technology", price: 121.66, base: 119.40 }, { symbol: "MSFT", name: "Microsoft Corp.", price: 446.81, base: 443.10 }, { symbol: "ADBE", name: "Adobe Inc.", price: 521.30, base: 526.40 }, { symbol: "STX", name: "Seagate Technology", price: 98.74, base: 98.10 }, { symbol: "RKLB", name: "Rocket Lab USA", price: 19.04, base: 18.50 }, { symbol: "HIMS", name: "Hims & Hers Health", price: 14.81, base: 15.30 }, { symbol: "CRWD", name: "CrowdStrike Holdings",price: 312.60, base: 307.90 }, ]; // piccolo PRNG seedabile per dati deterministici function rng(seed) { let s = seed | 0; return () => { s = (s * 1103515245 + 12345) & 0x7fffffff; return s / 0x7fffffff; }; } // Genera ~156 candele 5m delle ultime 2 sessioni — orari ET function makeCandles(symbol, basePrice, seed = 1) { const r = rng(seed); const now = Math.floor(Date.now() / 1000); const STEP = 5 * 60; const COUNT = 156; let price = basePrice; const out = []; let t = now - COUNT * STEP; // round t to last 5min boundary t = Math.floor(t / STEP) * STEP; for (let i = 0; i < COUNT; i++) { const vol = basePrice * 0.0025; const drift = (r() - 0.48) * vol * 1.4; const open = price; const close = Math.max(0.01, open + drift); const high = Math.max(open, close) + r() * vol; const low = Math.min(open, close) - r() * vol; out.push({ time: t + i * STEP, open: +open.toFixed(4), high: +high.toFixed(4), low: +low.toFixed(4), close: +close.toFixed(4), }); price = close; } return out; } function tool2Forecast(basePrice, seed) { const r = rng(seed); // pct percentuali sul basePrice const trend = r() > 0.55 ? 1 : -1; const intensity = 0.4 + r() * 1.2; const exp = { expected_1h: +(trend * intensity * 0.3 + (r()-0.5)*0.4).toFixed(2), expected_3h: +(trend * intensity * 0.6 + (r()-0.5)*0.5).toFixed(2), expected_6h: +(trend * intensity * 0.9 + (r()-0.5)*0.6).toFixed(2), expected_24h: +(trend * intensity * 1.6 + (r()-0.5)*0.9).toFixed(2), expected_2w: +(trend * intensity * 3.5 + (r()-0.5)*1.6).toFixed(2), }; const signal = exp.expected_24h > 0.8 ? "BUY" : exp.expected_24h < -0.8 ? "SELL" : "HOLD"; return { signal, confidence: Math.round(60 + r()*30), confidence_real: Math.round(50 + r()*35), trend_1h: trend>0 ? "Up" : "Down", ...exp, timestamp: nowIso(), mode: r() > 0.5 ? "quick" : "full", }; } function tool3Forecast(basePrice, seed) { const r = rng(seed + 7); const trend = r() > 0.6 ? 1 : -1; const i = 0.3 + r()*1.0; return { signal: r() > 0.66 ? "BUY" : r() > 0.33 ? "HOLD" : "SELL", score_total: Math.round(40 + r()*55), method: r() > 0.5 ? "EMA+RSI+MACD" : "Bollinger+ATR", sample_size: Math.round(120 + r()*200), h01: +(trend*i*0.25 + (r()-0.5)*0.3).toFixed(2), h03: +(trend*i*0.55 + (r()-0.5)*0.4).toFixed(2), h06: +(trend*i*0.80 + (r()-0.5)*0.5).toFixed(2), h24: +(trend*i*1.40 + (r()-0.5)*0.8).toFixed(2), h2w: +(trend*i*3.20 + (r()-0.5)*1.4).toFixed(2), timestamp: nowIso(), }; } function tool4Forecast(seed) { const r = rng(seed + 13); const sent = +(((r()-0.45) * 2)).toFixed(2); const trend = sent >= 0 ? 1 : -1; return { signal: sent > 0.3 ? "BUY" : sent < -0.3 ? "SELL" : "HOLD", news_impact: r() > 0.66 ? "HIGH" : r() > 0.3 ? "MEDIUM" : "LOW", sentiment: sent, fc_1h: +(trend*0.3 + (r()-0.5)*0.2).toFixed(2), fc_3h: +(trend*0.6 + (r()-0.5)*0.3).toFixed(2), fc_6h: +(trend*0.9 + (r()-0.5)*0.4).toFixed(2), fc_24h: +(trend*1.4 + (r()-0.5)*0.7).toFixed(2), confidence: Math.round(45 + r()*40), timestamp: nowIso(), }; } function nowIso() { const d = new Date(); return d.toISOString().slice(0, 19).replace("T", " "); } // Costruisce ALL_DATA per il dashboard const ALL_DATA = {}; WATCHLIST.forEach((w, idx) => { const seed = w.symbol.charCodeAt(0)*31 + w.symbol.length*7 + idx; const candles = makeCandles(w.symbol, w.base, seed); const lastClose = candles[candles.length-1].close; WATCHLIST[idx].price = +lastClose.toFixed(2); WATCHLIST[idx].deltaPct = +(((lastClose - w.base) / w.base) * 100).toFixed(2); const t2 = tool2Forecast(w.base, seed); const t3 = tool3Forecast(w.base, seed); const t4 = tool4Forecast(seed); ALL_DATA[w.symbol] = { candles, tool2_info: t2, tool3_info: t3, tool4_info: t4, last_candle_time: candles[candles.length-1].time, }; }); // Calendar events — richer mock data con sentiment e orari const CALENDAR_EVENTS = (() => { const today = new Date(); const events = {}; const add = (dayOffset, ev) => { const d = new Date(today); d.setDate(today.getDate() + dayOffset); const key = `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,"0")}-${String(d.getDate()).padStart(2,"0")}`; events[key] = events[key] || []; events[key].push(ev); }; // sentiment: -3 (bearish) → +3 (bullish) add( 0, { company:"Amazon.com Inc.", sym:"AMZN", title:"Risultati", type:"earnings", sentiment: 1, time:"22:00" }); add( 1, { company:"Micron Technology", sym:"MU", title:"Q3 Risultati", type:"earnings", sentiment: 2, time:"22:00" }); add( 1, { company:"Rocket Lab USA", sym:"RKLB", title:"Risultati", type:"earnings", sentiment: 3, time:"22:00" }); add( 2, { company:"Federal Reserve", sym:"FED", title:"FOMC Minutes", type:"fed", sentiment:-1, time:"20:00" }); add( 3, { company:"Intel Corporation", sym:"INTC", title:"Risultati", type:"earnings", sentiment:-1, time:"22:00" }); add( 5, { company:"CrowdStrike Holdings", sym:"CRWD", title:"Investor Day", type:"earnings", sentiment: 2, time:"14:00" }); add( 5, { company:"Seagate Technology", sym:"STX", title:"Risultati", type:"earnings", sentiment: 1, time:"22:00" }); add( 7, { company:"US Dept. of Labor", sym:"CPI", title:"CPI Release", type:"macro", sentiment:-1, time:"14:30" }); add( 9, { company:"Adobe Inc.", sym:"ADBE", title:"Risultati", type:"earnings", sentiment: 3, time:"22:00" }); add(-2, { company:"Jerome Powell", sym:"FED", title:"Powell Speech", type:"fed", sentiment:-2, time:"16:30" }); add(-3, { company:"Microsoft Corp.", sym:"MSFT", title:"Risultati", type:"earnings", sentiment: 2, time:"22:00" }); add(-3, { company:"Nokia Oyj", sym:"NOK", title:"Quarterly Results", type:"earnings", sentiment: 1, time:"08:00" }); add( 4, { company:"Bureau of Econ. Analysis", sym:"GDP", title:"GDP Q1 2026", type:"macro", sentiment: 1, time:"14:30" }); add(12, { company:"Hims & Hers Health", sym:"HIMS", title:"Risultati", type:"earnings", sentiment: 1, time:"22:00" }); add( 0, { company:"Hims & Hers Health", sym:"HIMS", title:"Investor Call", type:"earnings", sentiment: 2, time:"14:00" }); add( 3, { company:"NVIDIA Corporation", sym:"NVDA", title:"Risultati", type:"earnings", sentiment: 3, time:"22:00" }); return events; })(); // Report data — righe per Tool2, Tool3, Tool4 (stile tabella originale) function makeReportRows() { const rows = { tool2: [], tool3: [], tool4: [] }; const today = new Date(); const fmt = (d) => `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,"0")}-${String(d.getDate()).padStart(2,"0")}`; const dates = [fmt(today)]; // aggiungi 2 giorni feriali precedenti let tmp = new Date(today); let added = 0; while (added < 2) { tmp.setDate(tmp.getDate()-1); if (tmp.getDay() !== 0 && tmp.getDay() !== 6) { dates.push(fmt(tmp)); added++; } } dates.forEach((date, di) => { WATCHLIST.slice(0, 6).forEach((w, wi) => { const seed = w.symbol.charCodeAt(0)*17 + di*31 + wi*7; const t2 = tool2Forecast(w.base, seed); const t3 = tool3Forecast(w.base, seed+5); const t4 = tool4Forecast(seed+11); const rndP = (p, pct) => Math.round(p * (1 + pct/100) * 2) / 2; const hour = 9 + Math.floor(wi/2); const min = wi%2===0 ? "20" : "40"; const timeStr = `${String(hour).padStart(2,"0")}:${min}`; rows.tool2.push({ date, symbol: w.symbol, time: timeStr, mode: t2.mode, signal: t2.signal, conf: t2.confidence, conf_real: t2.confidence_real, trend1h: t2.trend_1h, close: w.price, h1: +(t2.expected_1h).toFixed(2), h3: +(t2.expected_3h).toFixed(2), h6: +(t2.expected_6h).toFixed(2), h24: +(t2.expected_24h).toFixed(2), h2w: +(t2.expected_2w).toFixed(2), target: rndP(w.price, t2.expected_24h > 0 ? t2.expected_24h*1.3 : t2.expected_24h*0.8), stop: rndP(w.price, t2.expected_24h > 0 ? -Math.abs(t2.expected_1h)*0.5 : Math.abs(t2.expected_1h)*0.5), }); rows.tool3.push({ date, symbol: w.symbol, time: `${String(hour).padStart(2,"0")}:${wi%2===0?"22":"42"}`, signal: t3.signal, score: t3.score_total, method: t3.method, sample_n: t3.sample_size, close: w.price, h1: +(t3.h01).toFixed(2), h3: +(t3.h03).toFixed(2), h6: +(t3.h06).toFixed(2), h24: +(t3.h24).toFixed(2), h2w: +(t3.h2w).toFixed(2), target: rndP(w.price, t3.h24 > 0 ? t3.h24*1.3 : t3.h24*0.8), stop: rndP(w.price, t3.h24 > 0 ? -Math.abs(t3.h01)*0.5 : Math.abs(t3.h01)*0.5), }); rows.tool4.push({ date, symbol: w.symbol, time: `${String(hour).padStart(2,"0")}:${wi%2===0?"25":"45"}`, signal: t4.signal, news_impact: t4.news_impact, sentiment: +(t4.sentiment).toFixed(2), conf: t4.confidence, close: w.price, h1: +(t4.fc_1h).toFixed(2), h3: +(t4.fc_3h).toFixed(2), h6: +(t4.fc_6h).toFixed(2), h24: +(t4.fc_24h).toFixed(2), target: rndP(w.price, t4.fc_24h > 0 ? t4.fc_24h*1.3 : t4.fc_24h*0.8), stop: rndP(w.price, t4.fc_24h > 0 ? -Math.abs(t4.fc_1h)*0.5 : Math.abs(t4.fc_1h)*0.5), }); }); }); return rows; } const REPORT_DATA = makeReportRows(); // Recent log lines const SAMPLE_LOGS = [ ["2026-05-16 14:32:01", "info", "tool1.collector", "Fetching 5m OHLCV for 10 symbols"], ["2026-05-16 14:32:04", "ok", "tool1.collector", "Saved 156 candles AMZN → stocks.db"], ["2026-05-16 14:32:04", "ok", "tool1.collector", "Saved 156 candles INTC → stocks.db"], ["2026-05-16 14:32:09", "info", "tool2.agent", "Prompt builder: lookback=156 mode=quick"], ["2026-05-16 14:32:18", "ok", "tool2.agent", "AMZN signal=BUY confidence=78 (real=71)"], ["2026-05-16 14:32:31", "ok", "tool3.analyzer", "AMZN score=72 method=EMA+RSI+MACD"], ["2026-05-16 14:32:42", "warn", "tool4.news", "Finnhub rate limit reached, backing off 30s"], ["2026-05-16 14:33:14", "ok", "tool4.news", "AMZN sentiment=+0.32 impact=MEDIUM"], ["2026-05-16 14:33:14", "info", "tool6.telegram", "Notification sent → BUY AMZN +1.42% 24h"], ["2026-05-16 14:35:00", "info", "tool1.collector", "Scheduler tick — next run 14:40"], ["2026-05-16 14:35:18", "err", "tool4.news", "Perplexity 502 Bad Gateway — retry 1/3"], ["2026-05-16 14:35:48", "ok", "tool4.news", "Perplexity recovered on retry"], ["2026-05-16 14:40:00", "info", "tool1.collector", "Fetching 5m OHLCV for 10 symbols"], ["2026-05-16 14:40:06", "ok", "tool1.collector", "Saved 12 new candles across watchlist"], ]; // Sample admin users const SAMPLE_USERS = [ { id: 1, username: "marco", is_admin: true, totp_enabled: true, telegram_chat_id: "129384712", created_at: "2025-08-12 09:14:00" }, { id: 2, username: "luca", is_admin: false, totp_enabled: true, telegram_chat_id: "904521133", created_at: "2025-09-03 17:22:00" }, { id: 3, username: "giulia", is_admin: false, totp_enabled: false, telegram_chat_id: "", created_at: "2025-11-21 11:08:00" }, ]; window.WATCHLIST = WATCHLIST; window.ALL_DATA = ALL_DATA; window.CALENDAR_EVENTS = CALENDAR_EVENTS; window.REPORT_DATA = REPORT_DATA; window.SAMPLE_LOGS = SAMPLE_LOGS; window.SAMPLE_USERS = SAMPLE_USERS;