HKJC 賠率的內在一致性
同一場波, 馬會同時開出主客和、讓球、入球大細、入球單雙、總入球、波膽等七類盤口。每一類都在講同一件事: 這場波會入多少球、哪一隊入得多。
問題是, 這七套報價背後, 是否真的存在同一個入球分布? 抑或每個盤口各自定價, 合併起來其實互相矛盾?
這個問題可以完全用數據回答, 不需要任何預測模型, 亦不需要知道賽果。本文用 56 場賽事、509 條盤口線、3,248 個獨立選項的即時報價, 加上 90,514 場有賽
果的歷史賠率, 把整個反解過程做一次, 並公開全部方法與程式碼。
本文屬量化研究與教學用途, 所有計算針對公開賠率數據的數學結構, 不構成任何投注建議。文中出現的「有效抽水」「最平路線」等概念, 描述的是成本高低, 不代表任何一種下注方式有正期望值。
本文重點
一句話總結: 可以還原, 而且一致程度遠超預期。逐場用該場全部盤口的報價反解一個 13×13 的比數聯合分布, 56 場合共 3,248 個選項的平均絕對殘差只有 0.20 個百分點。
但這個結論有三個前提, 每一個都值得獨立討論:
去水方法不能隨便選。 五種常見的 de-vig 方法, 在 6% 抽水的讓球盤幾乎沒有分別, 在 50% 抽水的波膽盤可以相差幾倍。
市場心目中的分布不是 Poisson。 三參數的 Dixon–Coles 模型無論如何都對不上, 殘差是非參數解的 1.5 至 6 倍。
盤口之間有大量冗餘, 但不是完全冗餘。 任何一個「勝負類 + 入球類」的兩盤口組合, 已經足以推出其餘盤口到 0.5pp 以內; 但單靠總入球盤, 對主客和的預測誤差高達 32pp。
一、把七個盤口翻譯成同一種語言
要比較不同盤口, 首先要有共同的坐標系。足球賽果的最小完整描述就是最終比數 (i, j), 即主隊入 i 球、客隊入 j 球。取 K = 13 (0 至 12 球), 就有一個 13×13 = 169 格的機率表 p[i][j], 加起來等於 1。
有了這個格, 每一個投注選項都可以寫成格上的一個 0/1 遮罩。「大 2.5」就是所有 i + j ≥ 3 的格; 「主隊 −1」就是所有 i − j ≥ 2 的格; 「2:1」就是單一格。於是任何一個選項的公平機率, 都是遮罩與 p 的內積:
q = Σ over all (i,j) of W[i][j] · p[i][j]所有盤口就此變成同一個線性方程組, 未知數是同一個 p。
K = 13
I_IDX, J_IDX = np.meshgrid(np.arange(K), np.arange(K), indexing="ij")
TOTAL = I_IDX + J_IDX # 總入球
DIFF = I_IDX - J_IDX # 主隊淨勝球
def weight_matrix(odds_type, cond, comb):
if odds_type == "HAD": # 主客和
return {"H": DIFF > 0, "D": DIFF == 0, "A": DIFF < 0}[comb].astype(float)
if odds_type == "HIL": # 入球大細
lines = parse_condition(cond) # "2.5" → [2.5]; "2.5/3.0" → [2.5, 3.0]
w = np.zeros((K, K))
for L in lines: # 半球盤: 一半注碼落一條線
hit = TOTAL > L if comb == "H" else TOTAL < L
w += hit.astype(float) / len(lines)
return w
if odds_type == "HHA": # 讓球主客和
h = float(cond) # 主隊讓球數, 可為負
d = DIFF + h
return {"H": d > 0, "D": d == 0, "A": d < 0}[comb].astype(float)
...這段程式碼裡面最容易出錯、亦最關鍵的一點, 是走盤 (push)。
讓球 0 球或整數球的盤, 打和會退還本金; 大細線是整數時, 總入球剛好等於該線亦會退還。走盤的正確處理方式不是當它輸, 而是把它排除在機率質量之外。換句話說, 一條有走盤可能的盤口線, 它所有選項的遮罩加起來不等於 1, 而是等於 1 − P(走盤)。
寫成檢查式就是:
def sanity_check(book):
"""純分割盤: 各選項遮罩相加必須逐格等於 1; 有走盤的盤: 差額即走盤機率。"""
s = book.weights.sum(axis=0)
push = 1.0 - s
assert (push >= -1e-9).all() and (push <= 1.0 + 1e-9).all()
return push這個檢查在後面的「等效賠率」計算裡救了一次命: 若把走盤當成輸, 讓球盤的成本會被系統性高估。
七類盤口的翻譯結果如下:
盤口 | 代號 | 選項數 | 對應格上條件 | 有走盤 |
讓球 | HDC | 2 | DIFF + h > 0 / < 0 | 整數讓球會 |
入球單雙 | OOE | 2 | TOTAL 單 / 雙 | 否 |
入球大細 | HIL | 2 | TOTAL > L / < L | 整數線會 |
主客和 | HAD | 3 | DIFF 正 / 零 / 負 | 否 |
讓球主客和 | HHA | 3 | DIFF + h 正 / 零 / 負 | 否 |
總入球 | TTG | 8 | TOTAL = 0…6, ≥ 7 | 否 |
波膽 | CRS | 33 | 28 個明確比數 + 5 個「其他」桶 | 否 |
波膽盤要特別小心。馬會列出 28 個明確比數, 其餘全部歸入「其他主勝」「其他和局」「其他客勝」等桶。這些桶的遮罩是「符合該結果, 但不屬於任何一個已列比數」的補集, 不能簡單當成剩餘機率。
二、資料: 七個 snapshot, 56 場, 3,248 個選項
HKJC 的即時賠率經 GraphQL 端點提供。要注意兩點: 端點只接受白名單內的查詢字串, 而且所有變數必須齊備, 缺一個 optional 參數都會回 Invalid queration arguments。
ENDPOINT = "https://info.cld.hkjc.com/graphql/base/"
FULL_VARS = { # 缺任何一個 key 都會被拒
"date": None, "startDate": None, "endDate": None,
"matchId": None, "tournId": None, "teamId": None,
"pmPoolId": None, "featuredPoolsOnly": None, "fbOddsTypes": [],
}
def fetch_odds_batch(odds_types, date):
body = {"query": QUERY_MATCH_LIST, # 逐字抄自官方前端
"variables": {**FULL_VARS, "date": date, "fbOddsTypes": odds_types}}
r = requests.post(ENDPOINT, json=body, headers=BROWSER_HEADERS, timeout=30)
return r.json()["data"]["matches"]單次請求拉不齊七類盤口, 要分批再按 match_id 合併。收集器每五分鐘存一個完整 snapshot, 檔案帶時間戳, 之後統一整理成一張 tidy table。
七個 snapshot 合共記錄 3,758 條盤口線、23,531 個報價點。剔除已開賽的賽事, 每條盤口線只保留最新一次報價, 得出分析樣本:
56 場賽事, 開賽時間橫跨 2026-08-17 至 2026-08-25, 距離開賽 0.7 小時至 8 日 (中位 20.7 小時)
涵蓋英超 (10 場)、阿甲 (7)、墨超 (5)、巴甲 (4)、美職 (4) 等 20 項賽事
509 條盤口線, 展開後 3,248 個獨立選項
其中 30 場七類盤口齊全, 另外 26 場欠讓球盤 (馬會只對部分賽事開讓球)。
三、抽水階梯: 同一場波, 成本相差八倍
去水之前先看抽水。抽水 (overround) 的定義是所有選項隱含機率之和減一:
overround = Σ (1 / o_i) − 1 o_i = 第 i 個選項的賠率
七個盤口排成一條非常整齊的階梯:
盤口 | 選項數 | 抽水中位 | P10–P90 | 價值保留率 |
讓球 | 2 | 6.29% | 5.36–6.65% | 0.941 |
入球單雙 | 2 | 8.12% | 8.11–8.22% | 0.925 |
入球大細 | 2 | 8.28% | 8.14–8.96% | 0.924 |
主客和 | 3 | 13.26% | 12.78–13.76% | 0.883 |
讓球主客和 | 3 | 14.21% | 14.10–14.47% | 0.876 |
總入球 | 8 | 29.67% | 29.53–29.98% | 0.771 |
波膽 | 33 | 49.96% | 49.90–50.50% | 0.667 |
抽水與選項數的關係緊到近乎機械: 對數選項數解釋了 99.7% 的抽水中位變異 (斜率 0.152, 即選項數每翻一倍, 抽水加 10.6 個百分點, p = 1.1e-07)。
用同場配對比較更清楚。以同一場的讓球盤為基準, 波膽盤的抽水多 44.0 個百分點, 即 8.15 倍 (t = 407); 總入球盤多 23.7pp, 即 4.85 倍。這不是抽樣噪音, 是定價政策。
P10–P90 那一欄同樣值得看。波膽盤的抽水區間只有 49.90–50.50%, 幾乎沒有變化 — 這是一條硬性設定的 50% 線, 而非按賽事風險調整的結果。
還有一個較細緻的觀察。入球大細盤的抽水會隨盤口線偏離主線而上升:
偏離主線 | 條數 | 抽水中位 | 最長賠率中位 |
0.00 | 56 | 8.19% | 2.00 |
0.25 | 39 | 8.26% | 2.05 |
0.75 | 17 | 8.66% | 2.70 |
1.00 | 31 | 8.67% | 2.75 |
1.25 | 10 | 8.96% | 3.70 |
同一場波、同一類盤口, 走遠一條線就貴多 0.8pp。這與後面「冷門被抽得更狠」的發現是同一個現象的兩面。
四、去水: 五種方法, 抽水愈厚分歧愈大
抽水要移除才能得到公平機率。這一步沒有唯一答案, 常見有五種做法, 每種對「抽水如何分攤在各選項之間」有不同假設。
以下用 r_i = 1/o_i 表示原始隱含機率, B = Σ r_i 表示 booksum:
Proportional (按比例): q_i = r_i / B。假設抽水按機率大小等比例攤分。最簡單, 亦最常見。
Additive (等額扣減): q_i = r_i − (B − 1)/n。假設每個選項扣同樣多的絕對機率。
Power (冪律): 求 k 使 Σ r_i^k = 1。抽水對長賠率的相對影響較大。
Odds-ratio: 求 c 使 Σ r_i / (c + r_i − c·r_i) = 1。
Shin: 假設市場中有比例 z 的知情資金, 莊家為此加價。求解
sqrt( z² + 4(1−z)·r_i²/B ) − z
q_i = ─────────────────────────────────── 並要求 Σ q_i = 1
2(1−z)def shin(odds):
r = 1.0 / np.asarray(odds, dtype=float)
B = r.sum()
def total(z):
return (np.sqrt(z * z + 4 * (1 - z) * r * r / B) - z).sum() / (2 * (1 - z))
lo, hi = 0.0, 0.9 # 二分法求 z 使機率和為 1
for _ in range(80):
mid = (lo + hi) / 2
if total(mid) > 1.0:
lo = mid
else:
hi = mid
z = (lo + hi) / 2
q = (np.sqrt(z * z + 4 * (1 - z) * r * r / B) - z) / (2 * (1 - z))
return q / q.sum()在薄抽水的盤口, 五種方法給出的答案幾乎相同, 選哪一種都無所謂。在厚抽水的盤口, 情況完全不同。

