diff --git a/web/app.py b/web/app.py index a8a78609..322f4b3c 100644 --- a/web/app.py +++ b/web/app.py @@ -354,6 +354,8 @@ def _analyze(city: str) -> Dict[str, Any]: if mgm: mgc = mgm.get("current", {}) mgm_data = { + "temp": _sf(mgc.get("temp")), + "time": mgc.get("time"), "feels_like": _sf(mgc.get("feels_like")), "humidity": _sf(mgc.get("humidity")), "wind_dir": _sf(mgc.get("wind_dir")), @@ -462,7 +464,8 @@ def _analyze(city: str) -> Dict[str, Any]: try: proxy = _config.get("proxy") fetch_weather_markets(proxy=proxy, timeout=10) - city_mkts = get_city_markets(city, target_date=local_date_str) + # We don't filter by target_date here, we want ALL active contracts for the city + city_mkts = get_city_markets(city) if city_mkts: result["polymarket"] = { "markets": [ diff --git a/web/static/app.js b/web/static/app.js index f635c347..8fab25d4 100644 --- a/web/static/app.js +++ b/web/static/app.js @@ -435,6 +435,18 @@ function renderHero(data) { parts.push(`๐๏ธ ${cur.visibility_mi}mi`); } + // MGM info (Ankara specific) + if (data.mgm?.temp != null) { + let mgmTimeStr = ""; + if (data.mgm.time) { + const match = data.mgm.time.match(/T?(\d{2}:\d{2})/); + if (match) mgmTimeStr = ` @${match[1]}`; + } + parts.push( + `โญ MGM ๅฎๆต: ${data.mgm.temp}${sym}${mgmTimeStr}`, + ); + } + // Trend badge const trend = data.trend || {}; if (trend.is_dead_market) { @@ -507,12 +519,29 @@ function renderChart(data) { }); } + // MGM observation point (Ankara specific) + const mgmPoints = new Array(times.length).fill(null); + if (data.mgm?.temp != null && data.mgm?.time) { + const timeMatch = data.mgm.time.match(/T?(\d{2}):(\d{2})/); + if (timeMatch) { + let h = parseInt(timeMatch[1], 10); + const m = parseInt(timeMatch[2], 10); + if (m >= 30) h = (h + 1) % 24; + const hourKey = h.toString().padStart(2, "0") + ":00"; + const idx = times.indexOf(hourKey); + if (idx >= 0) { + mgmPoints[idx] = data.mgm.temp; + } + } + } + const ctx = document.getElementById("tempChart").getContext("2d"); if (tempChart) tempChart.destroy(); const validDebTemps = debTemps.filter((t) => t != null); const validMetar = metarPoints.filter((t) => t != null); - const allVals = [...validDebTemps, ...validMetar]; + const validMgm = mgmPoints.filter((t) => t != null); + const allVals = [...validDebTemps, ...validMetar, ...validMgm]; if (allVals.length === 0) { document.getElementById("chartLegend").textContent = "ๆๆ ๆฐๆฎ"; return; @@ -555,11 +584,26 @@ function renderChart(data) { pointHoverRadius: 7, pointStyle: "circle", fill: false, - showLine: false, order: 0, }, ]; + if (validMgm.length > 0) { + datasets.push({ + label: "MGMๅฎๆต", + data: mgmPoints, + borderColor: "#facc15", + backgroundColor: "#facc15", + borderWidth: 0, + pointRadius: 7, + pointHoverRadius: 9, + pointStyle: "star", + fill: false, + showLine: false, + order: -1, // Draw on very top + }); + } + // Add subtle OM reference line if DEB offset is significant if (Math.abs(offset) > 0.3) { datasets.push({ @@ -648,6 +692,9 @@ function renderChart(data) { // Chart legend text const legend = document.getElementById("chartLegend"); const legendParts = []; + if (data.mgm?.temp != null) { + legendParts.push(`MGM: ${data.mgm.temp}${data.temp_symbol}`); + } if (debMax != null && omMax != null && Math.abs(offset) > 0.3) { const sign = offset > 0 ? "+" : ""; legendParts.push(`DEBๅ็งป ${sign}${offset.toFixed(1)}ยฐ vs OM`); @@ -827,16 +874,18 @@ function renderAI(data) { } function renderMarket(data) { + const widget = document.getElementById("marketFloatingWidget"); const container = document.getElementById("marketOdds"); if ( !data.polymarket || !data.polymarket.markets || data.polymarket.markets.length === 0 ) { - container.innerHTML = '