Type/to search
2
Follow
490
Followers
차익거래와 예측 사이: 월드컵 경로 수렴 전략의 소박한 실험
Discussions
Created 2026-06-18 09:09:14  Updated 2026-06-22 15:37:13
 0
 210

img

월드컵이 막 시작했을 때, 시장은 우리에게 작은 충격 교육을 선사했습니다: 강팀이라고 해서 항상 넘어지지 않는 것은 아니며, 단지 넘어지는 자세가 종종 우리가 상상한 것보다 더 창의적일 뿐이라는 것을요.

예를 들어 스페인 0:0 카보베르데. 경기 전에 실력, 순위, 선수 구성만 보면 대부분의 사람들은 직관적으로 생각하기 쉽습니다: 스페인이 이길 거라고. 하지만 축구가 가장 흥미롭고 동시에 트레이더를 괴롭히는 지점이 바로 여기에 있습니다. 당신은 '강팀 승'을 샀다고 생각하지만, 실제로는 90분 내내 펼쳐지는 운명의 연속극을 산 것입니다. 전반 15분 동안 골이 안 들어오면 배당이 움직입니다. 30분이 지나도 0:0이면 시장은 찡그리기 시작합니다. 70분이 되어도 아무 일이 없으면, 처음에는 안정적으로 보였던 강팀 승이 갑자기 불안정해집니다.

img

이때 고전적인 모순에 직면하게 됩니다: 차익 거래는 좋지만, 예측은 어렵다는 것입니다.

진정한 차익 거래는 이론적으로 무위험이어야 합니다. 예를 들어 상호 배타적이고 완전한 계약 집합을 찾아서, 어떤 결과가 일어나든 조합이 지급될 수 있어야 하고, 매수 비용이 지급 금액보다 낮아야 합니다. 듣기에는 좋아 보입니다, 트레이더 버전의 낮잠처럼요. 하지만 여기에 문제가 있습니다: 이런 기회는 너무 적고, 발생하면 보통 빨리 사라지며, 용량도 충분하지 않을 수 있습니다.

예측은 또 다른 이야기입니다. 당신은 강팀이 높은 확률로 이길 것이라고 판단하고, 선수 구성, 컨디션, 일정, 부상을 분석할 수 있으며, 배당률에 내재된 확률도 볼 수 있습니다. 하지만 경기는 우리가 열심히 분석했다고 해서 협조하지 않습니다. 특히 축구는 그렇습니다. 이른 퇴장, 골대, 터무니없는 VAR 하나만으로도 멋진 로직이 경기 후 복기에서 침묵의 3초가 될 수 있습니다.

img

그래서 문제는: 순수 차익 거래는 너무 희소하고, 순수 예측은 너무 무작위적이라면, 우리가 그 중간에 설 수 없을까요? 시장 자체가 이미 우리에게 일부 사전 확률을 제공합니다, 예를 들어 강팀 승의 가격, 0:0의 가격, 0:1의 가격. 이러한 가격은 공중에서 나온 것이 아니며, 시장이 다양한 경로에 대해 집단적으로 책정한 가격을 반영합니다. 그렇다면 우리는 이러한 사전 확률에 약간의 우리 자신의 수학적 모델을 더해, 완벽하지는 않지만 더 보호적인 조합을 만들어 '경로 수렴'의 창을 열 수 있을까요?

이것이 이 아이디어의 출발점입니다.

전통적인 무위험 차익 거래도 아니고, 단순한 감에 의존한 예측도 아닙니다. 절충안에 더 가깝습니다: 먼저 시장이 제공하는 주요 확률이 참고할 가치가 있음을 인정하고, 낮은 확률의 경로를 사용하여 주요 판단에서 가장 취약한 부분을 보호하면서, 간단한 모델로 가격이 여전히 수용 가능한지 확인합니다.

가상의 경기에서 브라질이 아이티보다 훨씬 강하다고 가정해 보겠습니다. 시장이 제시하는 브라질 승의 가격은 0.89이며, 이는 브라질이 이길 강력한 주요 경로임을 나타냅니다. 하지만 우리는 브라질 승만 직접 사지 않고, 동시에 두 가지 보호 경로를 관찰합니다: 0:0과 0:1. 강팀 승 판단에서 가장 괴로운 초기 시나리오는 종종 모든 결과가 아니라 경기가 좀처럼 열리지 않거나 약팀이 한 골을 훔치는 것이기 때문입니다.

따라서 초기 조합은 다음과 같습니다:

text
브라질 승 Yes 0:0 Yes 0:1 Yes

가격은 다음과 같다고 가정합니다:

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의 보호 다리는 기본적으로 0이 되지만, 브라질 승의 가격은 상승합니다. 이때 브라질 승의 매도 가능 가격이 초기 총 비용을 초과하고, 약간의 목표 이익을 더하면, 주승을 청산하고 이 조합을 조기에 마감할 수 있습니다.

공식은 간단합니다:

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
当前组合 bid 价值 >= 初始成本 + 目标利润

첫 번째와 두 번째 레이어가 동시에 충족될 때만 진입을 고려합니다. 진입 후에는 더 이상 모델로 최종 결과를 상상하지 않고, 실제 시장의 bid를 사용하여 청산 가능 여부를 판단합니다. 모델은 포지션 진입 품질을 높이는 역할을 하고, 시장은 청산 가능성을 결정합니다.

계약 검색도 최대한 간단하게 만듭니다. Polymarket의 월드컵 시장 slug는 규칙적입니다. 예를 들어, 한 경기의 event slug는 다음과 같습니다:

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로 계약을 조합하면 훨씬 깔끔합니다.

경기 중에는 실시간 스코어도 필요합니다. 첫 번째 버전에서는 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)