File size: 12,488 Bytes
6f7e932
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
"""
Advanced Analytics Dashboard Backend

Provides:
- Detailed accuracy tracking
- ROI calculations
- League performance analysis
- Betting patterns
- Trend analysis
"""

import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass, asdict
from collections import defaultdict
import statistics


@dataclass
class PredictionRecord:
    """Single prediction record"""
    id: str
    home: str
    away: str
    league: str
    predicted_outcome: str
    actual_outcome: Optional[str]
    confidence: float
    odds: float
    stake: float
    status: str  # pending, won, lost
    created_at: str
    settled_at: Optional[str] = None
    
    def profit_loss(self) -> float:
        if self.status == 'won':
            return self.stake * (self.odds - 1)
        elif self.status == 'lost':
            return -self.stake
        return 0.0


class AdvancedAnalytics:
    """Advanced analytics engine"""
    
    def __init__(self):
        self.predictions: List[PredictionRecord] = []
        self.daily_stats: Dict[str, Dict] = {}
        self.league_stats: Dict[str, Dict] = defaultdict(lambda: {
            'total': 0, 'correct': 0, 'profit': 0.0
        })
        
    def add_prediction(self, record: PredictionRecord):
        """Add a prediction record"""
        self.predictions.append(record)
        self._update_stats(record)
        
    def _update_stats(self, record: PredictionRecord):
        """Update statistics for a prediction"""
        date_key = record.created_at[:10]
        
        if date_key not in self.daily_stats:
            self.daily_stats[date_key] = {
                'total': 0, 'correct': 0, 'profit': 0.0,
                'stakes': 0.0, 'high_conf': 0, 'high_conf_correct': 0
            }
        
        stats = self.daily_stats[date_key]
        stats['total'] += 1
        stats['stakes'] += record.stake
        
        if record.confidence >= 0.8:
            stats['high_conf'] += 1
        
        if record.status == 'won':
            stats['correct'] += 1
            stats['profit'] += record.profit_loss()
            if record.confidence >= 0.8:
                stats['high_conf_correct'] += 1
        elif record.status == 'lost':
            stats['profit'] += record.profit_loss()
            
        # League stats
        league_stat = self.league_stats[record.league]
        league_stat['total'] += 1
        if record.status == 'won':
            league_stat['correct'] += 1
        league_stat['profit'] += record.profit_loss()
        
    def get_overall_accuracy(self) -> float:
        """Get overall prediction accuracy"""
        settled = [p for p in self.predictions if p.status in ['won', 'lost']]
        if not settled:
            return 0.0
        correct = len([p for p in settled if p.status == 'won'])
        return correct / len(settled) * 100
    
    def get_roi(self, period_days: int = 30) -> float:
        """Calculate ROI for a period"""
        cutoff = datetime.now() - timedelta(days=period_days)
        cutoff_str = cutoff.strftime('%Y-%m-%d')
        
        total_stakes = 0.0
        total_profit = 0.0
        
        for record in self.predictions:
            if record.created_at >= cutoff_str and record.status != 'pending':
                total_stakes += record.stake
                total_profit += record.profit_loss()
                
        if total_stakes == 0:
            return 0.0
        return (total_profit / total_stakes) * 100
    
    def get_league_performance(self) -> List[Dict]:
        """Get performance breakdown by league"""
        result = []
        for league, stats in self.league_stats.items():
            if stats['total'] > 0:
                accuracy = (stats['correct'] / stats['total']) * 100
                result.append({
                    'league': league,
                    'total': stats['total'],
                    'correct': stats['correct'],
                    'accuracy': round(accuracy, 1),
                    'profit': round(stats['profit'], 2)
                })
        return sorted(result, key=lambda x: x['accuracy'], reverse=True)
    
    def get_confidence_analysis(self) -> Dict:
        """Analyze accuracy by confidence bands"""
        bands = {
            '90-100%': {'total': 0, 'correct': 0},
            '80-90%': {'total': 0, 'correct': 0},
            '70-80%': {'total': 0, 'correct': 0},
            '60-70%': {'total': 0, 'correct': 0},
            '50-60%': {'total': 0, 'correct': 0},
        }
        
        for pred in self.predictions:
            if pred.status == 'pending':
                continue
                
            conf = pred.confidence * 100
            if conf >= 90:
                band = '90-100%'
            elif conf >= 80:
                band = '80-90%'
            elif conf >= 70:
                band = '70-80%'
            elif conf >= 60:
                band = '60-70%'
            else:
                band = '50-60%'
                
            bands[band]['total'] += 1
            if pred.status == 'won':
                bands[band]['correct'] += 1
                
        result = {}
        for band, stats in bands.items():
            if stats['total'] > 0:
                result[band] = {
                    'total': stats['total'],
                    'correct': stats['correct'],
                    'accuracy': round(stats['correct'] / stats['total'] * 100, 1)
                }
            else:
                result[band] = {'total': 0, 'correct': 0, 'accuracy': 0}
                
        return result
    
    def get_outcome_analysis(self) -> Dict:
        """Analyze accuracy by predicted outcome"""
        outcomes = defaultdict(lambda: {'total': 0, 'correct': 0})
        
        for pred in self.predictions:
            if pred.status == 'pending':
                continue
            outcomes[pred.predicted_outcome]['total'] += 1
            if pred.status == 'won':
                outcomes[pred.predicted_outcome]['correct'] += 1
                
        result = {}
        for outcome, stats in outcomes.items():
            if stats['total'] > 0:
                result[outcome] = {
                    'total': stats['total'],
                    'correct': stats['correct'],
                    'accuracy': round(stats['correct'] / stats['total'] * 100, 1)
                }
        return result
    
    def get_trend_analysis(self, days: int = 30) -> List[Dict]:
        """Get daily accuracy trend"""
        cutoff = datetime.now() - timedelta(days=days)
        cutoff_str = cutoff.strftime('%Y-%m-%d')
        
        trend = []
        for date, stats in sorted(self.daily_stats.items()):
            if date >= cutoff_str:
                if stats['total'] > 0:
                    accuracy = stats['correct'] / stats['total'] * 100
                else:
                    accuracy = 0
                trend.append({
                    'date': date,
                    'accuracy': round(accuracy, 1),
                    'total': stats['total'],
                    'correct': stats['correct'],
                    'profit': round(stats['profit'], 2)
                })
        return trend
    
    def get_streak_info(self) -> Dict:
        """Get winning/losing streak information"""
        settled = [p for p in self.predictions if p.status in ['won', 'lost']]
        settled.sort(key=lambda x: x.created_at)
        
        if not settled:
            return {'current_streak': 0, 'streak_type': 'none', 'best_streak': 0}
        
        current_streak = 0
        current_type = settled[-1].status
        best_winning_streak = 0
        current_winning = 0
        
        for pred in settled:
            if pred.status == 'won':
                current_winning += 1
                best_winning_streak = max(best_winning_streak, current_winning)
            else:
                current_winning = 0
                
        # Calculate current streak
        for pred in reversed(settled):
            if pred.status == current_type:
                current_streak += 1
            else:
                break
                
        return {
            'current_streak': current_streak,
            'streak_type': 'winning' if current_type == 'won' else 'losing',
            'best_winning_streak': best_winning_streak
        }
    
    def get_value_bet_analysis(self) -> Dict:
        """Analyze value bet performance"""
        value_bets = [p for p in self.predictions if hasattr(p, 'is_value_bet') and p.is_value_bet]
        
        if not value_bets:
            return {'count': 0, 'accuracy': 0, 'avg_edge': 0, 'roi': 0}
        
        settled = [p for p in value_bets if p.status in ['won', 'lost']]
        if not settled:
            return {'count': len(value_bets), 'accuracy': 0, 'avg_edge': 0, 'roi': 0}
        
        correct = len([p for p in settled if p.status == 'won'])
        total_stakes = sum(p.stake for p in settled)
        total_profit = sum(p.profit_loss() for p in settled)
        
        return {
            'count': len(value_bets),
            'settled': len(settled),
            'accuracy': round(correct / len(settled) * 100, 1),
            'roi': round(total_profit / total_stakes * 100, 1) if total_stakes > 0 else 0
        }
    
    def get_sure_wins_analysis(self) -> Dict:
        """Analyze sure wins (91%+ confidence) performance"""
        sure_wins = [p for p in self.predictions if p.confidence >= 0.91]
        
        if not sure_wins:
            return {'count': 0, 'accuracy': 0, 'profit': 0}
        
        settled = [p for p in sure_wins if p.status in ['won', 'lost']]
        if not settled:
            return {'count': len(sure_wins), 'accuracy': 0, 'profit': 0}
        
        correct = len([p for p in settled if p.status == 'won'])
        total_profit = sum(p.profit_loss() for p in settled)
        
        return {
            'count': len(sure_wins),
            'settled': len(settled),
            'correct': correct,
            'accuracy': round(correct / len(settled) * 100, 1),
            'profit': round(total_profit, 2)
        }
    
    def get_dashboard_summary(self) -> Dict:
        """Get complete dashboard summary"""
        return {
            'overall': {
                'total_predictions': len(self.predictions),
                'accuracy': round(self.get_overall_accuracy(), 1),
                'roi_30d': round(self.get_roi(30), 1),
                'roi_7d': round(self.get_roi(7), 1),
            },
            'streak': self.get_streak_info(),
            'by_league': self.get_league_performance()[:5],
            'by_confidence': self.get_confidence_analysis(),
            'by_outcome': self.get_outcome_analysis(),
            'trend': self.get_trend_analysis(14),
            'sure_wins': self.get_sure_wins_analysis(),
            'generated_at': datetime.now().isoformat()
        }