左圖是同一條總入球盤 (抽水 29.7%) 的五種去水結果。頭三格差別有限, 但看右圖便清楚: 分歧全部集中在長尾。到「6 球」和「7 球以上」, additive 直接把機率壓到 0, shin 給出的機率只有 proportional 的 0.38 倍, power 是 0.67 倍。
這不是一條盤口的個別現象。把 HKJC 全部盤口線, 加上 4,000 場 Pinnacle 收市 1X2 作參照畫在一起:

左圖橫軸是該盤口的抽水, 縱軸是五種方法對「最冷一項」給出的機率分歧幅度 (最高減最低, 除以平均)。這條關係跨越四個數量級: Pinnacle 收市盤 2.8% 抽水時, 分歧不足 1%; 馬會讓球盤 6% 抽水時約 0.5%; 到總入球和波膽盤, 分歧超過 100%, 即最高與最低的估計相差超過一倍。
結論很直接: 分析薄抽水市場時, 去水方法幾乎不影響結論; 分析厚抽水市場時, 去水方法本身就是結論的一部分。
五、免模型一致性檢查: 不用任何模型, 直接對數
有了去水後的機率, 就可以做第一個真正的檢驗, 而且完全不需要任何預測模型。
原理是: 某些事件可以由多於一個盤口精確計算。例如 P(總入球 ≥ 3), 波膽盤可以加總、總入球盤可以加總、大細 2.5 盤直接就是。如果三個盤口背後真的是同一個分布, 三個數字應該一致。
TARGETS = {
"P(主勝)": DIFF > 0,
"P(和局)": DIFF == 0,
"P(總入球≥3)": TOTAL >= 3,
"P(總入球單數)": TOTAL % 2 == 1,
...
}
def exact_value(book, mask, devig):
"""只有當 mask 可由該盤口的選項精確拼砌時才回傳數值, 否則回 None。"""
w = book.weights # (n_outcome, K, K)
inside = (w * mask).sum(axis=(1, 2))
outside = (w * ~mask).sum(axis=(1, 2))
if not (np.isclose(inside, 0) | np.isclose(outside, 0)).all():
return None # 有選項橫跨目標邊界, 無法精確計算
q = devig(book.raw)
return q[inside > outside].sum()這個檢查的好處是沒有任何自由度: 兩個盤口對同一件事的講法, 要麼一致, 要麼不一致。
先看單一目標。以波膽盤為基準 (它包含最完整的資訊), 其他盤口的偏差 (百分點, 正數代表該盤口報得較高):
目標 | 盤口 | additive | odds_ratio | power | proportional | shin |
P(主勝) | HAD | +0.94 | +0.52 | +1.10 | −0.50 | +0.53 |
P(主勝) | HHA | −1.25 | +0.09 | −1.15 | +1.80 | −0.38 |
P(總入球≥3) | HIL | +4.35 | −3.40 | −0.50 | −3.88 | +1.07 |
P(總入球≥3) | TTG | +2.97 | −1.90 | −0.02 | −2.13 | +1.09 |
看第三、四行。同一件事 P(總入球 ≥ 3), 用 additive 去水會得出大細盤比波膽盤高 4.35pp, 用 proportional 去水則得出低 3.88pp。方向都相反。
把全部目標 × 全部盤口對加起來:
去水方法 | 盤口對數 | 平均絕對偏差 | 最大盤口對偏差 | 不含波膽 |
shin | 12 | 0.927pp | 1.987pp | 0.863pp |
power | 12 | 1.176pp | 2.815pp | 1.864pp |
odds_ratio | 12 | 1.859pp | 3.817pp | 1.635pp |
proportional | 12 | 1.911pp | 3.880pp | 1.758pp |
additive | 12 | 2.431pp | 5.010pp | 1.667pp |

