import os import sys import psycopg2 from psycopg2.extras import RealDictCursor # Path ayarları sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from services.single_match_orchestrator import SingleMatchOrchestrator from services.feature_enrichment import FeatureEnrichmentService DSN = "postgresql://suggestbet:SuGGesT2026SecuRe@localhost:15432/boilerplate_db" def run_backtest(target_date="2026-05-03"): conn = psycopg2.connect(DSN) cur = conn.cursor(cursor_factory=RealDictCursor) # 1. Hedef tarihteki bitmiş maçları ve takım isimlerini getir cur.execute(""" SELECT m.id, m.score_home, m.score_away, m.mst_utc, t1.name as home_name, t2.name as away_name FROM matches m LEFT JOIN teams t1 ON m.home_team_id = t1.id LEFT JOIN teams t2 ON m.away_team_id = t2.id WHERE m.status IN ('FT', 'AET', 'PEN') AND to_timestamp(m.mst_utc / 1000.0)::date = %s::date AND m.score_home IS NOT NULL ORDER BY m.mst_utc ASC """, (target_date,)) matches = cur.fetchall() if not matches: print(f"❌ {target_date} tarihinde bitmiş maç bulunamadı.") return print(f"🚀 {target_date} için Orkestratör Backtesti Başlatılıyor... ({len(matches)} maç bulundu)") print("-" * 60) orchestrator = SingleMatchOrchestrator() bets_placed = 0 won = 0 lost = 0 total_odds_won = 0.0 for match in matches: # 3. Üst Akıl (Orkestratör) analizi yapar try: package = orchestrator.analyze_match(match['id']) except Exception as e: print(f"Hata ({match['id']}): {e}") continue if not package: continue package_data = package # 4. Üst akıl bu maça bahis yapmaya karar verdi mi? bet_advice = package_data.get("bet_advice", {}) if bet_advice.get("playable") == True: bets_placed += 1 main_pick = package_data.get("main_pick", {}) market = main_pick.get("market") pick = main_pick.get("pick") odds = float(main_pick.get("odds", 0.0) or 0.0) # Skora göre kazanıp kazanmadığını kontrol et is_won = False h = match['score_home'] a = match['score_away'] if market == "MS": if pick == "1" and h > a: is_won = True elif pick in ("X", "0") and h == a: is_won = True elif pick == "2" and a > h: is_won = True elif market == "OU25": if pick == "Üst" and (h+a) > 2.5: is_won = True elif pick == "Alt" and (h+a) < 2.5: is_won = True elif market == "OU15": if pick == "Üst" and (h+a) > 1.5: is_won = True elif pick == "Alt" and (h+a) < 1.5: is_won = True elif market == "BTTS": if pick == "KG Var" and h > 0 and a > 0: is_won = True elif pick == "KG Yok" and (h == 0 or a == 0): is_won = True elif market == "DC": if pick == "1X" and h >= a: is_won = True elif pick == "12" and h != a: is_won = True elif pick == "X2" and h <= a: is_won = True if is_won: won += 1 total_odds_won += odds res = "✅ KAZANDI" else: lost += 1 res = "❌ KAYBETTİ" print(f"[{res}] {match['home_name']} {h}-{a} {match['away_name']} | Tahmin: {market} {pick} (Oran: {odds})") else: main_pick = package_data.get("main_pick", {}) reasons = main_pick.get("reasons", ["Bilinmeyen Neden"]) if main_pick else ["No main pick"] reason = " | ".join(reasons) if isinstance(reasons, list) else str(reasons) market_board = package_data.get("market_board", {}) main_pick_market = main_pick.get('market', 'N/A') if main_pick else 'N/A' main_pick_pick = main_pick.get('pick', 'N/A') if main_pick else 'N/A' print(f"[PAS] {match['home_name']} {match['score_home']}-{match['score_away']} {match['away_name']} | Reddedilen: {main_pick_market} {main_pick_pick} -> Neden: {reason}") if "market_passed_all_gates" in reason: print(f" DEBUG: bet_advice = {bet_advice}") v25_ms = market_board.get("MS", {}).get("probs", {}) v27_ms = {} # V27 is merged into V25 probabilities in market_board, or we don't have separate V27 access here # Skora göre ms kontrolü h = match['score_home'] a = match['score_away'] actual_ms = "1" if h > a else ("X" if h == a else "2") v25_top = max(v25_ms, key=v25_ms.get) if v25_ms else "N/A" v27_top = "N/A" rejected_market = main_pick.get("market", "N/A") if main_pick else "N/A" rejected_pick = main_pick.get("pick", "N/A") if main_pick else "N/A" print(f"[PAS] {match['home_name']} {h}-{a} {match['away_name']} | Reddedilen: {rejected_market} {rejected_pick} -> Neden: {reason}") print(f" [V25 MS Raw: {v25_top}] [Gerçek MS: {actual_ms}]") # Sonuç Raporu print("\n" + "=" * 60) print(f"📊 BACKTEST SONUÇLARI ({target_date})") print("=" * 60) print(f"Toplam Maç Sayısı : {len(matches)}") print(f"Oynanan Bahis Sayısı: {bets_placed} (Oynama Oranı: %{bets_placed/len(matches)*100:.1f})") print(f"Riskli Bulunup Pas Geçilen: {len(matches) - bets_placed}") if bets_placed > 0: win_rate = won / bets_placed * 100 roi = ((total_odds_won - bets_placed) / bets_placed) * 100 print(f"Kazanılan : {won}") print(f"Kaybedilen : {lost}") print(f"İsabet Oranı : %{win_rate:.1f}") print(f"Net Kar (ROI) : %{roi:.1f} {'📈' if roi > 0 else '📉'}") if __name__ == "__main__": run_backtest("2026-05-03")