AI-система для фэнтези-спорта и ставок

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1Все 1566 услуг
AI-система для фэнтези-спорта и ставок
Сложный
от 1 недели до 3 месяцев
Часто задаваемые вопросы

Направления AI-разработки

Этапы разработки AI-решения

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1285
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    902
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1122
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    859

AI-системы для фэнтези-спорта и ставок

Спортивная аналитика с ML — это предсказание исходов через моделирование реальных процессов: физическое состояние игрока, форма команды, исторические матчапы, venue-фактор, погода. Фэнтези-платформы используют эти же модели для скоринга, подбора составов и оценки игроков.

Предсказание результатов матчей

import numpy as np
import pandas as pd
from sklearn.ensemble import GradientBoostingClassifier, GradientBoostingRegressor
from sklearn.calibration import CalibratedClassifierCV
import json

class MatchOutcomePredictor:
    """
    Предсказание исхода матча: Win/Draw/Loss + xG (Expected Goals).
    Базируется на ELO, форме команды, home advantage, матчапах.
    """

    ELO_K = 32
    HOME_ADVANTAGE = 100  # ELO points

    def __init__(self):
        # Модель для вероятностей исходов
        self.outcome_model = CalibratedClassifierCV(
            GradientBoostingClassifier(n_estimators=300, learning_rate=0.05, random_state=42),
            method='isotonic', cv=5
        )
        # Регрессионная модель для xG
        self.xg_model = GradientBoostingRegressor(
            n_estimators=200, learning_rate=0.05, random_state=42
        )
        self.elo_ratings = {}

    def update_elo(self, home_team: str, away_team: str,
                    outcome: str) -> tuple:
        """Обновление ELO рейтинга после матча"""
        home_elo = self.elo_ratings.get(home_team, 1500)
        away_elo = self.elo_ratings.get(away_team, 1500)

        home_elo_adj = home_elo + self.HOME_ADVANTAGE

        p_home_win = 1 / (1 + 10 ** ((away_elo - home_elo_adj) / 400))
        p_away_win = 1 - p_home_win

        if outcome == 'home_win':
            home_result, away_result = 1.0, 0.0
        elif outcome == 'away_win':
            home_result, away_result = 0.0, 1.0
        else:  # draw
            home_result, away_result = 0.5, 0.5

        new_home_elo = home_elo + self.ELO_K * (home_result - p_home_win)
        new_away_elo = away_elo + self.ELO_K * (away_result - p_away_win)

        self.elo_ratings[home_team] = new_home_elo
        self.elo_ratings[away_team] = new_away_elo

        return new_home_elo, new_away_elo

    def build_match_features(self, home_team: str, away_team: str,
                              match_context: dict,
                              team_stats: dict) -> np.ndarray:
        """Feature-вектор для матча"""
        home_elo = self.elo_ratings.get(home_team, 1500)
        away_elo = self.elo_ratings.get(away_team, 1500)

        home_stats = team_stats.get(home_team, {})
        away_stats = team_stats.get(away_team, {})

        return np.array([
            # ELO и форма
            home_elo - away_elo,                          # ELO разница
            home_elo + self.HOME_ADVANTAGE - away_elo,    # Скорректированная разница
            home_stats.get('form_5_games', 0.5),          # Форма: очки/возможные последние 5
            away_stats.get('form_5_games', 0.5),
            home_stats.get('form_trend', 0),              # Тренд формы

            # Атака/защита
            home_stats.get('goals_scored_avg', 1.5),
            home_stats.get('goals_conceded_avg', 1.2),
            away_stats.get('goals_scored_avg', 1.5),
            away_stats.get('goals_conceded_avg', 1.2),
            home_stats.get('xg_for_avg', 1.4),
            home_stats.get('xg_against_avg', 1.1),

            # Контекст
            int(match_context.get('is_cup', False)),
            int(match_context.get('is_derby', False)),
            match_context.get('home_fatigue_days', 7),    # Дней с последнего матча
            away_stats.get('travel_distance_km', 0) / 1000,

            # Исторические матчапы
            match_context.get('h2h_home_win_rate', 0.4),
            match_context.get('h2h_goals_avg', 2.5),
        ])

    def predict_outcome(self, home_team: str, away_team: str,
                         match_context: dict, team_stats: dict) -> dict:
        """Вероятности исходов матча"""
        features = self.build_match_features(home_team, away_team, match_context, team_stats)
        probs = self.outcome_model.predict_proba(features.reshape(1, -1))[0]

        return {
            'home_win': round(float(probs[0]), 3),
            'draw': round(float(probs[1]), 3),
            'away_win': round(float(probs[2]), 3),
            'expected_goals_home': round(float(self.xg_model.predict(features.reshape(1, -1))[0]), 2),
            'home_elo': self.elo_ratings.get(home_team, 1500),
            'away_elo': self.elo_ratings.get(away_team, 1500)
        }


