""" VQWEN Live Prediction Tracker ============================= Predicts today's upcoming matches (from live_matches) and tracks results. """ import os import sys import json import time import pickle import psycopg2 import pandas as pd import numpy as np from psycopg2.extras import RealDictCursor AI_DIR = os.path.dirname(os.path.abspath(__file__)) ROOT_DIR = os.path.dirname(AI_DIR) PROJECT_ROOT = os.path.dirname(ROOT_DIR) def get_clean_dsn() -> str: return "postgresql://suggestbet:SuGGesT2026SecuRe@localhost:15432/boilerplate_db" def run_live_predictions(): print("🔴 VQWEN LIVE PREDICTION TRACKER") print("="*60) # Load Models mdir = os.path.join(ROOT_DIR, 'models', 'vqwen') try: with open(os.path.join(mdir, 'vqwen_ms.pkl'), 'rb') as f: model_ms = pickle.load(f) with open(os.path.join(mdir, 'vqwen_ou25.pkl'), 'rb') as f: model_ou = pickle.load(f) with open(os.path.join(mdir, 'vqwen_btts.pkl'), 'rb') as f: model_btts = pickle.load(f) print("✅ VQWEN v3 modelleri yüklendi.") except Exception as e: print(f"❌ Model hatası: {e}") return dsn = get_clean_dsn() conn = psycopg2.connect(dsn) cur = conn.cursor(cursor_factory=RealDictCursor) # 1. Bugünün Maçlarını Çek (NS veya oynanıyor ama henüz bitmemiş olanlar) # mst_utc bugün olan maçlar start_of_day = int(time.mktime(time.strptime(time.strftime("%Y-%m-%d"), "%Y-%m-%d")) * 1000) end_of_day = start_of_day + (24 * 60 * 60 * 1000) print(f"📅 Bugünün maçları taranıyor...") # live_matches veya matches tablosundan bugünkü maçları alıyoruz # Önce odds olanları alalım cur.execute(""" SELECT m.id, m.home_team_id, m.away_team_id, m.score_home, m.score_away, m.mst_utc, m.status, t1.name as home_team, t2.name as away_team, l.name as league_name, maf.home_elo, maf.away_elo FROM live_matches m LEFT JOIN teams t1 ON m.home_team_id = t1.id LEFT JOIN teams t2 ON m.away_team_id = t2.id LEFT JOIN leagues l ON m.league_id = l.id LEFT JOIN football_ai_features maf ON maf.match_id = m.id WHERE m.mst_utc >= %s AND m.mst_utc <= %s ORDER BY m.mst_utc ASC """, (start_of_day, end_of_day)) rows = cur.fetchall() print(f"📊 Bugün için {len(rows)} maç bulundu.") if not rows: print("⚠️ Bugün için oranı olan maç bulunamadı.") cur.close() conn.close() return results = [] total_profit = 0.0 total_bet = 0 total_won = 0 for i, row in enumerate(rows): match_id = str(row['id']) home = row['home_team'] or "Home" away = row['away_team'] or "Away" league = row['league_name'] or "Unknown" # Maç bitmiş mi kontrol et is_finished = row['status'] in ['FT', 'AET', 'PEN', 'post', 'postGame'] or ( row['score_home'] is not None and row['score_away'] is not None and row['status'] not in ['NS', 'pre', 'preGame', 'live', 'liveGame'] ) # Oranları al (odd_categories) cur.execute(""" SELECT oc.name as category, os.name as selection, os.odd_value FROM odd_categories oc JOIN odd_selections os ON os.odd_category_db_id = oc.db_id WHERE oc.match_id = %s AND oc.name ILIKE ANY (ARRAY['%%Maç Sonucu%%', '%%2,5 Alt/Üst%%', '%%Karşılıklı Gol%%']) """, (match_id,)) odds_rows = cur.fetchall() odds_dict = {} for o in odds_rows: cat = o['category'].lower() sel = o['selection'].lower() val = float(o['odd_value']) if 'maç sonucu' in cat or 'mac sonucu' in cat: if sel == '1': odds_dict['ms_h'] = val elif sel == 'x': odds_dict['ms_d'] = val elif sel == '2': odds_dict['ms_a'] = val elif '2,5 alt' in cat or '2.5 alt' in cat: if 'alt' in sel: odds_dict['ou25_u'] = val elif 'üst' in sel or 'ust' in sel: odds_dict['ou25_o'] = val elif 'karşılıklı gol' in cat: if 'var' in sel: odds_dict['btts_y'] = val elif 'yok' in sel: odds_dict['btts_n'] = val # Eğer oranlar yoksa atla if not all(k in odds_dict for k in ['ms_h', 'ms_d', 'ms_a', 'ou25_o', 'btts_y']): # print(f"⚠️ {home} vs {away} - Oranlar eksik.") continue # Özellikleri Hesapla # Form, Rest, Contextual Goals veritabanından çekilmeli (canlı maç için) cur.execute(""" SELECT COALESCE((SELECT AVG(m2.score_home) FROM matches m2 WHERE m2.home_team_id = %s AND m2.status = 'FT' AND m2.mst_utc < %s), 1.2) as h_home_goals, COALESCE((SELECT AVG(m2.score_away) FROM matches m2 WHERE m2.away_team_id = %s AND m2.status = 'FT' AND m2.mst_utc < %s), 1.2) as a_away_goals, COALESCE(EXTRACT(EPOCH FROM (to_timestamp(%s/1000) - (SELECT MAX(to_timestamp(m2.mst_utc/1000)) FROM matches m2 WHERE m2.home_team_id = %s AND m2.status = 'FT' AND m2.mst_utc < %s)) / 86400), 7) as h_rest, COALESCE(EXTRACT(EPOCH FROM (to_timestamp(%s/1000) - (SELECT MAX(to_timestamp(m2.mst_utc/1000)) FROM matches m2 WHERE m2.away_team_id = %s AND m2.status = 'FT' AND m2.mst_utc < %s)) / 86400), 7) as a_rest, COALESCE((SELECT COUNT(*) FROM match_player_participation mp WHERE mp.match_id = %s AND mp.team_id = %s AND mp.is_starting = true), 11) as h_xi, COALESCE((SELECT COUNT(*) FROM match_player_participation mp WHERE mp.match_id = %s AND mp.team_id = %s AND mp.is_starting = true), 11) as a_xi, COALESCE((SELECT COUNT(*) FILTER (WHERE m2.score_home > m2.score_away)::float / NULLIF(COUNT(*), 0) FROM matches m2 WHERE m2.home_team_id = %s AND m2.away_team_id = m2.away_team_id AND m2.status = 'FT' AND m2.mst_utc < %s), 0.5) as h2h_h_wr, COALESCE((SELECT SUM(pts) FROM (SELECT CASE WHEN m2.score_home > m2.score_away THEN 3 WHEN m2.score_home = m2.score_away THEN 1 ELSE 0 END as pts FROM matches m2 WHERE m2.home_team_id = %s AND m2.status = 'FT' AND m2.mst_utc < %s ORDER BY m2.mst_utc DESC LIMIT 5) sub), 0) as h_form_pts, COALESCE((SELECT SUM(pts) FROM (SELECT CASE WHEN m2.score_away > m2.score_home THEN 3 WHEN m2.score_away = m2.score_home THEN 1 ELSE 0 END as pts FROM matches m2 WHERE m2.away_team_id = %s AND m2.status = 'FT' AND m2.mst_utc < %s ORDER BY m2.mst_utc DESC LIMIT 5) sub), 0) as a_form_pts """, ( row['home_team_id'], row['mst_utc'], row['away_team_id'], row['mst_utc'], row['mst_utc'], row['home_team_id'], row['mst_utc'], row['mst_utc'], row['away_team_id'], row['mst_utc'], match_id, row['home_team_id'], match_id, row['away_team_id'], row['home_team_id'], row['away_team_id'], row['mst_utc'], row['home_team_id'], row['mst_utc'], row['away_team_id'], row['mst_utc'] )) stats = cur.fetchone() h_elo = float(row['home_elo'] or 1500) a_elo = float(row['away_elo'] or 1500) h_home_goals = float(stats['h_home_goals'] or 1.2) a_away_goals = float(stats['a_away_goals'] or 1.2) h_rest = float(stats['h_rest'] or 7) a_rest = float(stats['a_rest'] or 7) h_xi = float(stats['h_xi'] or 11) a_xi = float(stats['a_xi'] or 11) h2h_h_wr = float(stats['h2h_h_wr'] or 0.5) h_pts = float(stats['h_form_pts'] or 0) a_pts = float(stats['a_form_pts'] or 0) def fatigue(rest): if rest < 3: return 0.85 if rest < 5: return 0.95 return 1.0 h_fat = fatigue(h_rest) a_fat = fatigue(a_rest) h_xg = h_home_goals * h_fat a_xg = a_away_goals * a_fat margin = (1/odds_dict['ms_h']) + (1/odds_dict['ms_d']) + (1/odds_dict['ms_a']) features = pd.DataFrame([{ 'elo_diff': h_elo - a_elo, 'h_xg': h_xg, 'a_xg': a_xg, 'total_xg': h_xg + a_xg, 'pow_diff': (h_elo/100)*h_fat - (a_elo/100)*a_fat, 'rest_diff': h_rest - a_rest, 'h_fatigue': h_fat, 'a_fatigue': a_fat, 'imp_h': (1/odds_dict['ms_h'])/margin, 'imp_d': (1/odds_dict['ms_d'])/margin, 'imp_a': (1/odds_dict['ms_a'])/margin, 'h_xi': h_xi, 'a_xi': a_xi, 'h2h_h_wr': h2h_h_wr, 'form_diff': h_pts - a_pts }]) # --- TAHMİNLER --- ms_probs = model_ms.predict(features)[0] p_over = float(model_ou.predict(features)[0]) p_btts = float(model_btts.predict(features)[0]) # --- EN İYİ VALUE PICK --- picks = [] for pick, prob, odd in zip(['1', 'X', '2'], ms_probs, [odds_dict['ms_h'], odds_dict['ms_d'], odds_dict['ms_a']]): edge = prob - (1/odd) if edge > 0.05 and prob > 0.45: picks.append({"market": "MS", "pick": pick, "prob": prob, "odds": odd}) if p_over > 0.55: picks.append({"market": "OU2.5", "pick": "Over", "prob": p_over, "odds": odds_dict.get('ou25_o', 1.85)}) if p_btts > 0.55: picks.append({"market": "BTTS", "pick": "Var", "prob": p_btts, "odds": odds_dict.get('btts_y', 1.85)}) picks.sort(key=lambda x: (x['prob'] + max(0, x['prob'] - 1/x['odds'])*100), reverse=True) best_pick = picks[0] if picks else None # --- SONUÇ KONTROLÜ --- res_str = "⏳ Oynanıyor/Bekleniyor" won = None h_score = row['score_home'] a_score = row['score_away'] if is_finished and h_score is not None and a_score is not None: res_str = f"🏁 SONUÇ: {h_score}-{a_score}" if best_pick: p = best_pick['pick'] if p == '1': won = h_score > a_score elif p == 'X': won = h_score == a_score elif p == '2': won = a_score > h_score elif p == 'Over': won = (h_score + a_score) > 2.5 elif p == 'Var': won = h_score > 0 and a_score > 0 res_str += " | " + ("✅ KAZANDI" if won else "❌ KAYBETTİ") if won: total_profit += (best_pick['odds'] - 1.0) else: total_profit -= 1.0 total_bet += 1 if won: total_won += 1 # Çıktı match_time = time.strftime("%H:%M", time.gmtime(row['mst_utc']/1000)) pick_info = f"{best_pick['market']} - {best_pick['pick']} (%{best_pick['prob']*100:.0f} @ {best_pick['odds']:.2f})" if best_pick else "💤 Önerilen Bahis Yok" print(f"\n⚽ [{match_time}] {home} vs {away} ({league})") print(f" 🧠 Tahmin: {pick_info}") print(f" {res_str}") print("\n" + "="*60) print("📊 GÜNLÜK ÖZET") print("="*60) if total_bet > 0: print(f"🎲 Oynanan Bahis: {total_bet}") print(f"✅ Kazanan: {total_won}") print(f"💰 Toplam Kâr: {total_profit:.2f} Units") print(f"📈 ROI: {(total_profit/total_bet)*100:.1f}%") else: print("📝 Bugün için Value Bahis bulunamadı veya maçlar bitmedi.") cur.close() conn.close() if __name__ == "__main__": run_live_predictions()