const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); /** * GLM-5 Tahmin Yaklaşımı * ====================== * Bir maç için eldeki veriler: * - Takım isimleri (ev sahibi, deplasman) * - Oranlar (MS, Alt/Üst, BTTS, DC) * - Sakatlar/Cezalılar * - Lig * - Hakem * * Hedef: Maç sonucunu tahmin etmek (1/X/2) */ async function glm5PredictionApproach() { console.log('\n'); console.log( '╔══════════════════════════════════════════════════════════════════╗', ); console.log( '║ GLM-5 TAHMİN YAKLAŞIMI - VERİTABANI ANALİZİ ║', ); console.log( '╚══════════════════════════════════════════════════════════════════╝', ); console.log('\n'); // ===================================== // BÖLÜM 1: VERİTABANI HAZİNESİ // ===================================== console.log('📦 BÖLÜM 1: VERİTABANI HAZİNESİ'); console.log('─'.repeat(50)); const stats = { matches: await prisma.match.count({ where: { sport: 'football', state: 'postGame' }, }), odds: await prisma.oddSelection.count(), events: await prisma.matchPlayerEvents.count(), teamStats: await prisma.matchTeamStats.count(), officials: await prisma.matchOfficial.count(), }; console.log(`\nKullanılabilir Veri Miktarı:`); console.log(` ⚽ ${stats.matches.toLocaleString()} bitmiş futbol maçı`); console.log(` 📊 ${stats.odds.toLocaleString()} oran kaydı`); console.log( ` ⚡ ${stats.events.toLocaleString()} maç olayı (gol, kart, değişiklik)`, ); console.log(` 📈 ${stats.teamStats.toLocaleString()} takım istatistiği`); console.log(` 👨‍⚖️ ${stats.officials.toLocaleString()} hakem kaydı`); // ===================================== // BÖLÜM 2: TAHMİN FAKTÖRLERİ // ===================================== console.log('\n\n🧠 BÖLÜM 2: TAHMİN FAKTÖRLERİ'); console.log('─'.repeat(50)); console.log(` Bir maç sonucunu etkileyen faktörler ve veritabanından nasıl çıkarılır: ┌─────────────────────────────────────────────────────────────────────┐ │ FAKTÖR │ VERİTABANI KAYNAĞI │ ├─────────────────────────────────────────────────────────────────────┤ │ 1. Takım Gücü │ Son maçlarda gol atma/yeme ortalaması │ │ 2. Ev/Deplasman Avantajı │ Ev sahibi %52, Deplasman %28, Berabere %20│ │ 3. Form Durumu │ Son 5 maçta alınan puanlar │ │ 4. Oranlar │ Bookmaker'ın fiyatlaması (implied prob) │ │ 5. Sakat/Cezalı │ sidelined_data JSON alanı │ │ 6. Hakem Etkisi │ Hakemin istatistikleri │ │ 7. Lig Özelliği │ Gol ortalamaları, ev avantajı │ │ 8. Head-to-Head │ Karşılıklı geçmiş maçlar │ └─────────────────────────────────────────────────────────────────────┘ `); // ===================================== // BÖLÜM 3: ÖRNEK ANALİZ // ===================================== console.log('\n\n🎯 BÖLÜM 3: ÖRNEK MAÇ ANALİZİ'); console.log('─'.repeat(50)); // preGame durumundaki bir maç bul const match = await prisma.match.findFirst({ where: { sport: 'football', state: 'preGame' }, include: { homeTeam: true, awayTeam: true, league: true, oddCategories: { include: { selections: true } }, officials: { include: { role: true } }, }, }); if (!match) { // Son bitmiş maçı kullan const finishedMatch = await prisma.match.findFirst({ where: { sport: 'football', state: 'postGame', scoreHome: { not: null } }, include: { homeTeam: true, awayTeam: true, league: true, oddCategories: { include: { selections: true } }, officials: { include: { role: true } }, }, orderBy: { mstUtc: 'desc' }, }); if (finishedMatch) { await analyzeMatch(finishedMatch, true); } } else { await analyzeMatch(match, false); } await prisma.$disconnect(); } async function analyzeMatch(match, isFinished) { console.log(`\n⚽ MAÇ: ${match.homeTeam?.name} vs ${match.awayTeam?.name}`); console.log(`🏆 Lig: ${match.league?.name}`); console.log(`📅 Tarih: ${new Date(Number(match.mstUtc)).toISOString()}`); if (isFinished) { console.log(`📊 Gerçek Skor: ${match.scoreHome} - ${match.scoreAway}`); } // ═════════════════════════════════════════════════════════════════ // ADIM 1: ORANLARI OKU VE IMPLIED PROBABILITY HESAPLA // ═════════════════════════════════════════════════════════════════ console.log('\n📊 ADIM 1: ORAN ANALİZİ'); console.log('─'.repeat(40)); const odds = {}; for (const cat of match.oddCategories) { for (const sel of cat.selections) { if (cat.name?.includes('Maç Sonucu') || cat.name === 'MS') { if (sel.name === '1') odds.ms_home = parseFloat(sel.oddValue); if (sel.name === 'X') odds.ms_draw = parseFloat(sel.oddValue); if (sel.name === '2') odds.ms_away = parseFloat(sel.oddValue); } if (cat.name?.includes('2,5') || cat.name?.includes('2.5')) { if (sel.name === 'Alt') odds.ou25_under = parseFloat(sel.oddValue); if (sel.name === 'Üst') odds.ou25_over = parseFloat(sel.oddValue); } if (cat.name?.includes('Karşılıklı') || cat.name?.includes('KG')) { if (sel.name === 'Var' || sel.name === 'Evet') odds.btts_yes = parseFloat(sel.oddValue); if (sel.name === 'Yok' || sel.name === 'Hayır') odds.btts_no = parseFloat(sel.oddValue); } } } // Implied probability hesapla if (odds.ms_home && odds.ms_draw && odds.ms_away) { const rawHome = (1 / odds.ms_home) * 100; const rawDraw = (1 / odds.ms_draw) * 100; const rawAway = (1 / odds.ms_away) * 100; const total = rawHome + rawDraw + rawAway; console.log( `\nOranlar: 1=${odds.ms_home} | X=${odds.ms_draw} | 2=${odds.ms_away}`, ); console.log( `Ham Implied Probability: 1=%${rawHome.toFixed(1)} | X=%${rawDraw.toFixed(1)} | 2=%${rawAway.toFixed(1)}`, ); console.log(`Bookmaker Margin: %${(total - 100).toFixed(1)}`); // Normalize edilmiş const normHome = (rawHome / total) * 100; const normDraw = (rawDraw / total) * 100; const normAway = (rawAway / total) * 100; console.log( `Normalize: 1=%${normHome.toFixed(1)} | X=%${normDraw.toFixed(1)} | 2=%${normAway.toFixed(1)}`, ); odds.normHome = normHome; odds.normDraw = normDraw; odds.normAway = normAway; } // ═════════════════════════════════════════════════════════════════ // ADIM 2: TAKIM GEÇMİŞ PERFORMANSI // ═════════════════════════════════════════════════════════════════ console.log('\n📈 ADIM 2: TAKIM PERFORMANS ANALİZİ'); console.log('─'.repeat(40)); // Ev sahibi son 10 maç const homeMatches = await prisma.match.findMany({ where: { OR: [{ homeTeamId: match.homeTeamId }, { awayTeamId: match.homeTeamId }], sport: 'football', state: 'postGame', scoreHome: { not: null }, scoreAway: { not: null }, }, orderBy: { mstUtc: 'desc' }, take: 10, }); const homeStats = calculateTeamStats(homeMatches, match.homeTeamId); console.log(`\n🏠 ${match.homeTeam?.name}:`); console.log( ` Son 10: ${homeStats.wins}G ${homeStats.draws}B ${homeStats.losses}M`, ); console.log( ` Gol: ${homeStats.goalsFor} attı, ${homeStats.goalsAgainst} yedi`, ); console.log(` Ortalama: ${(homeStats.goalsFor / 10).toFixed(2)} gol/maç`); // Deplasman son 10 maç const awayMatches = await prisma.match.findMany({ where: { OR: [{ homeTeamId: match.awayTeamId }, { awayTeamId: match.awayTeamId }], sport: 'football', state: 'postGame', scoreHome: { not: null }, scoreAway: { not: null }, }, orderBy: { mstUtc: 'desc' }, take: 10, }); const awayStats = calculateTeamStats(awayMatches, match.awayTeamId); console.log(`\n✈️ ${match.awayTeam?.name}:`); console.log( ` Son 10: ${awayStats.wins}G ${awayStats.draws}B ${awayStats.losses}M`, ); console.log( ` Gol: ${awayStats.goalsFor} attı, ${awayStats.goalsAgainst} yedi`, ); console.log(` Ortalama: ${(awayStats.goalsFor / 10).toFixed(2)} gol/maç`); // ═════════════════════════════════════════════════════════════════ // ADIM 3: HAKEM ANALİZİ // ═════════════════════════════════════════════════════════════════ console.log('\n👨‍⚖️ ADIM 3: HAKEM ANALİZİ'); console.log('─'.repeat(40)); const mainReferee = match.officials?.find( (o) => o.role?.name === 'Orta Hakem', ); if (mainReferee) { console.log(`\nHakem: ${mainReferee.name}`); // Bu hakemin yönettiği maçları bul const refereeMatches = await prisma.matchOfficial.findMany({ where: { name: mainReferee.name, roleId: 1 }, include: { match: true }, take: 20, }); if (refereeMatches.length > 0) { let homeWins = 0, draws = 0, awayWins = 0; let totalCards = 0; for (const rm of refereeMatches) { if (rm.match?.scoreHome !== null && rm.match?.scoreAway !== null) { if (rm.match.scoreHome > rm.match.scoreAway) homeWins++; else if (rm.match.scoreHome < rm.match.scoreAway) awayWins++; else draws++; } } const total = homeWins + draws + awayWins; if (total > 0) { console.log(` Yönettiği maçlar: ${total}`); console.log( ` Ev sahibi kazanma: %${((homeWins / total) * 100).toFixed(1)}`, ); console.log(` Beraberlik: %${((draws / total) * 100).toFixed(1)}`); console.log( ` Deplasman kazanma: %${((awayWins / total) * 100).toFixed(1)}`, ); } } } else { console.log('Hakem bilgisi yok'); } // ═════════════════════════════════════════════════════════════════ // ADIM 4: LİG ÖZELLİKLERİ // ═════════════════════════════════════════════════════════════════ console.log('\n🏆 ADIM 4: LİG ANALİZİ'); console.log('─'.repeat(40)); const leagueMatches = await prisma.match.findMany({ where: { leagueId: match.leagueId, sport: 'football', state: 'postGame' }, take: 100, }); let leagueHomeWins = 0, leagueDraws = 0, leagueAwayWins = 0; let leagueGoals = 0; for (const lm of leagueMatches) { if (lm.scoreHome !== null && lm.scoreAway !== null) { leagueGoals += lm.scoreHome + lm.scoreAway; if (lm.scoreHome > lm.scoreAway) leagueHomeWins++; else if (lm.scoreHome < lm.scoreAway) leagueAwayWins++; else leagueDraws++; } } const leagueTotal = leagueHomeWins + leagueDraws + leagueAwayWins; if (leagueTotal > 0) { console.log(`\nLig: ${match.league?.name}`); console.log( ` Ev sahibi kazanma: %${((leagueHomeWins / leagueTotal) * 100).toFixed(1)}`, ); console.log( ` Beraberlik: %${((leagueDraws / leagueTotal) * 100).toFixed(1)}`, ); console.log( ` Deplasman kazanma: %${((leagueAwayWins / leagueTotal) * 100).toFixed(1)}`, ); console.log( ` Ortalama gol: ${(leagueGoals / leagueTotal).toFixed(2)}/maç`, ); } // ═════════════════════════════════════════════════════════════════ // ADIM 5: GLM-5 TAHMİN MODELİ // ═════════════════════════════════════════════════════════════════ console.log('\n\n🤖 ADIM 5: GLM-5 TAHMİN MODELİ'); console.log('═'.repeat(50)); // Ağırlıklar const weights = { odds: 0.4, // Bookmaker en güvenilir form: 0.25, // Son performans homeAdvantage: 0.15, // Ev sahibi avantajı league: 0.1, // Lig eğilimleri referee: 0.1, // Hakem etkisi }; console.log(`\nAğırlıklar:`); console.log(` Oranlar: %${weights.odds * 100}`); console.log(` Form: %${weights.form * 100}`); console.log(` Ev Avantajı: %${weights.homeAdvantage * 100}`); console.log(` Lig: %${weights.league * 100}`); console.log(` Hakem: %${weights.referee * 100}`); // Base skorlar (oranlardan) let homeScore = odds.normHome || 33; let drawScore = odds.normDraw || 33; let awayScore = odds.normAway || 33; // Form düzeltmesi const homeFormScore = ((homeStats.wins * 3 + homeStats.draws) / 30) * 100; const awayFormScore = ((awayStats.wins * 3 + awayStats.draws) / 30) * 100; const formDiff = homeFormScore - awayFormScore; console.log(`\nForm Skorları:`); console.log(` Ev Sahibi: ${homeFormScore.toFixed(1)}`); console.log(` Deplasman: ${awayFormScore.toFixed(1)}`); console.log(` Fark: ${formDiff.toFixed(1)} (ev lehine pozitif)`); // Ev sahibi avantajı (genel istatistik) const homeAdvantageBonus = 8; // %8 ev sahibi avantajı // Final hesaplama homeScore = (odds.normHome || 33) * weights.odds + homeFormScore * 0.5 * weights.form + homeAdvantageBonus * weights.homeAdvantage + (leagueHomeWins / leagueTotal) * 100 * weights.league; awayScore = (odds.normAway || 33) * weights.odds + awayFormScore * 0.5 * weights.form + 0 * weights.homeAdvantage + // Deplasman avantajı yok (leagueAwayWins / leagueTotal) * 100 * weights.league; drawScore = (odds.normDraw || 33) * weights.odds + (100 - Math.abs(formDiff)) * 0.1 * weights.form + (leagueDraws / leagueTotal) * 100 * weights.league; // Normalize const totalScore = homeScore + drawScore + awayScore; const finalHome = (homeScore / totalScore) * 100; const finalDraw = (drawScore / totalScore) * 100; const finalAway = (awayScore / totalScore) * 100; console.log(`\n🎯 FINAL TAHMİN:`); console.log('─'.repeat(40)); console.log(` 1 (Ev Sahibi): %${finalHome.toFixed(1)}`); console.log(` X (Beraberlik): %${finalDraw.toFixed(1)}`); console.log(` 2 (Deplasman): %${finalAway.toFixed(1)}`); // Kazanan belirle let prediction, confidence; if (finalHome > finalDraw && finalHome > finalAway) { prediction = '1'; confidence = finalHome; } else if (finalAway > finalDraw) { prediction = '2'; confidence = finalAway; } else { prediction = 'X'; confidence = finalDraw; } console.log(`\n🏆 TAHMİN: ${prediction}`); console.log(` Güven: %${confidence.toFixed(1)}`); // Alt/Üst tahmini const avgGoals = (homeStats.goalsFor + homeStats.goalsAgainst + awayStats.goalsFor + awayStats.goalsAgainst) / 20; const ou25Prediction = avgGoals > 2.5 ? 'ÜST' : 'ALT'; console.log(`\n⚽ 2.5 ${ou25Prediction} (Ort: ${avgGoals.toFixed(2)} gol)`); if (isFinished) { console.log(`\n✅ GERÇEK SONUÇ: ${match.scoreHome} - ${match.scoreAway}`); const actual = match.scoreHome > match.scoreAway ? '1' : match.scoreHome < match.scoreAway ? '2' : 'X'; console.log(` Tahmin ${prediction === actual ? 'DOĞRU ✓' : 'YANLIŞ ✗'}`); } } function calculateTeamStats(matches, teamId) { let wins = 0, draws = 0, losses = 0; let goalsFor = 0, goalsAgainst = 0; for (const m of matches) { const isHome = m.homeTeamId === teamId; const gf = isHome ? m.scoreHome : m.scoreAway; const ga = isHome ? m.scoreAway : m.scoreHome; goalsFor += gf || 0; goalsAgainst += ga || 0; if (gf > ga) wins++; else if (gf < ga) losses++; else draws++; } return { wins, draws, losses, goalsFor, goalsAgainst }; } glm5PredictionApproach().catch(console.error);