Shin 令各盤口最接近同一個分布, 平均絕對偏差 0.93pp, 是 additive 的三分之一。右圖把「大細盤 vs 總入球盤對 P(總入球 ≥ 3) 的講法」逐場畫出來: proportional 的點系統性地偏在對角線一邊 (平均絕對偏差約 1.7pp), shin 的點則貼住對角線 (約 0.5pp)。
只看抽水相近的二元盤 (排除長尾定價的干擾), 結論略有分歧: P(總入球≥3) 上 shin 最好 (0.49pp), P(主勝) 上則是 odds_ratio 最好 (1.01pp), shin 緊隨 (1.11pp)。沒有一種方法在所有測試上通殺, 但 shin 是唯一在兩項測試都排前二的方法。
六、正式反解: 一個 13×13 分布, 對到七個盤口
免模型檢查只用到少數幾個「剛好可以互相對照」的事件。真正的問題是: 能不能為每一場波找到一個 169 格的分布 p, 同時解釋該場所有盤口的每一個報價?
把每個選項寫成一條方程: w · p = q。全部堆起來變成矩陣方程 A p ≈ b, 再加上 p ≥ 0 和 Σp = 1。
def build_system(books, q_all):
"""每個選項一行: A[k] · vec(p) = 該選項的去水後機率。"""
rows, rhs = [], []
for b in books:
q = q_all[id(b)]
push = 1.0 - b.weights.sum(axis=0) # 走盤機率, 逐格
for k in range(b.n):
rows.append(b.weights[k].ravel())
rhs.append(q[k] * (1.0 - float((push * p_hint).sum())))
return np.asarray(rows), np.asarray(rhs)單靠最小平方會有問題: 169 個未知數、幾十條有效方程, 解不唯一, 而且會把質量推到極端比數上。所以用最大熵原則: 在所有滿足約束的分布之中, 取離參照分布最近 (KL 散度最小) 的那個, 即除盤口本身的資訊外不額外假設任何結構:
min over p : Σ p_ij · log( p_ij / p_ref_ij ) + λ · ‖A·p − b‖²
subject to : p ≥ 0 , Σ p = 1參照分布 p_ref 用同一場的 Dixon–Coles 擬合結果, 目的只是給極端比數一個合理的尾部形狀, 對主要格點的影響可以忽略。
def solve_maxent(A, b, p_ref=None, lam=1e4):
ref = np.full(A.shape[1], 1.0 / A.shape[1]) if p_ref is None else p_ref
log_ref = np.log(np.clip(ref, 1e-12, None))
def obj(theta): # softmax 參數化, 自動滿足 p≥0, Σp=1
p = np.exp(theta - theta.max()); p /= p.sum()
kl = float(p @ (np.log(np.clip(p, 1e-300, None)) - log_ref))
r = A @ p - b
return kl + lam * float(r @ r)
res = minimize(obj, log_ref.copy(), method="L-BFGS-B",
options={"maxiter": 4000})
p = np.exp(res.x - res.x.max())
return p / p.sum()結果如下。逐場反解 56 場, 用 shin 去水:
盤口 | power | proportional | shin |
入球單雙 | 0.101 | 0.044 | 0.038 |
波膽 | 0.167 | 0.231 | 0.123 |
總入球 | 0.376 | 0.365 | 0.236 |
入球大細 | 0.515 | 0.354 | 0.270 |
讓球主客和 | 1.152 | 1.013 | 0.402 |
讓球 | 0.543 | 0.398 | 0.433 |
主客和 | 1.166 | 0.742 | 0.475 |
全盤口合計 | 0.378 | 0.358 | 0.200 |
(單位: 百分點)
平均絕對殘差 0.20 個百分點。 換個講法: 每場用一個 169 格的分布去解釋該場所有盤口的報價, 56 場合計 3,248 個報價, 平均每個報價的機率誤差是萬分之二十。
用 shin 去水的殘差, 比 proportional 或 power 細接近一半。這與第五節的免模型檢查獨立地指向同一個結論。
單場的樣子:

