- PVSM.RU - https://www.pvsm.ru -
📍 Работа с сырыми спортивными коэффициентами — это как пытаться собрать модель корабля из разбросанных деталей конструктора. Без инструкции. И с половиной лишних запчастей.
Я аналитик в финтех-компании, и одна из наших задач — автоматический анализ спортивных линий. Цель — находить сигналы для прогнозов, искать переоценённые исходы, аномалии, иногда даже арбитражные окна.
Идея простая: подключить внешний источник с коэффициентами, привести данные в порядок и прогонять через нашу модель.
На этапе тестов выбор пал на raceodds.net [1] — платформу с открытым API и охватом по сотням лиг, включая мелкие чемпионаты. И казалось бы — бери и используй. Но...
Подключился к их API — и сразу несколько сюрпризов:
1. Шум и мусор в ответах
Каждый ответ — это массив из 50–70 полей, из которых реально нужно 6–8. Остальное: технические идентификаторы, флаги, устаревшие ключи, пустые поля.
2. Неоднородность форматов
Даты в разных форматах: 2025-07-21T19:30:00Z, 21/07/2025 19:30, unix timestamp
Названия команд отличались даже внутри одной лиги:
Manchester Utd, Man United, Manchester United FC
3. Дублирование событий
Одно и то же событие приходило под разными ID — от разных источников, но с разными наборами маркетов и коэффициентов. Часто — с разной актуальностью.
4. Отсутствие нормализации маркетов
Например, рынок "Обе забьют" представлен как:
BTTS, BothTeamsScore, BTS, goalgoal — всё это одно и то же, но в базе они шли как независимые записи.
Примерно через неделю экспериментов и ругани с JSON-ответами API, решил собрать собственный ETL-процесс, который решил сразу несколько задач.
Параллельная выгрузка по лигам через aiohttp
Лимит на частоту запросов (иначе API режет)
Авто-ретрай при 5xx/timeout
python
async def fetch_league_data(session, league_id):
async with session.get(f"{API_BASE}/odds?league={league_id}") as resp:
return await resp.json(
Все даты — в UTC ISO 8601
Команды — через словарь соответствий + fuzzy matching (fuzzywuzzy)
Названия маркетов — через enum-сопоставление
Поля удаляю жёстким whitelist-фильтром
python
NORMALIZED_FIELDS = ['event_id', 'league', 'teams', 'start_time', 'market', 'odds']
def clean_entry(entry):
return {k: entry[k] for k in NORMALIZED_FIELDS if k in entry}
События считаются одним, если:
Разница во времени < 10 минут
Названия команд совпадают на ≥ 85%
Лига та же
Для оценки схожести использую Levenshtein distance
python
def is_same_event(a, b):
return (a['league'] == b['league'] and
abs(a['start_time'] - b['start_time']) < 600 and
fuzz.ratio(a['teams'][0], b['teams'][0]) > 85)
Данные пишутся в две таблицы:
events_normalized — уникальные события
odds_snapshots — история изменения коэффициентов по времени
Добавлен индекс по (event_id, market, timestamp) — чтобы быстро вытаскивать движение линии.
После нормализации и структурирования данных, стало возможным:
Анализировать движение линии по времени: видно, как изменяется коэффициент на победу команды X за 24 часа до матча
Выявлять «запаздывающих» букмекеров: кто дольше всех реагирует на изменение рынка
Выделять value-bets: если коэффициент у одной БК выбивается из общего тренда — сигнал
Собрал простой дашборд на Streamlit:
Поиск по лигам и датам
График движения коэффициентов по событиям
Таблица отклонений между букмекерами
Фильтр по аномалиям (например, скачки >10% за 1 час)
Вот пример графика по матчу «Лидс — Суонси»:
🟡 Коэф. на победу Лидса:
→ вырос с 2.10 до 2.65 за 3 часа — новость о травме капитана
Добавил вторичный источник (Betdata.io [2]) и теперь сравниваю скорость обновлений
Планирую натренировать LightGBM-модель на признаках движения линии, чтобы предсказывать вероятность value-бета
Подумываю об open-source версии нормализатора — таких кейсов ещё много
На старте казалось, что raceodds.net [1] — это куча неструктурированного шума. Но оказалось, что если приложить немного усилий (и много нормализации), можно превратить этот поток в мощный источник для спортивной аналитики.
Главное — не бояться грязных данных. Они — как руда. Пока не переработаешь — золота не будет.
Автор: egor_gavrilov7
Источник [3]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sportivnaya-analitika/425918
Ссылки в тексте:
[1] raceodds.net: http://raceodds.net
[2] Betdata.io: http://Betdata.io
[3] Источник: https://habr.com/ru/articles/930020/?utm_campaign=930020&utm_source=habrahabr&utm_medium=rss
Нажмите здесь для печати.