Type/to search
2
Follow
490
Followers
Между арбитражем и прогнозированием: наивный эксперимент стратегии сходимости путей на чемпионате мира
Discussions
Created 2026-06-18 09:09:14  Updated 2026-06-22 15:37:13
 0
 209

img

Как только открылся чемпионат мира, рынок сразу преподал нам небольшой отрезвляющий урок: сильные команды не застрахованы от провалов, просто их провалы часто оказываются более креативными, чем мы могли представить.

Например, Испания — Кабо-Верде 0:0. До матча, если смотреть только на силу, рейтинг, глубину состава, большинство интуитивно подумало бы: Испания должна выиграть, верно? Но самое интересное и мучительное для трейдеров в футболе заключается именно в этом. Тебе кажется, что ты покупаешь «победу сильной команды», а на самом деле ты покупаешь целую 90-минутную драму судьбы. Первые 15 минут без голов — коэффициенты шевельнулись; через полчаса всё ещё 0:0 — рынок начинает хмуриться; к 70-й минуте тишина, и казавшаяся надёжной победа сильной команды внезапно перестаёт быть такой уж надёжной.

img

Вот тут и возникает классическое противоречие: арбитраж — это хорошо, а прогнозирование — сложно.

Настоящий арбитраж в теории должен быть безрисковым. Например, найти набор взаимоисключающих и исчерпывающих контрактов, так что независимо от исхода комбинация выплачивается, а стоимость покупки ниже суммы выплаты. Звучит заманчиво, как послеобеденный сон трейдера. Но проблема в том, что таких возможностей слишком мало, они быстро исчезают, и их объём часто недостаточен.

Прогнозирование — совсем другое дело. Можно оценить, что сильная команда, скорее всего, выиграет, проанализировать состав, форму, календарь, травмы, посмотреть подразумеваемые вероятности по коэффициентам, но матч не будет подыгрывать только потому, что мы тщательно всё проанализировали. Особенно в футболе: ранняя красная карточка, штанга, нелепый VAR — и красивая логика превращается в молчаливые три секунды послематчевого разбора.

img

Итак, вопрос в следующем: если чистый арбитраж слишком редок, а чистое прогнозирование слишком случайно, можем ли мы занять позицию между ними? Рынок сам предоставляет некоторые априорные вероятности, например, цену победы сильной команды, цену счёта 0:0, цену 0:1. Эти цены не берутся из ниоткуда — они отражают коллективную оценку рынком различных сценариев. Так можем ли мы использовать эти априорные вероятности и, добавив немного собственной математической модели, сформировать неидеальную, но более защищённую комбинацию, чтобы открыть окно «схождения путей»?

Это и есть отправная точка данной идеи.

Это не традиционный безрисковый арбитраж и не просто прогнозирование «на глаз». Это, скорее, компромисс: сначала признать, что основные вероятности, данные рынком, имеют справочную ценность, затем использовать маловероятные сценарии для защиты самых уязвимых частей основного суждения, а также с помощью простой модели проверить, приемлема ли цена.

Предположим, в матче Бразилия явно сильнее Гаити. Рынок даёт цену победы Бразилии 0,89 — это указывает на то, что победа Бразилии — сильный основной сценарий. Но мы не будем покупать только победу Бразилии, а одновременно рассмотрим два защитных сценария: 0:0 и 0:1. Потому что для суждения о победе сильной команды самый неприятный ранний сценарий — это не все возможные исходы, а когда матч никак не открывается или слабая команда забивает первой.

Таким образом, начальная комбинация будет такой:

text
Победа Бразилии Да 0:0 Да 0:1 Да

Предположим, цены:

text
Победа Бразилии = 0,89 0:0 = 0,016 0:1 = 0,011

Общая стоимость трёх ног:

text
C = 0,89 + 0,016 + 0,011 = 0,917

Этот набор не является исчерпывающим событием. Он не охватывает 1:1, 0:2, 2:2 и все странные сценарии. Поэтому, если держать до финального свистка, он, конечно, может принести убыток, и довольно прямой. Но у него есть одна важная особенность: он объединяет три вероятности, уже заданные рынком, в корзину сценариев вокруг основной победы.