左邊是還原出來的比數聯合分布, 中間是它推算的總入球邊際分布與總入球盤報價的對照。右邊最能說明問題: 這場波七個盤口共 60 個選項, 全部落在對角線上, 最大偏離只有 0.78pp。由 60% 級數的主勝機率, 一路到 0.2% 級數的冷門比數, 跨越三個數量級都對得上。
答案是肯定的: 七個盤口確實共用同一個入球分布。
七、市場心目中的分布, 不是 Poisson
反解出來的 p 有 169 個自由度。一個自然的追問是: 需要這麼多嗎? 足球比分的標準模型 Dixon–Coles 只用三個參數 (λ主、λ客、低比數修正 ρ), 會不會已經足夠?
把同一組約束改為擬合 Dixon–Coles 的三個參數, 再比較殘差:

盤口 | Dixon–Coles (3 參數) | 非參數 (169 格) | 倍數 |
主客和 | 0.815 | 0.475 | 1.7× |
讓球 | 0.548 | 0.433 | 1.3× |
讓球主客和 | 0.658 | 0.402 | 1.6× |
入球大細 | 0.413 | 0.270 | 1.5× |
總入球 | 0.427 | 0.236 | 1.8× |
波膽 | 0.220 | 0.123 | 1.8× |
入球單雙 | 0.222 | 0.038 | 5.8× |
跨場的參數中位是 λ主 = 1.463、λ客 = 1.125、ρ = −0.021, 數值本身很合理。但殘差全面較高, 而且差距最大的是入球單雙, 這正是 Poisson 結構最緊的地方。獨立 Poisson 的總入球單雙機率由 λ 完全決定, 沒有任何自由度; 市場的報價明顯不受這個約束。
需要強調的是, 0.22pp 的殘差以絕對水平計依然很細, Dixon–Coles 作為近似仍然實用。但市場的定價確實帶有三參數模型容納不了的結構, 這個結構是系統性的, 不是噪音。
八、資訊冗餘: 用哪幾個盤口就足夠?
既然七個盤口共用一個分布, 那它們之間必然有大量重複資訊。哪些是冗餘, 哪些是獨有?
做法是留一驗證: 只用部分盤口反解 p, 再看它對沒有參與擬合的盤口報價預測得幾準。