class PlayerPerformancePredictor:
    """Предсказание показателей игрока для фэнтези"""

    def predict_fantasy_points(self, player: dict,
                                match_context: dict,
                                season_stats: pd.DataFrame) -> dict:
        """
        Прогноз фэнтези-очков для игрока в конкретном матче.
        Учитывает позицию, форму, оппонента, venue.
        """
        player_stats = season_stats[season_stats['player_id'] == player['id']]

        if player_stats.empty:
            return {'expected_points': 0, 'confidence': 'low'}

        # Скользящие средние показателей
        recent = player_stats.sort_values('date').tail(5)
        avg_stats = {
            'goals_per_game': recent['goals'].mean(),
            'assists_per_game': recent['assists'].mean(),
            'shots_per_game': recent['shots'].mean(),
            'minutes_per_game': recent['minutes_played'].mean(),
            'key_passes': recent.get('key_passes', pd.Series([0])).mean(),
        }

        # Поправка на качество оппонента
        opp_defensive_rank = match_context.get('opponent_defensive_rank', 10)  # 1=лучшая
        difficulty_multiplier = 1.0 + (opp_defensive_rank - 10) * 0.02  # ±0.2 от ранга

        # Поправка на форму
        form_factor = recent['fantasy_points'].mean() / max(
            player_stats['fantasy_points'].mean(), 0.1
        )
        form_factor = float(np.clip(form_factor, 0.7, 1.3))

        # Позиционная формула
        position_multiplier = {
            'GK': 0.8, 'DEF': 1.0, 'MID': 1.2, 'FWD': 1.1
        }.get(player.get('position', 'MID'), 1.0)

        # Базовые очки
        expected_points = (
            avg_stats['goals_per_game'] * 4 +
            avg_stats['assists_per_game'] * 3 +
            avg_stats['shots_per_game'] * 0.3 +
            (avg_stats['minutes_per_game'] / 90) * 2
        ) * difficulty_multiplier * form_factor * position_multiplier

        # Вероятность выйти в стартовом составе
        starting_prob = player.get('starting_probability', 0.9)

        return {
            'player_id': player['id'],
            'player_name': player.get('name', ''),
            'position': player.get('position', ''),
            'expected_points': round(expected_points * starting_prob, 2),
            'expected_if_starts': round(expected_points, 2),
            'starting_probability': starting_prob,
            'form_factor': round(form_factor, 2),
            'difficulty_multiplier': round(difficulty_multiplier, 2),
            'confidence': 'high' if len(player_stats) >= 10 else 'medium'
        }


class FantasyTeamOptimizer:
    """Оптимизация состава фэнтези-команды"""

    def optimize_lineup(self, player_predictions: list[dict],
                         budget: float,
                         formation: str = '4-3-3') -> dict:
        """
        Линейное программирование для максимизации ожидаемых очков
        при бюджетных и позиционных ограничениях.
        """
        from scipy.optimize import linprog

        formation_requirements = {
            '4-3-3': {'GK': 1, 'DEF': 4, 'MID': 3, 'FWD': 3},
            '4-4-2': {'GK': 1, 'DEF': 4, 'MID': 4, 'FWD': 2},
            '3-5-2': {'GK': 1, 'DEF': 3, 'MID': 5, 'FWD': 2},
        }
        requirements = formation_requirements.get(formation, formation_requirements['4-3-3'])

        # Жадный подбор (greedy) как быстрый heuristic
        selected = []
        remaining_budget = budget
        position_slots = dict(requirements)

        # Сортируем по expected_points / price
        sorted_players = sorted(
            player_predictions,
            key=lambda p: p['expected_points'] / max(p.get('price', 5), 0.1),
            reverse=True
        )

        for player in sorted_players:
            pos = player.get('position', 'MID')
            if position_slots.get(pos, 0) <= 0:
                continue
            if player.get('price', 5) > remaining_budget:
                continue

            selected.append(player)
            position_slots[pos] -= 1
            remaining_budget -= player.get('price', 5)

            if all(v == 0 for v in position_slots.values()):
                break

        total_expected = sum(p['expected_points'] for p in selected)
        total_cost = budget - remaining_budget

        return {
            'lineup': selected,
            'total_expected_points': round(total_expected, 2),
            'total_cost': round(total_cost, 1),
            'remaining_budget': round(remaining_budget, 1),
            'formation': formation
        }

Ответственный гейминг

Ставки и фэнтези-системы требуют интеграции RG (Responsible Gambling) инструментов: мониторинг паттернов чрезмерных ставок (резкий рост объёма, ставки после крупных проигрышей, ночные сессии), автоматические лимиты, самоисключение. Это не опционально — регуляторное требование в большинстве юрисдикций.

Точность предсказания исходов футбольных матчей: AUC 0.72-0.78 (рынок эффективен, абсолютного перевеса нет). Ценность ML — в точной оценке вероятностей для выявления overvalued/undervalued ставок против линии букмекера.