This commit is contained in:
@@ -0,0 +1,500 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user