Если в итоге Бразилия выигрывает, комбинация выплачивает 1. Если в итоге 0:0 или 0:1 — тоже выплачивает 1. То есть он покупает:

img

text
Победа Бразилии ∪ 0:0 ∪ 0:1

Если произойдёт хотя бы один из этих сценариев, выплата при истечении составит 1. Стоимость — 0,917, запас по покрываемым сценариям — 0,083. Но ключевой момент не в финале, а на промежуточном этапе.

Если Бразилия забивает рано, счёт становится 1:0, тогда две защитные ноги (0:0 и 0:1) практически обнуляются, но цена победы Бразилии вырастет. Если в этот момент цена продажи победы Бразилии превысит первоначальную общую стоимость плюс небольшую целевую прибыль, можно закрыть основную победу и досрочно завершить комбинацию.

Формула проста:

text
Условие фиксации прибыли = bid победы Бразилии >= начальная общая стоимость C + целевая прибыль

Например, целевая прибыль установлена 0,02:

text
Цена срабатывания = 0,917 + 0,02 = 0,937

Если после 1:0 bid победы Бразилии достиг 0,95, то:

text
Зафиксированная прибыль = 0,95 - 0,917 = 0,033

В этом случае мы зарабатываем не за счёт финального розыгрыша, а за счёт того, что ход матча вошёл в благоприятную ветвь, и мы досрочно продали комбинацию. Этот процесс напоминает то, как рынок открывает для вас маленькое окно — не стойте у окна, сочиняя стихи, лучше пролезайте в него.

Но здесь есть ещё одна проблема: если три ноги выглядят дёшево, означает ли это, что их обязательно стоит покупать? Не обязательно. Рыночная цена — это только первый уровень информации. Нам нужна собственная мерка-ориентир, пусть даже простая.

Здесь я использовал самую базовую пуассоновскую модель забитых голов.

Счёт в футболе можно грубо рассматривать как случайный процесс, в котором две команды забивают голы за 90 минут. Предположим, ожидаемое количество голов хозяев за 90 минут равно λ_home, ожидаемое количество голов гостей — λ_away. Тогда вероятность того, что хозяева забьют i голов, а гости — j голов, можно записать как:

text
P(i, j) = Pois(i; λ_home) × Pois(j; λ_away)

где:

text
Pois(k; λ) = e^(-λ) × λ^k / k!

img

Конечно, она очень грубая. Футбол — это не два независимых автомата для розыгрыша: после гола меняется тактика, появляются красные карточки, меняется психология. Но её достоинство — простота и прозрачность; по крайней мере, она не даёт нам действовать совсем наугад.

Перед матчем пуассоновская модель может дать первоначальную ориентировку. Мы можем вручную задать λ_home и λ_away или позволить программе вывести их из точных рыночных котировок на счёт. Например, котировки на счёта 0:0, 0:1, 1:0, 1:1, 2:0, 2:1, 3:0 — каждая из них представляет собой точку вероятности, данную рынком. Программе нужно найти такие λ_home и λ_away, чтобы вероятности счёта, рассчитанные по пуассоновской модели, максимально приближались к этим рыночным ценам.

Другими словами, рынок говорит: «Я думаю, эти счета стоят примерно этих денег». А пуассоновская модель рядом шепчет: «Ладно, попробую подогнаться и посмотреть, какая интенсивность голов скрывается за этими ценами».

В стратегии можно настроить:

python
CALIBRATE_LAMBDA_FROM_MARKET = True MODEL_SCORE_SAMPLES = "0-0,0-1,1-0,1-1,2-0,2-1,3-0"

Эти счета используются только для моделирования, не для совершения сделок. Торгуемые ноги по-прежнему:

text
Победа целевой команды 0:0 0:1

В коде для подбора λ используется поиск по сетке. Это не сложно, но очень наглядно.

