501 lines
16 KiB
JavaScript
501 lines
16 KiB
JavaScript
const { PrismaClient } = require('@prisma/client');
|
||
const prisma = new PrismaClient();
|
||
|
||
async function analyzePredictionProcess() {
|
||
console.log('\n========================================');
|
||
console.log('🎯 MAÇ TAHMİN SÜRECİ ANALİZİ');
|
||
console.log('========================================\n');
|
||
|
||
// Mevcut maçların tarih aralığı
|
||
const oldestMatch = await prisma.match.findFirst({
|
||
where: { sport: 'football' },
|
||
orderBy: { mstUtc: 'asc' },
|
||
});
|
||
|
||
const newestMatch = await prisma.match.findFirst({
|
||
where: { sport: 'football' },
|
||
orderBy: { mstUtc: 'desc' },
|
||
});
|
||
|
||
console.log('📅 FUTBOL MAÇ TARİH ARALIĞI:');
|
||
console.log(
|
||
` En Eski: ${new Date(Number(oldestMatch.mstUtc)).toISOString()}`,
|
||
);
|
||
console.log(
|
||
` En Yeni: ${new Date(Number(newestMatch.mstUtc)).toISOString()}`,
|
||
);
|
||
|
||
// preGame durumundaki maçları bul
|
||
const upcomingMatches = await prisma.match.findMany({
|
||
where: {
|
||
sport: 'football',
|
||
state: 'preGame',
|
||
},
|
||
include: {
|
||
homeTeam: true,
|
||
awayTeam: true,
|
||
league: true,
|
||
oddCategories: {
|
||
include: { selections: true },
|
||
},
|
||
aiFeatures: true,
|
||
},
|
||
take: 5,
|
||
orderBy: { mstUtc: 'desc' },
|
||
});
|
||
|
||
console.log(`\n🔴 preGame Durumundaki Maçlar: ${upcomingMatches.length}`);
|
||
|
||
// Eğer preGame yoksa, son bitmiş maçları al
|
||
let selectedMatch = null;
|
||
if (upcomingMatches.length > 0) {
|
||
selectedMatch = upcomingMatches[0];
|
||
} else {
|
||
// Son bitmiş futbol maçını al (analiz için)
|
||
const recentMatches = await prisma.match.findMany({
|
||
where: {
|
||
sport: 'football',
|
||
state: 'postGame',
|
||
scoreHome: { not: null },
|
||
scoreAway: { not: null },
|
||
},
|
||
include: {
|
||
homeTeam: true,
|
||
awayTeam: true,
|
||
league: true,
|
||
oddCategories: {
|
||
include: { selections: true },
|
||
},
|
||
aiFeatures: true,
|
||
},
|
||
take: 1,
|
||
orderBy: { mstUtc: 'desc' },
|
||
});
|
||
|
||
if (recentMatches.length > 0) {
|
||
selectedMatch = recentMatches[0];
|
||
console.log(
|
||
'\n⚠️ preGame maçı bulunamadı. Son bitmiş maç analiz edilecek.',
|
||
);
|
||
}
|
||
}
|
||
|
||
if (!selectedMatch) {
|
||
console.log('Analiz edilecek maç bulunamadı.');
|
||
await prisma.$disconnect();
|
||
return;
|
||
}
|
||
|
||
console.log('\n========================================');
|
||
console.log('⚽ SEÇİLEN MAÇ');
|
||
console.log('========================================');
|
||
console.log(`Maç ID: ${selectedMatch.id}`);
|
||
console.log(`Ev Sahibi: ${selectedMatch.homeTeam?.name}`);
|
||
console.log(`Deplasman: ${selectedMatch.awayTeam?.name}`);
|
||
console.log(`Lig: ${selectedMatch.league?.name}`);
|
||
console.log(`Tarih: ${new Date(Number(selectedMatch.mstUtc)).toISOString()}`);
|
||
console.log(`Durum: ${selectedMatch.state}`);
|
||
if (selectedMatch.scoreHome !== null) {
|
||
console.log(
|
||
`Skor: ${selectedMatch.scoreHome} - ${selectedMatch.scoreAway}`,
|
||
);
|
||
}
|
||
console.log(`İddaa Kodu: ${selectedMatch.iddaaCode}`);
|
||
|
||
// =====================================
|
||
// ADIM 1: ORAN VERİLERİNİ TOPLA
|
||
// =====================================
|
||
console.log('\n========================================');
|
||
console.log('📊 ADIM 1: ORAN VERİLERİ');
|
||
console.log('========================================');
|
||
|
||
const oddsData = {};
|
||
const msCategory = selectedMatch.oddCategories.find((c) =>
|
||
c.name?.includes('Maç Sonucu'),
|
||
);
|
||
if (msCategory) {
|
||
for (const sel of msCategory.selections) {
|
||
if (sel.name === '1') oddsData.ms_h = parseFloat(sel.oddValue) || 0;
|
||
if (sel.name === 'X') oddsData.ms_d = parseFloat(sel.oddValue) || 0;
|
||
if (sel.name === '2') oddsData.ms_a = parseFloat(sel.oddValue) || 0;
|
||
}
|
||
}
|
||
|
||
const dcCategory = selectedMatch.oddCategories.find((c) =>
|
||
c.name?.includes('Çifte Şans'),
|
||
);
|
||
if (dcCategory) {
|
||
for (const sel of dcCategory.selections) {
|
||
if (sel.name === '1-X') oddsData.dc_1x = parseFloat(sel.oddValue) || 0;
|
||
if (sel.name === 'X-2') oddsData.dc_x2 = parseFloat(sel.oddValue) || 0;
|
||
if (sel.name === '1-2') oddsData.dc_12 = parseFloat(sel.oddValue) || 0;
|
||
}
|
||
}
|
||
|
||
const ou25Category = selectedMatch.oddCategories.find((c) =>
|
||
c.name?.includes('2,5'),
|
||
);
|
||
if (ou25Category) {
|
||
for (const sel of ou25Category.selections) {
|
||
if (sel.name === 'Alt') oddsData.ou25_u = parseFloat(sel.oddValue) || 0;
|
||
if (sel.name === 'Üst') oddsData.ou25_o = parseFloat(sel.oddValue) || 0;
|
||
}
|
||
}
|
||
|
||
const ou15Category = selectedMatch.oddCategories.find((c) =>
|
||
c.name?.includes('1,5'),
|
||
);
|
||
if (ou15Category) {
|
||
for (const sel of ou15Category.selections) {
|
||
if (sel.name === 'Alt') oddsData.ou15_u = parseFloat(sel.oddValue) || 0;
|
||
if (sel.name === 'Üst') oddsData.ou15_o = parseFloat(sel.oddValue) || 0;
|
||
}
|
||
}
|
||
|
||
const bttsCategory = selectedMatch.oddCategories.find(
|
||
(c) =>
|
||
c.name?.toLowerCase().includes('karşılıklı') || c.name?.includes('KG'),
|
||
);
|
||
if (bttsCategory) {
|
||
for (const sel of bttsCategory.selections) {
|
||
if (sel.name === 'Var' || sel.name === 'Evet')
|
||
oddsData.btts_y = parseFloat(sel.oddValue) || 0;
|
||
if (sel.name === 'Yok' || sel.name === 'Hayır')
|
||
oddsData.btts_n = parseFloat(sel.oddValue) || 0;
|
||
}
|
||
}
|
||
|
||
console.log('Toplanan Oranlar:');
|
||
console.log(
|
||
` MS (1/X/2): ${oddsData.ms_h || 'N/A'} / ${oddsData.ms_d || 'N/A'} / ${oddsData.ms_a || 'N/A'}`,
|
||
);
|
||
console.log(
|
||
` DC (1X/X2/12): ${oddsData.dc_1x || 'N/A'} / ${oddsData.dc_x2 || 'N/A'} / ${oddsData.dc_12 || 'N/A'}`,
|
||
);
|
||
console.log(
|
||
` 2.5 Alt/Üst: ${oddsData.ou25_u || 'N/A'} / ${oddsData.ou25_o || 'N/A'}`,
|
||
);
|
||
console.log(
|
||
` 1.5 Alt/Üst: ${oddsData.ou15_u || 'N/A'} / ${oddsData.ou15_o || 'N/A'}`,
|
||
);
|
||
|
||
// =====================================
|
||
// ADIM 2: TAKIM İSTATİSTİKLERİ
|
||
// =====================================
|
||
console.log('\n========================================');
|
||
console.log('📈 ADIM 2: TAKIM İSTATİSTİKLERİ');
|
||
console.log('========================================');
|
||
|
||
// Ev sahibi son 10 maç
|
||
const homeTeamRecentMatches = await prisma.match.findMany({
|
||
where: {
|
||
OR: [
|
||
{ homeTeamId: selectedMatch.homeTeamId },
|
||
{ awayTeamId: selectedMatch.homeTeamId },
|
||
],
|
||
sport: 'football',
|
||
state: 'postGame',
|
||
scoreHome: { not: null },
|
||
scoreAway: { not: null },
|
||
},
|
||
include: { homeTeam: true, awayTeam: true },
|
||
take: 10,
|
||
orderBy: { mstUtc: 'desc' },
|
||
});
|
||
|
||
// Ev sahibi istatistik hesapla
|
||
let homeWins = 0,
|
||
homeDraws = 0,
|
||
homeLosses = 0;
|
||
let homeGoalsFor = 0,
|
||
homeGoalsAgainst = 0;
|
||
|
||
for (const m of homeTeamRecentMatches) {
|
||
const isHome = m.homeTeamId === selectedMatch.homeTeamId;
|
||
const gf = isHome ? m.scoreHome : m.scoreAway;
|
||
const ga = isHome ? m.scoreAway : m.scoreHome;
|
||
homeGoalsFor += gf || 0;
|
||
homeGoalsAgainst += ga || 0;
|
||
|
||
if (gf > ga) homeWins++;
|
||
else if (gf < ga) homeLosses++;
|
||
else homeDraws++;
|
||
}
|
||
|
||
console.log(`\n🏠 ${selectedMatch.homeTeam?.name} (Ev Sahibi):`);
|
||
console.log(` Son 10 Maç: ${homeWins}G ${homeDraws}B ${homeLosses}M`);
|
||
console.log(` Gol Averajı: ${homeGoalsFor} attı, ${homeGoalsAgainst} yedi`);
|
||
console.log(` Ortalama Gol: ${(homeGoalsFor / 10).toFixed(2)} / maç`);
|
||
console.log(
|
||
` Ortalama Yenilen: ${(homeGoalsAgainst / 10).toFixed(2)} / maç`,
|
||
);
|
||
|
||
// Deplasman takımı son 10 maç
|
||
const awayTeamRecentMatches = await prisma.match.findMany({
|
||
where: {
|
||
OR: [
|
||
{ homeTeamId: selectedMatch.awayTeamId },
|
||
{ awayTeamId: selectedMatch.awayTeamId },
|
||
],
|
||
sport: 'football',
|
||
state: 'postGame',
|
||
scoreHome: { not: null },
|
||
scoreAway: { not: null },
|
||
},
|
||
include: { homeTeam: true, awayTeam: true },
|
||
take: 10,
|
||
orderBy: { mstUtc: 'desc' },
|
||
});
|
||
|
||
let awayWins = 0,
|
||
awayDraws = 0,
|
||
awayLosses = 0;
|
||
let awayGoalsFor = 0,
|
||
awayGoalsAgainst = 0;
|
||
|
||
for (const m of awayTeamRecentMatches) {
|
||
const isHome = m.homeTeamId === selectedMatch.awayTeamId;
|
||
const gf = isHome ? m.scoreHome : m.scoreAway;
|
||
const ga = isHome ? m.scoreAway : m.scoreHome;
|
||
awayGoalsFor += gf || 0;
|
||
awayGoalsAgainst += ga || 0;
|
||
|
||
if (gf > ga) awayWins++;
|
||
else if (gf < ga) awayLosses++;
|
||
else awayDraws++;
|
||
}
|
||
|
||
console.log(`\n✈️ ${selectedMatch.awayTeam?.name} (Deplasman):`);
|
||
console.log(` Son 10 Maç: ${awayWins}G ${awayDraws}B ${awayLosses}M`);
|
||
console.log(` Gol Averajı: ${awayGoalsFor} attı, ${awayGoalsAgainst} yedi`);
|
||
console.log(` Ortalama Gol: ${(awayGoalsFor / 10).toFixed(2)} / maç`);
|
||
console.log(
|
||
` Ortalama Yenilen: ${(awayGoalsAgainst / 10).toFixed(2)} / maç`,
|
||
);
|
||
|
||
// =====================================
|
||
// ADIM 3: ELO VE FORM SKORLARI
|
||
// =====================================
|
||
console.log('\n========================================');
|
||
console.log('🤖 ADIM 3: ELO & FORM SKORLARI');
|
||
console.log('========================================');
|
||
|
||
if (selectedMatch.aiFeatures) {
|
||
console.log(
|
||
`\nEv Sahibi ELO: ${selectedMatch.aiFeatures.homeElo.toFixed(0)}`,
|
||
);
|
||
console.log(
|
||
`Deplasman ELO: ${selectedMatch.aiFeatures.awayElo.toFixed(0)}`,
|
||
);
|
||
console.log(
|
||
`Ev Sahibi Form: ${selectedMatch.aiFeatures.homeFormScore.toFixed(1)}/100`,
|
||
);
|
||
console.log(
|
||
`Deplasman Form: ${selectedMatch.aiFeatures.awayFormScore.toFixed(1)}/100`,
|
||
);
|
||
console.log(
|
||
`Eksik Oyuncu Etkisi: ${selectedMatch.aiFeatures.missingPlayersImpact}`,
|
||
);
|
||
} else {
|
||
console.log('⚠️ AI Features mevcut değil');
|
||
}
|
||
|
||
// =====================================
|
||
// ADIM 4: HEAD-TO-HEAD
|
||
// =====================================
|
||
console.log('\n========================================');
|
||
console.log('🔄 ADIM 4: HEAD-TO-HEAD');
|
||
console.log('========================================');
|
||
|
||
const h2hMatches = await prisma.match.findMany({
|
||
where: {
|
||
OR: [
|
||
{
|
||
homeTeamId: selectedMatch.homeTeamId,
|
||
awayTeamId: selectedMatch.awayTeamId,
|
||
},
|
||
{
|
||
homeTeamId: selectedMatch.awayTeamId,
|
||
awayTeamId: selectedMatch.homeTeamId,
|
||
},
|
||
],
|
||
sport: 'football',
|
||
state: 'postGame',
|
||
},
|
||
include: { homeTeam: true, awayTeam: true },
|
||
take: 5,
|
||
orderBy: { mstUtc: 'desc' },
|
||
});
|
||
|
||
if (h2hMatches.length > 0) {
|
||
let h2hHomeWins = 0,
|
||
h2hDraws = 0,
|
||
h2hAwayWins = 0;
|
||
for (const m of h2hMatches) {
|
||
const homeTeamIsHome = m.homeTeamId === selectedMatch.homeTeamId;
|
||
const winner =
|
||
m.scoreHome > m.scoreAway
|
||
? 'home'
|
||
: m.scoreHome < m.scoreAway
|
||
? 'away'
|
||
: 'draw';
|
||
|
||
if (winner === 'draw') h2hDraws++;
|
||
else if (
|
||
(winner === 'home' && homeTeamIsHome) ||
|
||
(winner === 'away' && !homeTeamIsHome)
|
||
)
|
||
h2hHomeWins++;
|
||
else h2hAwayWins++;
|
||
|
||
console.log(
|
||
` ${m.homeTeam?.name} ${m.scoreHome} - ${m.scoreAway} ${m.awayTeam?.name}`,
|
||
);
|
||
}
|
||
console.log(
|
||
`\nKarşılıklı: ${selectedMatch.homeTeam?.name} ${h2hHomeWins}G, Beraberlik ${h2hDraws}, ${selectedMatch.awayTeam?.name} ${h2hAwayWins}G`,
|
||
);
|
||
} else {
|
||
console.log('Karşılıklı maç bulunamadı');
|
||
}
|
||
|
||
// =====================================
|
||
// ADIM 5: TAHMİN HESAPLAMA
|
||
// =====================================
|
||
console.log('\n========================================');
|
||
console.log('🎯 ADIM 5: TAHMİN HESAPLAMA');
|
||
console.log('========================================');
|
||
|
||
// Basit bir tahmin modeli (AI Engine'den bağımsız)
|
||
const homeForm = selectedMatch.aiFeatures?.homeFormScore || 50;
|
||
const awayForm = selectedMatch.aiFeatures?.awayFormScore || 50;
|
||
const homeElo = selectedMatch.aiFeatures?.homeElo || 1500;
|
||
const awayElo = selectedMatch.aiFeatures?.awayElo || 1500;
|
||
|
||
// Oranları olasılığa çevir
|
||
const msHomeProb = oddsData.ms_h ? (1 / oddsData.ms_h) * 100 : 33;
|
||
const msDrawProb = oddsData.ms_d ? (1 / oddsData.ms_d) * 100 : 33;
|
||
const msAwayProb = oddsData.ms_a ? (1 / oddsData.ms_a) * 100 : 33;
|
||
|
||
// Normalize et
|
||
const totalProb = msHomeProb + msDrawProb + msAwayProb;
|
||
const normHomeProb = (msHomeProb / totalProb) * 100;
|
||
const normDrawProb = (msDrawProb / totalProb) * 100;
|
||
const normAwayProb = (msAwayProb / totalProb) * 100;
|
||
|
||
console.log('\n📊 Oran Bazlı Olasılıklar:');
|
||
console.log(` 1 (Ev): %${normHomeProb.toFixed(1)}`);
|
||
console.log(` X (Beraberlik): %${normDrawProb.toFixed(1)}`);
|
||
console.log(` 2 (Deplasman): %${normAwayProb.toFixed(1)}`);
|
||
|
||
// Form bazlı ağırlık
|
||
const formDiff = homeForm - awayForm;
|
||
const eloDiff = homeElo - awayElo;
|
||
|
||
console.log(`\n📈 Form Farkı: ${formDiff.toFixed(1)} (Ev lehine pozitif)`);
|
||
console.log(`📈 ELO Farkı: ${eloDiff.toFixed(0)} (Ev lehine pozitif)`);
|
||
|
||
// Tahmin skoru hesapla
|
||
let homeScore = normHomeProb + formDiff * 0.3 + eloDiff * 0.02;
|
||
let awayScore = normAwayProb - formDiff * 0.3 - eloDiff * 0.02;
|
||
let drawScore = normDrawProb;
|
||
|
||
// Ev sahibi avantajı
|
||
homeScore += 5;
|
||
|
||
console.log(`\n🎯 Tahmin Skorları:`);
|
||
console.log(` Ev Sahibi: ${homeScore.toFixed(1)}`);
|
||
console.log(` Beraberlik: ${drawScore.toFixed(1)}`);
|
||
console.log(` Deplasman: ${awayScore.toFixed(1)}`);
|
||
|
||
// Final tahmin
|
||
const maxScore = Math.max(homeScore, drawScore, awayScore);
|
||
let prediction, confidence;
|
||
|
||
if (maxScore === homeScore) {
|
||
prediction = '1 (Ev Sahibi Kazanır)';
|
||
confidence = Math.min(95, Math.max(40, homeScore));
|
||
} else if (maxScore === awayScore) {
|
||
prediction = '2 (Deplasman Kazanır)';
|
||
confidence = Math.min(95, Math.max(40, awayScore));
|
||
} else {
|
||
prediction = 'X (Beraberlik)';
|
||
confidence = Math.min(95, Math.max(40, drawScore));
|
||
}
|
||
|
||
// Alt/Üst tahmini
|
||
const avgGoals =
|
||
((homeGoalsFor + homeGoalsAgainst) / 10 +
|
||
(awayGoalsFor + awayGoalsAgainst) / 10) /
|
||
2;
|
||
const ou25Prediction = avgGoals > 2.5 ? '2.5 ÜST' : '2.5 ALT';
|
||
const ou25Confidence = Math.min(85, Math.abs(avgGoals - 2.5) * 20 + 50);
|
||
|
||
console.log('\n========================================');
|
||
console.log('🏆 FİNAL TAHMİN');
|
||
console.log('========================================');
|
||
console.log(`\n⚽ Maç Sonucu: ${prediction}`);
|
||
console.log(` Güven: %${confidence.toFixed(1)}`);
|
||
console.log(`\n🎯 2.5 Alt/Üst: ${ou25Prediction}`);
|
||
console.log(` Güven: %${ou25Confidence.toFixed(1)}`);
|
||
console.log(` Ortalama Gol Beklentisi: ${avgGoals.toFixed(2)}`);
|
||
|
||
// Risk değerlendirmesi
|
||
console.log('\n⚠️ RİSK DEĞERLENDİRMESİ:');
|
||
const riskFactors = [];
|
||
|
||
if (Math.abs(homeForm - awayForm) < 10) {
|
||
riskFactors.push('Takımların form durumları yakın - BELIRSIZ');
|
||
}
|
||
if (
|
||
oddsData.ms_h &&
|
||
oddsData.ms_a &&
|
||
Math.abs(oddsData.ms_h - oddsData.ms_a) < 0.5
|
||
) {
|
||
riskFactors.push('Oranlar birbirine yakın - ZOR MAÇ');
|
||
}
|
||
if (h2hMatches.length < 3) {
|
||
riskFactors.push('Yeterli H2H verisi yok');
|
||
}
|
||
if (!selectedMatch.aiFeatures) {
|
||
riskFactors.push('AI özellikleri hesaplanmamış');
|
||
}
|
||
|
||
if (riskFactors.length === 0) {
|
||
console.log(' ✅ Düşük risk - Yüksek güvenilirlik');
|
||
} else {
|
||
for (const risk of riskFactors) {
|
||
console.log(` ⚠️ ${risk}`);
|
||
}
|
||
}
|
||
|
||
// Gerçek sonuç (eğer maç bitmişse)
|
||
if (selectedMatch.state === 'postGame' && selectedMatch.scoreHome !== null) {
|
||
console.log('\n========================================');
|
||
console.log('📊 GERÇEK SONUÇ');
|
||
console.log('========================================');
|
||
const actualResult =
|
||
selectedMatch.scoreHome > selectedMatch.scoreAway
|
||
? '1'
|
||
: selectedMatch.scoreHome < selectedMatch.scoreAway
|
||
? '2'
|
||
: 'X';
|
||
const totalGoals =
|
||
(selectedMatch.scoreHome || 0) + (selectedMatch.scoreAway || 0);
|
||
const actualOU = totalGoals > 2.5 ? '2.5 ÜST' : '2.5 ALT';
|
||
|
||
console.log(
|
||
`Skor: ${selectedMatch.scoreHome} - ${selectedMatch.scoreAway}`,
|
||
);
|
||
console.log(`Sonuç: ${actualResult}`);
|
||
console.log(`Alt/Üst: ${actualOU} (${totalGoals} gol)`);
|
||
}
|
||
|
||
await prisma.$disconnect();
|
||
}
|
||
|
||
analyzePredictionProcess().catch((e) => {
|
||
console.error('Hata:', e);
|
||
process.exit(1);
|
||
});
|