NetBoss
V3.0 Ultimate Enhancement - Complete production system
6f7e932
"""
Complete Production FastAPI for Football Prediction System V3.0
Features:
- REST endpoints for all predictions
- WebSocket for real-time updates
- Monte Carlo simulation
- Value betting detection
- Player props
- RL strategy recommendations
"""
from fastapi import FastAPI, WebSocket, HTTPException, Query
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import Dict, List, Optional, Any
import asyncio
from datetime import datetime
import json
import logging
import sys
import os
# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Import modules
from src.simulation.monte_carlo import MonteCarloSimulator, run_monte_carlo
from src.predictions.player_props import PlayerPropsPredictor, predict_player_goals
from src.betting.reinforcement_learning import BettingEnvironment, DQNBettingAgent
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Initialize FastAPI with all features
app = FastAPI(
title="Ultimate Football Prediction API V3.0",
description="""
Complete football prediction system with:
- Monte Carlo simulation (100k iterations)
- Deep learning predictions
- Reinforcement learning betting strategy
- Player props prediction
- Real-time odds integration
- Value betting detection
""",
version="3.0.0",
docs_url="/docs",
redoc_url="/redoc"
)
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Pydantic models
class MatchPredictionRequest(BaseModel):
home_team: str
away_team: str
home_xg: Optional[float] = None
away_xg: Optional[float] = None
league: Optional[str] = None
include_simulation: bool = True
simulation_count: int = 100000
odds: Optional[Dict[str, float]] = None
class MonteCarloRequest(BaseModel):
home_xg: float
away_xg: float
n_simulations: int = 100000
include_htft: bool = False
class PlayerPropsRequest(BaseModel):
player_id: str
player_name: Optional[str] = None
position: str = "FW"
goals_avg: float = 0.3
is_home: bool = True
opponent_strength: float = 1.0
props: Optional[Dict[str, float]] = None
class SeasonSimulationRequest(BaseModel):
league: str
remaining_fixtures: List[Dict]
team_strengths: Dict[str, Dict]
n_simulations: int = 10000
class ValueBetRequest(BaseModel):
predictions: Dict[str, float]
odds: Dict[str, float]
min_edge: float = 0.03
# Global services
simulator = MonteCarloSimulator(n_simulations=100000)
player_predictor = PlayerPropsPredictor()
rl_agent = DQNBettingAgent()
# Health check
@app.get("/health")
async def health():
return {
"status": "healthy",
"timestamp": datetime.now().isoformat(),
"version": "3.0.0",
"features": [
"monte_carlo_simulation",
"player_props",
"rl_betting",
"value_detection"
]
}
# Main prediction endpoint
@app.post("/api/v3/predict")
async def predict_match(request: MatchPredictionRequest):
"""
Generate comprehensive match prediction using Monte Carlo simulation.
Includes:
- 1X2 probabilities
- Correct score probabilities
- Over/Under probabilities
- BTTS probabilities
- Expected goals
- Asian Handicap probabilities
"""
try:
# Get xG values
home_xg = request.home_xg or 1.5
away_xg = request.away_xg or 1.2
# Run simulation
if request.include_simulation:
result = simulator.simulate_match(
home_xg=home_xg,
away_xg=away_xg,
home_xg_std=0.3,
away_xg_std=0.3
)
simulation = result.to_dict()
else:
simulation = None
# Find value bets if odds provided
value_bets = []
if request.odds and simulation:
for market, prob in [
('home_win', simulation['1x2']['home_win']),
('draw', simulation['1x2']['draw']),
('away_win', simulation['1x2']['away_win']),
('over_2.5', simulation['over_under']['over_2.5']),
('btts_yes', simulation['btts']['yes'])
]:
if market in request.odds:
implied = 1 / request.odds[market]
edge = prob - implied
if edge > 0.03:
value_bets.append({
'market': market,
'probability': round(prob, 4),
'odds': request.odds[market],
'edge': round(edge, 4),
'expected_value': round(edge * request.odds[market], 4)
})
return {
'success': True,
'match': f"{request.home_team} vs {request.away_team}",
'timestamp': datetime.now().isoformat(),
'simulation': simulation,
'value_bets': value_bets if value_bets else None,
'methodology': f'Monte Carlo simulation with {request.simulation_count:,} iterations'
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# Monte Carlo simulation endpoint
@app.post("/api/v3/simulate")
async def monte_carlo_simulate(request: MonteCarloRequest):
"""
Run Monte Carlo simulation for a match.
Returns detailed probabilities for all markets.
"""
try:
result = run_monte_carlo(
home_xg=request.home_xg,
away_xg=request.away_xg,
n_simulations=request.n_simulations,
include_htft=request.include_htft
)
return {
'success': True,
'result': result,
'simulations': request.n_simulations
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# HT/FT simulation endpoint
@app.get("/api/v3/simulate-htft")
async def simulate_htft(
home_xg: float = Query(..., description="Home team expected goals"),
away_xg: float = Query(..., description="Away team expected goals"),
n_simulations: int = Query(100000, description="Number of simulations")
):
"""
Simulate match with HT/FT breakdown.
Uses time-segmented Poisson (42% goals in 1st half).
"""
try:
result = simulator.simulate_match_with_htft(
home_xg_1h=home_xg * 0.42,
away_xg_1h=away_xg * 0.42,
home_xg_2h=home_xg * 0.58,
away_xg_2h=away_xg * 0.58
)
return {
'success': True,
'1x2': {
'home_win': result.home_win_prob,
'draw': result.draw_prob,
'away_win': result.away_win_prob
},
'htft': result.htft_probs,
'correct_scores': result.correct_score_probs,
'btts': result.btts_prob
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# Season simulation endpoint
@app.post("/api/v3/simulate-season")
async def simulate_season(request: SeasonSimulationRequest):
"""
Simulate remaining season to predict final standings.
"""
try:
result = simulator.simulate_season(
fixtures=request.remaining_fixtures,
team_strengths=request.team_strengths,
n_simulations=request.n_simulations
)
return {
'success': True,
'league': request.league,
**result
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# Player props endpoint
@app.post("/api/v3/player-props")
async def predict_player_props(request: PlayerPropsRequest):
"""
Predict player props for a match.
Includes:
- Goals probability
- Assists probability
- Shots
- Anytime scorer
- Card probability
"""
try:
# Create features
features = {
'goals_avg_5': request.goals_avg,
'assists_avg_5': request.goals_avg * 0.5,
'shots_avg_5': request.goals_avg * 5,
'shots_on_target_avg_5': request.goals_avg * 2.5,
'is_home': 1 if request.is_home else 0,
'opponent_strength': request.opponent_strength,
'minutes_ratio': 0.9
}
predictions = player_predictor.predict_all_props(
features,
request.position,
request.props
)
predictions['player_id'] = request.player_id
predictions['player_name'] = request.player_name or request.player_id
return {
'success': True,
'predictions': predictions
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# Anytime scorer endpoint
@app.get("/api/v3/anytime-scorer")
async def anytime_scorer(
goals_avg: float = Query(..., description="Player's average goals per game"),
position: str = Query("FW", description="Player position"),
is_home: bool = Query(True, description="Playing at home"),
odds: Optional[float] = Query(None, description="Bookmaker odds")
):
"""
Calculate anytime scorer probability.
"""
try:
result = predict_player_goals(
goals_avg=goals_avg,
position=position,
is_home=is_home
)
prob = result['prob_1plus']
fair_odds = 1 / prob if prob > 0 else 99
response = {
'success': True,
'probability': round(prob, 4),
'fair_odds': round(fair_odds, 2),
'expected_goals': result['expected_goals']
}
if odds:
implied = 1 / odds
edge = prob - implied
response['bookmaker_odds'] = odds
response['edge'] = round(edge, 4)
response['value_bet'] = edge > 0.05
return response
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# Value betting endpoint
@app.post("/api/v3/value-bets")
async def find_value_bets(request: ValueBetRequest):
"""
Find value betting opportunities.
"""
try:
value_bets = []
for market, prob in request.predictions.items():
if market in request.odds:
implied = 1 / request.odds[market]
edge = prob - implied
if edge >= request.min_edge:
# Calculate Kelly stake
kelly = (prob * request.odds[market] - 1) / (request.odds[market] - 1)
kelly = max(0, min(kelly, 0.25)) # Cap at 25%
value_bets.append({
'market': market,
'probability': round(prob, 4),
'odds': request.odds[market],
'implied_probability': round(implied, 4),
'edge': round(edge, 4),
'expected_value': round(edge * request.odds[market], 4),
'kelly_stake': round(kelly * 100, 1)
})
# Sort by edge
value_bets.sort(key=lambda x: x['edge'], reverse=True)
return {
'success': True,
'value_bets': value_bets,
'total_opportunities': len(value_bets)
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# RL betting strategy endpoint
@app.post("/api/v3/rl-strategy")
async def get_rl_betting_strategy(
probability: float = Query(..., description="Model probability"),
odds: float = Query(..., description="Bookmaker odds"),
confidence: float = Query(0.5, description="Model confidence")
):
"""
Get betting action from RL agent.
"""
try:
result = rl_agent.get_optimal_bet_size(
model_probability=probability,
odds=odds,
confidence=confidence
)
return {
'success': True,
**result
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# WebSocket for real-time predictions
@app.websocket("/ws/predictions")
async def websocket_predictions(websocket: WebSocket):
"""
WebSocket for real-time match predictions.
Send JSON with action and parameters, receive predictions.
"""
await websocket.accept()
try:
while True:
data = await websocket.receive_text()
request = json.loads(data)
action = request.get('action')
if action == 'simulate':
result = run_monte_carlo(
home_xg=request.get('home_xg', 1.5),
away_xg=request.get('away_xg', 1.2),
n_simulations=request.get('n_simulations', 100000)
)
await websocket.send_json({
'type': 'simulation',
'result': result,
'timestamp': datetime.now().isoformat()
})
elif action == 'player_props':
goals_pred = predict_player_goals(
goals_avg=request.get('goals_avg', 0.3),
position=request.get('position', 'FW'),
is_home=request.get('is_home', True)
)
await websocket.send_json({
'type': 'player_props',
'result': goals_pred,
'timestamp': datetime.now().isoformat()
})
elif action == 'ping':
await websocket.send_json({
'type': 'pong',
'timestamp': datetime.now().isoformat()
})
except Exception as e:
logger.error(f"WebSocket error: {e}")
await websocket.close()
# Run with uvicorn
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"main:app",
host="0.0.0.0",
port=8000,
reload=True
)