python
def fit_lambdas_from_score_markets(quotes, model_score_legs, event_state=None): samples = [] live_score = event_state.get("score_tuple") if event_state else None minute = event_state.get("elapsed") if event_state else None is_live = bool(live_score and minute not in [None, ""]) for leg in model_score_legs: q = quotes.get(leg["name"]) p_market = quote_probability(q) if p_market is None: continue target_h, target_a = parse_score_text(leg["score"]) if is_live: current_h, current_a = live_score if current_h > target_h or current_a > target_a: continue samples.append((target_h - current_h, target_a - current_a, p_market, leg["score"])) else: samples.append((target_h, target_a, p_market, leg["score"])) if len(samples) < 2: return None best = None for ih in range(5, 501, 5): lh = ih / 100.0 for ia in range(5, 501, 5): la = ia / 100.0 err = 0.0 for add_h, add_a, p_market, _score in samples: p_model = poisson_pmf(add_h, lh) * poisson_pmf(add_a, la) err += (p_model - p_market) ** 2 if best is None or err < best["err"]: best = {"lambda_home": lh, "lambda_away": la, "err": err, "samples": samples} if is_live: ratio = max(0.01, max(0.0, 90.0 - float(minute)) / 90.0) best["lambda_home"] = best["lambda_home"] / ratio best["lambda_away"] = best["lambda_away"] / ratio best["source"] = "live_score_markets" else: best["source"] = "pre_match_score_markets" return best

Перед матчем этот λ — лишь начальная калибровка. Поскольку игра ещё не началась, нет возможности обновлять по реальному ходу событий, счёт по умолчанию 0:0, оставшееся время — 90 минут. На этом этапе мы используем его для фильтрации входа:

text
Вероятность покрытия модели = P(Победа целевой команды) + P(0:0) + P(0:1)

И требуется:

text
Вероятность покрытия модели - Рыночная цена >= Запас прочности

Открывать позицию разрешается только тогда, когда рыночная цена достаточно низкая, и модель считает, что у данной корзины есть хоть небольшое преимущество.

Действительно интересное начинается после начала матча.

Как только игра началась, пуассоновская модель перестаёт быть статичной. Предположим, матч идёт 30-я минута, текущий счёт всё ещё 0:0, тогда оставшееся время — всего 60 минут, и интенсивность будущих голов должна быть уменьшена пропорционально оставшемуся времени:

text
λ_home_remaining = λ_home × (90 - t) / 90 λ_away_remaining = λ_away × (90 - t) / 90

Если текущий счёт уже 1:0, то счета 0:0 и 0:1 уже невозможны. В этом случае модель должна исходить из текущего счёта и рассчитывать только то, сколько голов будет забито в оставшееся время. Только счета, которые всё ещё возможны (например, 2:0, 2:1, 3:0, 1:1), имеют право участвовать в новой оценке.

В этом суть обновления Пуассона в реальном времени: не механически уменьшать предматчевый λ каждую минуту, а заново оценивать, как может развиваться игра дальше, учитывая текущий счёт, оставшееся время и всё ещё возможные точные счета.

В итоге стратегия превращается в три уровня проверки.

Первый уровень — рыночная цена:

text
win_ask + 0:0_ask + 0:1_ask <= Максимально допустимая стоимость

Второй уровень — фильтрация Пуассона:

text
Вероятность покрытия модели - Рыночная цена >= Запас прочности

Третий уровень — сходимость пути:

text
Текущая стоимость бид комбинации >= Начальная стоимость + Целевая прибыль

Только если одновременно выполнены первый и второй уровни, рассматривается вход. После входа больше не полагаемся на модель для фантазий о финале, а используем реальные бид-цены для решения, можно ли закрыть позицию. Модель отвечает за повышение качества входа, а рыночные цены — за возможность фиксации результата.

Поиск контрактов стараются сделать максимально простым. Слаг рынка Polymarket для чемпионата мира очень предсказуем. Например, слаг события для матча:

python
EVENT_SLUG = "fifwc-aut-jor-2026-06-17"

Если мы защищаем победу Jordan, то суффикс соответствующего контракта на победу:

python
WIN_SUFFIX = "jor"

Тогда три необходимых для торговли контракта можно собрать напрямую:

python
def yes_symbol(slug): return slug + "_USDC.Yes" def build_legs(): legs = [ { "name": "win", "slug": EVENT_SLUG + "-" + WIN_SUFFIX, "symbol": yes_symbol(EVENT_SLUG + "-" + WIN_SUFFIX), "kind": "win", } ] for score in parse_scores(PROTECT_SCORES): legs.append( { "name": "score_" + score.replace("-", "_"), "slug": EVENT_SLUG + "-exact-score-" + score, "symbol": yes_symbol(EVENT_SLUG + "-exact-score-" + score), "kind": "score", "score": score, } ) return legs

