@@ -0,0 +1,136 @@
|
||||
"""
|
||||
VQWEN Full Backtest
|
||||
===================
|
||||
Tests all 3 VQWEN models (MS, OU25, BTTS) on 1000 historical matches.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import pickle
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import psycopg2
|
||||
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_vqwen_backtest():
|
||||
print("🧠 VQWEN FULL BACKTEST")
|
||||
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 MS, OU25, BTTS modelleri yüklendi.")
|
||||
except Exception as e:
|
||||
print(f"❌ Model hatası: {e}")
|
||||
return
|
||||
|
||||
with open(os.path.join(PROJECT_ROOT, "top_leagues.json"), 'r') as f:
|
||||
league_ids = tuple(str(lid) for lid in json.load(f))
|
||||
|
||||
dsn = get_clean_dsn()
|
||||
conn = psycopg2.connect(dsn)
|
||||
cur = conn.cursor(cursor_factory=RealDictCursor)
|
||||
|
||||
cur.execute("""
|
||||
SELECT m.id, m.home_team_id, m.away_team_id, m.score_home, m.score_away,
|
||||
t1.name as home_team, t2.name as away_team,
|
||||
(SELECT os.odd_value FROM odd_categories oc JOIN odd_selections os ON os.odd_category_db_id = oc.db_id WHERE oc.match_id = m.id AND oc.name ILIKE 'Maç Sonucu' AND os.name = '1' LIMIT 1) as oh,
|
||||
(SELECT os.odd_value FROM odd_categories oc JOIN odd_selections os ON os.odd_category_db_id = oc.db_id WHERE oc.match_id = m.id AND oc.name ILIKE 'Maç Sonucu' AND os.name = 'X' LIMIT 1) as od,
|
||||
(SELECT os.odd_value FROM odd_categories oc JOIN odd_selections os ON os.odd_category_db_id = oc.db_id WHERE oc.match_id = m.id AND oc.name ILIKE 'Maç Sonucu' AND os.name = '2' LIMIT 1) as oa,
|
||||
COALESCE((SELECT AVG(CASE WHEN m2.home_team_id = m.home_team_id AND m2.score_home > m2.score_away THEN 3 WHEN m2.home_team_id = m.home_team_id AND m2.score_home = m2.score_away THEN 1 ELSE 0 END) FROM matches m2 WHERE m2.home_team_id = m.home_team_id AND m2.status = 'FT' AND m2.mst_utc < m.mst_utc LIMIT 5), 0) as h_form,
|
||||
COALESCE((SELECT AVG(CASE WHEN m2.away_team_id = m.away_team_id AND m2.score_away > m2.score_home THEN 3 WHEN m2.away_team_id = m.away_team_id AND m2.score_away = m2.score_home THEN 1 ELSE 0 END) FROM matches m2 WHERE m2.away_team_id = m.away_team_id AND m2.status = 'FT' AND m2.mst_utc < m.mst_utc LIMIT 5), 0) as a_form,
|
||||
COALESCE((SELECT AVG(m2.score_home) FROM matches m2 WHERE m2.home_team_id = m.home_team_id AND m2.status = 'FT' LIMIT 10), 1.2) as h_sc,
|
||||
COALESCE((SELECT AVG(m2.score_away) FROM matches m2 WHERE m2.away_team_id = m.home_team_id AND m2.status = 'FT' LIMIT 10), 1.2) as h_co,
|
||||
COALESCE((SELECT AVG(m2.score_away) FROM matches m2 WHERE m2.away_team_id = m.away_team_id AND m2.status = 'FT' LIMIT 10), 1.2) as a_sc,
|
||||
COALESCE((SELECT AVG(m2.score_home) FROM matches m2 WHERE m2.home_team_id = m.away_team_id AND m2.status = 'FT' LIMIT 10), 1.2) as a_co
|
||||
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.league_id IN %s AND m.status = 'FT' AND m.score_home IS NOT NULL
|
||||
ORDER BY m.mst_utc DESC
|
||||
LIMIT 1000
|
||||
""", (league_ids,))
|
||||
|
||||
rows = cur.fetchall()
|
||||
print(f"📊 {len(rows)} maç analiz ediliyor...")
|
||||
|
||||
results = {'ms': {'bet': 0, 'won': 0, 'profit': 0}, 'ou25': {'bet': 0, 'won': 0, 'profit': 0}, 'btts': {'bet': 0, 'won': 0, 'profit': 0}}
|
||||
|
||||
for row in rows:
|
||||
oh, od, oa = float(row['oh'] or 0), float(row['od'] or 0), float(row['oa'] or 0)
|
||||
if oh <= 1.0 or od <= 1.0 or oa <= 1.0: continue
|
||||
|
||||
h_xg = (float(row['h_sc'] or 1.2) + float(row['a_co'] or 1.2)) / 2
|
||||
a_xg = (float(row['a_sc'] or 1.2) + float(row['h_co'] or 1.2)) / 2
|
||||
h_p = (float(row['h_form'] or 0)*10) + (float(row['h_sc'] or 1.2)*5) - (float(row['h_co'] or 1.2)*5)
|
||||
a_p = (float(row['a_form'] or 0)*10) + (float(row['a_sc'] or 1.2)*5) - (float(row['a_co'] or 1.2)*5)
|
||||
|
||||
margin = (1/oh) + (1/od) + (1/oa)
|
||||
|
||||
# MS Prediction
|
||||
f_ms = pd.DataFrame([{'h_form': float(row['h_form']), 'a_form': float(row['a_form']), 'h_xg': h_xg, 'a_xg': a_xg,
|
||||
'pow_diff': h_p - a_p, 'imp_h': (1/oh)/margin, 'imp_d': (1/od)/margin, 'imp_a': (1/oa)/margin,
|
||||
'h_sot': 4.0, 'a_sot': 3.0}])
|
||||
ms_probs = model_ms.predict(f_ms)[0]
|
||||
|
||||
# MS Value Bet
|
||||
for i, (pick, prob, odd) in enumerate(zip(['1', 'X', '2'], ms_probs, [oh, od, oa])):
|
||||
if odd <= 1.0: continue
|
||||
edge = prob - (1/odd)
|
||||
if edge > 0.05 and prob > 0.50: # Value ve Güven
|
||||
results['ms']['bet'] += 1
|
||||
h, a = row['score_home'], row['score_away']
|
||||
w = (pick=='1' and h>a) or (pick=='X' and h==a) or (pick=='2' and a>h)
|
||||
if w: results['ms']['won'] += 1; results['ms']['profit'] += (odd - 1.0)
|
||||
else: results['ms']['profit'] -= 1.0
|
||||
break
|
||||
|
||||
# OU2.5 Prediction
|
||||
f_ou = pd.DataFrame([{'h_xg': h_xg, 'a_xg': a_xg, 'total_xg': h_xg+a_xg, 'h_sot': 4.0, 'a_sot': 3.0}])
|
||||
p_over = model_ou.predict(f_ou)[0]
|
||||
|
||||
# OU2.5 Value Bet
|
||||
if p_over > 0.55 and oh > 1.0: # Sadece örnek olarak over > %55 ise
|
||||
results['ou25']['bet'] += 1
|
||||
if (row['score_home'] + row['score_away']) > 2.5: results['ou25']['won'] += 1; results['ou25']['profit'] += 0.85 # Ortalama oran
|
||||
else: results['ou25']['profit'] -= 1.0
|
||||
|
||||
# BTTS Prediction
|
||||
f_btts = pd.DataFrame([{'h_xg': h_xg, 'a_xg': a_xg, 'h_sc': float(row['h_sc']), 'a_sc': float(row['a_sc'])}])
|
||||
p_btts = model_btts.predict(f_btts)[0]
|
||||
|
||||
# BTTS Value Bet
|
||||
if p_btts > 0.55:
|
||||
results['btts']['bet'] += 1
|
||||
if row['score_home'] > 0 and row['score_away'] > 0: results['btts']['won'] += 1; results['btts']['profit'] += 0.85
|
||||
else: results['btts']['profit'] -= 1.0
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("📊 VQWEN PAZAR BAZLI SONUÇLAR")
|
||||
print("="*60)
|
||||
for mkt in ['ms', 'ou25', 'btts']:
|
||||
r = results[mkt]
|
||||
wr = (r['won'] / r['bet'] * 100) if r['bet'] > 0 else 0
|
||||
print(f"{mkt.upper():<10} Oynanan: {r['bet']:<5} Kazanılan: {r['won']:<5} WR: {wr:.1f}% Kâr: {r['profit']:+.2f} Units")
|
||||
|
||||
total_profit = sum(r['profit'] for r in results.values())
|
||||
print(f"\n💰 TOPLAM KÂR: {total_profit:+.2f} Units")
|
||||
if total_profit > 0: print("🟢 PARA KAZANDIK!")
|
||||
else: print("🔴 ZARARDA")
|
||||
|
||||
cur.close()
|
||||
conn.close()
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_vqwen_backtest()
|
||||
Reference in New Issue
Block a user