Files
fahricansecer 2f0b85a0c7
Deploy Iddaai Backend / build-and-deploy (push) Failing after 18s
first (part 2: other directories)
2026-04-16 15:11:25 +03:00

251 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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()