Здесь стоит избегать нечёткого поиска по названиям команд. Например, при поиске Jordan легко найти Michael B. Jordan, Jordan Pickford, Jordan Spieth, и в итоге, не успев запустить футбольную стратегию, мы получим за столом представителей шоу-бизнеса, английского вратаря и гольфа. Использование event slug для сборки контрактов гораздо чище.

Во время матча также нужен live-счёт. В первой версии его можно получать напрямую из Polymarket Gamma event:

python
def get_event_state(): data = get_json(GAMMA_BASE + "/events", slug=EVENT_SLUG) e = data[0] return { "title": e.get("title"), "score": e.get("score"), "score_tuple": parse_score(e.get("score")), "elapsed": e.get("elapsed"), "period": e.get("period"), "live": bool(e.get("live")), "ended": bool(e.get("ended")), "start_time": e.get("startTime"), }

Текущая стоимость корзины с использованием реального бида:

python
def basket_bid_value(legs, quotes): total = 0.0 for leg in legs: pos = positions.get(leg["name"], {}) amount = float(pos.get("amount", 0)) if amount <= 0: continue q = quotes.get(leg["name"]) if not q or q["bid"] is None: continue total += amount * q["bid"] return total

Определение тейк-профита:

python
cost = current_position_cost() value = basket_bid_value(legs, quotes) target = cost + TARGET_PROFIT * SHARES if value >= target: close_all()

Это минимальная версия. Она не делает вид, что решила задачу прогнозирования футбольных матчей, и не заявляет о стабильном арбитраже. Она лишь пытается исследовать серую зону между «арбитражем» и «прогнозом».

Прелесть арбитража – в определённости, но определённость редка. Привлекательность прогноза – в широких возможностях, но и в высокой случайности. Данная стратегия берёт предсказанные рынком цены в качестве материала, использует одно высоковероятностное основное направление, два низковероятностных защитных пути, а затем применяет модель Пуассона для грубой фильтрации, пытаясь сформировать окно, которое может сойтись раньше окончания матча.

Риски необходимо чётко обозначить. Эта корзина не покрывает все исходы, это не безрисковый арбитраж. Она подходит для матчей с большим разрывом в силах команд, где основной путь достаточно очевиден, а цены защитных путей достаточно низки. Если игра примерно равная (50/50) или защитные ноги уже дороги, навязывать такую сделку бессмысленно. Хуже того, эта конструкция не охватывает все неблагоприятные сценарии, например 1:1, 0:2, 2:2 – они могут привести к заметным убыткам. Поэтому необходимо устанавливать лимиты позиции, максимальный убыток, стоп-лосс и ни в коем случае не воспринимать эту структуру как арбитраж, только потому что она на него похожа.

Модель Пуассона – тоже не магия. Это лишь очень простая математическая основа, которая помогает перейти от «я чувствую, что цена хорошая» к «я хотя бы проверил эту цену прозрачной моделью». Она может ошибаться, рынок может ошибаться, и мы сами можем ошибаться. Самая честная часть трейдинга – признать, что всё это может быть неправильно, и постараться, чтобы ошибка не снесла стол целиком.

Эта попытка очень поверхностна. Она скорее задаёт вопрос: когда чистых арбитражных возможностей становится всё меньше, а чистый прогноз слишком сложен, можем ли мы, используя вероятности, уже заложенные рынком, строить более структурированные сделки? Не мечтая устранить риск, а разложив его на составляющие и поняв, с каких направлений он приходит.

Возможно, это не ответ, но это небольшая ямка, которую стоит копать дальше. Прогноз объясняет нам, какой основной путь может быть шире, а идея арбитража напоминает, что нужно смотреть не только на направление, но и на структуру комбинации. Между ними, вероятно, ещё много пространства для исследований.

Исходный код стратегии: Стратегия сходимости футбольных путей Polymarket

Comment
All comments (0)
No data
No data
  • 1
Forums
PINE Language
Get the app
iPhone Download
© 2015 - ∞ INVENTOR PTE LTD (SG)