擬合用盤口 | 擬合外選項數 | 平均絕對殘差 | RMSE |
只用總入球 | 2,800 | 8.14pp | 16.71 |
只用波膽 | 1,400 | 0.77pp | 0.97 |
主客和 + 入球大細 | 2,774 | 0.49pp | 0.85 |
讓球主客和 + 入球大細 | 2,636 | 0.47pp | 0.79 |
主客和 + 總入球 | 2,632 | 0.46pp | 0.80 |
任何一個「勝負類 + 入球類」的兩盤口組合, 已經足以推出其餘五個盤口到 0.5pp 以內。單靠波膽盤一個 (它有 33 個選項) 也做到 0.77pp。
反例極端: 只用總入球盤, 樣本外殘差是 8.14pp, 高出十幾倍。逐盤口拆開看就明白原因:
擬合外盤口 | 平均絕對殘差 |
讓球 | 38.04pp |
主客和 | 32.19pp |
讓球主客和 | 26.04pp |
波膽 | 3.71pp |
入球大細 | 0.73pp |
入球單雙 | 0.47pp |
總入球盤只約束 TOTAL 的邊際分布, 對 DIFF 一無所知。它可以完美推出大細和單雙 (兩者都只是 TOTAL 的函數), 但對「哪隊贏」的預測誤差高達 32 至 38 個百分點, 相當於完全沒有資訊。
圖 6 右邊補上另一個發現: 在各種兩盤口組合下, 樣本外殘差最集中的位置都是讓球盤。讓球盤的線由莊家選定, 而且經常是四分一球 (例如 −0.5/−1.0), 它帶著「市場認為差距落在哪個窄區間」的資訊, 是其他盤口的粗網格捕捉不到的。
九、歷史驗證: 90,514 場有賽果的樣本
以上全部分析都沒有用到賽果 — 這是刻意的, 因為一致性是賠率的內在性質。但要判斷「哪種去水最貼近真實機率」, 始終要有結果數據。
用 football-data.co.uk 的歐洲 13 個聯賽、21 個球季共 90,514 場, 其中 58,026 場有 Pinnacle 收市 1X2 賠率。