# Global analytics instance
analytics = AdvancedAnalytics()


def record_prediction(
    home: str, away: str, league: str,
    prediction: str, confidence: float,
    odds: float = 1.0, stake: float = 10.0
) -> str:
    """Record a new prediction"""
    record = PredictionRecord(
        id=f"pred_{datetime.now().timestamp()}",
        home=home,
        away=away,
        league=league,
        predicted_outcome=prediction,
        actual_outcome=None,
        confidence=confidence,
        odds=odds,
        stake=stake,
        status='pending',
        created_at=datetime.now().isoformat()
    )
    analytics.add_prediction(record)
    return record.id


def settle_prediction(pred_id: str, actual_outcome: str) -> bool:
    """Settle a prediction as won or lost"""
    for pred in analytics.predictions:
        if pred.id == pred_id:
            pred.actual_outcome = actual_outcome
            pred.status = 'won' if pred.predicted_outcome == actual_outcome else 'lost'
            pred.settled_at = datetime.now().isoformat()
            analytics._update_stats(pred)
            return True
    return False


def get_analytics_summary() -> Dict:
    """Get analytics dashboard summary"""
    return analytics.get_dashboard_summary()


def get_league_accuracy(league: str) -> float:
    """Get accuracy for a specific league"""
    stats = analytics.league_stats.get(league)
    if stats and stats['total'] > 0:
        return stats['correct'] / stats['total'] * 100
    return 0.0