第一項: 收市 1X2 的校準。 Pinnacle 收市盤平均抽水只有 2.77%:
方法 | log loss | Brier | 平均絕對分桶偏差 | 對 power 的 Δlog loss | p |
power | 0.97386 | 0.57982 | 0.427pp | — | — |
additive | 0.97387 | 0.57983 | 0.425pp | +0.11e-4 | 0.556 |
shin | 0.97392 | 0.57985 | 0.526pp | +0.66e-4 | 0.015 |
odds_ratio | 0.97395 | 0.57986 | 0.558pp | +0.92e-4 | 0.0018 |
proportional | 0.97420 | 0.57998 | 0.913pp | +3.38e-4 | 7.1e-06 |
這裡出現一個表面矛盾: 在 HKJC 的跨盤口一致性測試裡 shin 最好, 在歷史校準測試裡卻是 power 最好, shin 排第三。
矛盾其實不存在。看清楚 log loss 的差距: 最好與最差之間只有 3.4e-4, 在 0.974 的水平上是萬分之三。抽水只有 2.8% 時, 五種方法本來就近乎等價, 排名的實際意義極低。
真正有用的是校準曲線的形狀。圖 8 左圖顯示, proportional 在熱門一端 (報價機率 65% 以上) 系統性高估 2.70pp, 在冷門一端 (5–10%) 系統性低估 1.72pp。這就是教科書上的 favourite–longshot bias。Shin 把這個偏差壓到 1.74pp 和 1.06pp, 減幅約三分之一, 但沒有完全消除。
換句話說: 熱門被低估、冷門被高估的現象, 有一部分來自去水方法的假設錯誤, 但另有一部分是市場的真實定價偏好, 任何去水方法都消不掉。
第二項: 歷史樣本的免模型一致性。 用 8,631 場同時有 1X2 與亞洲讓球收市盤的賽事, 檢查「讓球 −0.5 應該等於 P(主勝)」這類恆等式:
讓球線 | proportional | additive | power | odds_ratio | shin |
−0.5 | 0.258 | 0.259 | 0.267 | 0.102 | 0.147 |
0.0 | 0.086 | 0.085 | 0.103 | 0.102 | 0.093 |
+0.5 | 0.254 | 0.259 | 0.270 | 0.111 | 0.155 |
合計 | 0.187 | 0.188 | 0.200 | 0.104 | 0.127 |
(單位: 百分點)
在 2.4–3.0% 抽水的市場, 兩個獨立盤口對同一件事的講法相差只有 0.10 至 0.20 個百分點。市場的內在一致性極高, 這也印證了第六節在 HKJC 高抽水環境下得出的 0.20pp 殘差並非巧合。
第三項: 加一個盤口, 分布準多少。 用 6,000 場, 分別以不同盤口組合擬合 Dixon–Coles, 再看它對真實比數的預測:
擬合盤口 | 比數 log loss | 1X2 log loss | 大細 log loss | 對讓球盤誤差 | 對大細盤誤差 |
只用 1X2 | 2.9373 | 0.9606 | 0.7128 | 1.39pp | 10.32pp |
1X2 + 大細 2.5 | 2.8651 | 0.9609 | 0.6741 | 0.65pp | 0.01pp |
1X2 + 大細 + 讓球 | 2.8646 | 0.9612 | 0.6741 | 0.29pp | 0.07pp |
基準線: 用整體實際入球率的固定模型 (λ主 = 1.519, λ客 = 1.175), 比數 log loss 是 3.0351。
從只用 1X2 到加入大細盤, 比數 log loss 由 2.9373 跌到 2.8651, 對大細盤的定價誤差由 10.32pp 跌到 0.01pp。再加讓球盤, 比數預測幾乎沒有進一步改善 (2.8651 → 2.8646), 但對讓球盤自身的定價誤差再減一半。
這一點與第八節完全吻合: 勝負類與入球類各取其一就足夠, 第三個盤口帶來的邊際資訊很有限。
十、實務含意: 抽水不是平均分佈的
既然可以還原一個公平分布, 就可以反過來量度每一個選項的實際成本。方法是留一法: 反解時剔除該盤口自身, 用其餘六個盤口還原的分布作為公平值, 再算
edge_i = q_fair_i × o_i − 1 負值即每 1 元注碼的期望損失
盤口 | 選項數 | 平均有效抽水 | 最好選項 | 最差選項 |
讓球 | 60 | 5.81% | −2.70% | −10.70% |
入球單雙 | 112 | 7.54% | −4.39% | −10.61% |
入球大細 | 306 | 8.29% | −2.30% | −24.70% |
主客和 | 168 | 13.27% | −5.06% | −49.62% |
讓球主客和 | 306 | 14.72% | +1.44% | −41.78% |
總入球 | 448 | 28.71% | −10.04% | −77.17% |
波膽 | 1,848 | 50.63% | −6.06% | −100.00% |
平均值與第三節的名義抽水基本吻合, 這本身是一個一致性檢查。但「最好」與「最差」兩欄的距離說明, 名義抽水只是平均數。
按賠率分組看得更清楚:
賠率區間 | 波膽 | 主客和 | 讓球主客和 | 入球大細 | 總入球 |
1–1.5 | — | −9.9% | −8.8% | −6.4% | — |
2–3 | — | −11.5% | −14.6% | −8.6% | −18.4% |
5–10 | −27.9% | −18.8% | −25.8% | — | −28.9% |
10–25 | −31.2% | −33.4% | −36.1% | — | −36.4% |
60–150 | −70.5% | — | — | — | −53.3% |
150 以上 | −80.0% | — | — | — | — |
同一個主客和盤內, 熱門選項的有效抽水約 10%, 賠率 10 以上的冷門選項則接近 33%。波膽盤賠率 150 以上的選項, 有效抽水達 80%。第三節看到的「盤口線走遠一條就貴 0.8pp」, 在這裡放大成三倍以上的成本差距。
同一個觀點, 選錯路線貴三倍。 由於同一件事可以經多個盤口表達, 成本差別可以直接量度:
觀點 | 入球大細 | 總入球 | 波膽 | 主客和 |
大 2.5 (總入球 ≥ 3) | 8.21% | 25.41% | 37.97% | — |
細 2.5 (總入球 ≤ 2) | 7.48% | 21.22% | 28.34% | — |
主勝 | — | — | 36.18% | 13.21% |
和局 | — | — | 30.52% | 14.47% |
兩隊皆有入球 | — | — | 35.16% | — |
「大 2.5」經大細盤表達成本 8.21%, 經總入球盤加總是 25.41%, 經波膽盤砌是 37.97%。同一個觀點、同一個結算條件, 成本差 4.6 倍。逐場統計, 大細盤在 75% 場次是最平路線, 總入球盤佔 25%。
最後: 有沒有套戥? 既然七個盤口共用一個分布但各有抽水, 一個自然問題是能否組合出無風險利潤。用線性規劃求「最少要多少本金, 才能保證任何比數下都收回 1 元」:
# 變數: 每個選項的注碼 x_i ≥ 0
# 約束: 對每個比數 (i,j), Σ_k x_k · payoff_k(i,j) ≥ 1
# 目標: min Σ x_i → 最優值 < 1 即存在套戥
res = linprog(c=np.ones(n), A_ub=-payoff.T, b_ub=-np.ones(K * K), bounds=(0, None))56 場全部檢查:
七個盤口同時使用, 保證回本的最低本金中位為 1.0689 元
最佳單一盤口需要 1.0778 元
出現套戥 (低於 1.00) 的場數: 0 / 56
跨盤口組合相對最佳單一盤口的改善, 中位只有 0.73 個百分點, 最大 1.94 個百分點 (圖 9 右)。
這個結果與前面的分析吻合: 正因為七個盤口高度一致, 它們之間才沒有套戥空間。跨盤口組合唯一的作用, 是把保證回本的成本由 7.8% 壓到 6.9%, 距離收支平衡仍然很遠。
十一、方法的限制
樣本的時間跨度短。 七個 snapshot 集中在約 40 分鐘內, 距離開賽 0.7 小時至 8 日不等, 不足以分析賠率隨開賽時間的動態。「臨近開賽時一致性會否收窄」這個問題, 本文回答不到。
參照分布的選擇有影響。 最大熵解在約束稀疏的格點 (例如 8:3 這類比數) 主要由 p_ref 決定。本文用 Dixon–Coles 作參照, 換一個參照會改變極端尾部, 但對佔九成以上機率質量的主要格點影響很細。
走盤機率的處理是近似。 計算約束右邊時, 走盤機率用當前迭代的 p 估算, 存在輕微的循環依賴。實測收斂很快, 但這是一個近似。
波膽盤的「其他」桶。 五個 catch-all 桶佔的機率不多 (等比例隱含機率約 0.3–4%), 但它們的遮罩定義依賴「馬會明確列出了哪 28 個比數」, 若不同賽事列表不同, 需要逐場重建。
總結
七個盤口能否還原一個一致的市場預期入球分布? 能, 而且一致程度遠高於預期: 同一場波之內, 七類結算方式完全不同的盤口共用同一個 169 格分布時, 平均誤差只有 0.20 個百分點 (56 場、3,248 個選項)。
但這個「能」有條件。去水方法在厚抽水的盤口是決定性的; 市場的分布不服從三參數 Poisson 結構; 而勝負類與入球類盤口之間, 存在不能互相取代的資訊。
概念 | 實務作用 | 章節 |
比數格上的線性約束 | 把七類盤口翻譯成同一種語言 | 一 |
走盤的正確處理 | 避免系統性高估讓球盤成本 | 一 |
抽水 ∝ log(選項數) | 一眼判斷某盤口的定價層級 | 三 |
去水方法的分歧隨抽水擴大 | 決定何時要認真挑方法 | 四、九 |
免模型一致性檢查 | 不用賽果就能評估去水方法 | 五 |
最大熵反解 | 由多個盤口合成一個分布 | 六 |
非參數 vs Dixon–Coles | 判斷參數模型夠不夠用 | 七 |
留一樣本外測試 | 找出哪些盤口帶獨有資訊 | 八 |
逐選項有效抽水 | 量度真實成本而非名義抽水 | 十 |
線性規劃套戥檢查 | 驗證市場一致性的另一個角度 | 十 |
最後補充一點: 高度一致本身就是套戥空間不存在的原因。若七個盤口真的各自為政, 反而會出現無風險套利的縫隙; 實際觀察到的是 56 場全部沒有。對於想由賠率提取市場觀點的人, 這代表任何一個資訊量足夠的盤口已經包含大部分內容, 不必逐個盤口分開處理。
Reference
Shin, H. S. (1993). Measuring the Incidence of Insider Trading in a Market for State-Contingent Claims. The Economic Journal, 103(420), 1141–1153.
Dixon, M. J., & Coles, S. G. (1997). Modelling Association Football Scores and Inefficiencies in the Football Betting Market. Journal of the Royal Statistical Society: Series C, 46(2), 265–280.
Štrumbelj, E. (2014). On Determining Probability Forecasts from Betting Odds. International Journal of Forecasting, 30(4), 934–943.
Clarke, S., Kovalchik, S., & Ingram, M. (2017). Adjusting Bookmaker's Odds to Allow for Overround. American Journal of Sports Science, 5(6), 45–49.
Jaynes, E. T. (1957). Information Theory and Statistical Mechanics. Physical Review, 106(4), 620–630.



