World Cup vừa khai mạc, thị trường đã cho chúng ta một bài học nhỏ đầy bất ngờ: đội mạnh không phải không thể lật xe, chỉ là cách lật thường sáng tạo hơn chúng ta tưởng tượng.
Ví dụ như Tây Ban Nha 0:0 Cape Verde. Trước trận đấu, nếu chỉ nhìn vào sức mạnh, thứ hạng, chiều sâu đội hình, đa số mọi người sẽ có trực giác đơn giản: Tây Ban Nha chắc thắng chứ? Nhưng bóng đá thú vị nhất, cũng là điều hành hạ các nhà giao dịch nhất, chính là ở đây. Bạn nghĩ mình mua "đội mạnh thắng", nhưng thực tế bạn đang mua cả một bộ phim dài tập 90 phút về số phận. 15 phút đầu chưa có bàn, tỷ lệ cược nhúc nhích; nửa tiếng vẫn 0:0, thị trường bắt đầu nhíu mày; đến phút 70 vẫn im hơi lặng tiếng, lúc đầu tưởng đội mạnh thắng chắc, bỗng dưng không còn vững nữa.
Lúc này sẽ gặp một mâu thuẫn kinh điển: Arbitrage tốt, dự đoán khó.
Arbitrage thực sự, về mặt lý thuyết, phải là không có rủi ro. Ví dụ tìm một bộ hợp đồng loại trừ lẫn nhau và đầy đủ, dù kết quả cuối cùng là gì, tổ hợp đều có thể thanh toán và chi phí mua thấp hơn số tiền thanh toán. Nghe có vẻ tuyệt vời, như giấc ngủ trưa của một trader. Nhưng vấn đề là: cơ hội như vậy quá ít, khi xuất hiện thường biến mất rất nhanh, và dung lượng chưa chắc đã đủ.
Dự đoán lại là chuyện khác. Bạn có thể phán đoán đội mạnh có khả năng thắng cao, có thể phân tích đội hình, phong độ, lịch thi đấu, chấn thương, cũng có thể xem tỷ lệ cược ngụ ý xác suất, nhưng trận đấu không diễn ra chỉ vì chúng ta phân tích nghiêm túc. Bóng đá càng như vậy, một thẻ đỏ sớm, một cú dội cột, một VAR kỳ quặc, đều có thể biến một logic đẹp đẽ thành ba giây im lặng trong phần phân tích sau trận.
Vậy câu hỏi đặt ra: Nếu arbitrage thuần túy quá hiếm, còn dự đoán thuần túy lại quá ngẫu nhiên, liệu chúng ta có thể đứng ở giữa cả hai không? Bản thân thị trường đã cho chúng ta một số xác suất tiền đề, ví dụ giá đội mạnh thắng, giá 0:0, giá 0:1. Những mức giá này không phải tự nhiên mà có, chúng phản ánh định giá tập thể của thị trường đối với các kịch bản khác nhau. Vậy chúng ta có thể tận dụng những xác suất tiền đề này, kết hợp với một chút mô hình toán học của riêng mình, để xây dựng một tổ hợp không hoàn hảo nhưng có tính bảo vệ cao hơn, nhằm mở ra một "cửa sổ hội tụ đường đi"?
Đó là điểm khởi đầu của ý tưởng này.
Nó không phải là arbitrage phi rủi ro truyền thống, cũng không phải dự đoán dựa trên cảm tính. Nó giống một sự thỏa hiệp hơn: trước tiên thừa nhận xác suất chính mà thị trường đưa ra có giá trị tham khảo, sau đó dùng các đường đi có xác suất thấp để bảo vệ phần dễ tổn thương nhất trong phán đoán chính, đồng thời dùng một mô hình đơn giản để kiểm tra xem giá còn chấp nhận được không.
Giả sử trong một trận đấu, Brazil rõ ràng mạnh hơn Haiti. Thị trường đưa ra giá Brazil thắng là 0.89, cho thấy Brazil thắng là một đường đi chính mạnh. Nhưng chúng ta không chỉ mua Brazil thắng, mà đồng thời quan sát hai đường đi bảo vệ: 0:0 và 0:1. Bởi vì đối với một phán đoán đội mạnh thắng, kịch bản khó chịu nhất ở giai đoạn đầu thường không phải tất cả các kết quả, mà là trận đấu mãi không có bàn thắng, hoặc đội yếu ăn cắp một bàn.
Vậy tổ hợp ban đầu trở thành:
text
Brazil thắng Yes
0:0 Yes
0:1 Yes
Giả sử giá là:
text
Brazil thắng = 0.89
0:0 = 0.016
0:1 = 0.011
Tổng chi phí ba chân:
text
C = 0.89 + 0.016 + 0.011 = 0.917
Tập hợp này không phải là một sự kiện đầy đủ. Nó không bao gồm 1:1, 0:2, 2:2, cũng không bao gồm tất cả các kịch bản kỳ lạ. Vì vậy nếu giữ đến hết trận, tất nhiên nó có thể thua, và có thể thua rất trực tiếp. Nhưng nó có một đặc điểm rất quan trọng: nó kết hợp ba xác suất mà thị trường đã đưa ra, tạo thành một rổ đường đi xoay quanh chiến thắng của đội chính.
Nếu cuối cùng Brazil thắng, tổ hợp thanh toán 1. Nếu cuối cùng 0:0 hoặc 0:1, cũng thanh toán 1. Nói cách khác, nó mua:
text
Brazil thắng ∪ 0:0 ∪ 0:1
Miễn là một trong những đường đi này xảy ra, thanh toán khi đáo hạn là 1. Chi phí là 0.917, có khoảng cách 0.083 trong phạm vi đường đi được bảo hiểm. Nhưng điểm mấu chốt thực sự không phải ở cuối trận, mà là ở giữa trận.
Nếu Brazil ghi bàn sớm, tỷ số trở thành 1:0, thì hai chân bảo vệ 0:0 và 0:1 gần như về 0, nhưng giá Brazil thắng sẽ tăng lên. Miễn là lúc đó giá bán được của Brazil thắng vượt quá tổng chi phí ban đầu, cộng thêm một chút lợi nhuận mục tiêu, chúng ta có thể đóng chân thắng chính, thu hẹp tổ hợp này trước thời hạn.
Công thức rất đơn giản:
text
Điều kiện chốt lời = Giá bid Brazil thắng >= Tổng chi phí ban đầu C + Lợi nhuận mục tiêu
Ví dụ đặt lợi nhuận mục tiêu là 0.02:
text
Giá kích hoạt = 0.917 + 0.02 = 0.937
Nếu sau 1:0, giá bid Brazil thắng lên 0.95, thì:
text
Lợi nhuận khóa = 0.95 - 0.917 = 0.033
Lúc này chúng ta không kiếm tiền nhờ kết quả cuối trận, mà nhờ đường đi trận đấu đi vào một nhánh thuận lợi, bán tổ hợp trước hạn. Quá trình này hơi giống thị trường mở cho bạn một ô cửa sổ nhỏ, đừng đứng bên cửa sổ làm thơ, hãy chui qua ô cửa trước đã.
Nhưng còn một vấn đề nữa: ba chân nhìn có vẻ rẻ, liệu có đáng mua không? Không nhất thiết. Giá thị trường chỉ là lớp thông tin đầu tiên. Chúng ta cần một thước đo tham khảo của riêng mình, dù nó có đơn giản đến đâu.
Ở đây tôi sử dụng mô hình Poisson cơ bản nhất.
Tỷ số bóng đá có thể được xem gần đúng như quá trình ngẫu nhiên của hai đội ghi bàn trong 90 phút. Giả sử số bàn thắng dự kiến trong 90 phút của đội chủ nhà là λ_home, số bàn thắng dự kiến của đội khách là λ_away, thì xác suất đội chủ nhà ghi i bàn, đội khách ghi j bàn có thể được viết:
text
P(i, j) = Pois(i; λ_home) × Pois(j; λ_away)
Trong đó:
text
Pois(k; λ) = e^(-λ) × λ^k / k!
Tất nhiên mô hình này rất thô. Bóng đá không phải hai cỗ máy rút thăm độc lập, sau khi ghi bàn chiến thuật thay đổi, thẻ đỏ thay đổi, tâm lý cũng thay đổi. Nhưng ưu điểm của nó là đơn giản, minh bạch, ít nhất giúp chúng ta không hoàn toàn hành động theo cảm tính.
Trước trận đấu, mô hình Poisson có thể cung cấp cho chúng ta một tham chiếu ban đầu. Chúng ta có thể tự đưa ra λ_home và λ_away, hoặc để chương trình suy ngược từ các tỷ lệ cược chính xác trên thị trường. Ví dụ, các tỷ lệ 0:0, 0:1, 1:0, 1:1, 2:0, 2:1, 3:0, mỗi tỷ lệ tương đương một điểm xác suất mà thị trường đưa ra. Chương trình cần tìm một bộ λ_home và λ_away để xác suất tỷ số do mô hình Poisson tính toán càng gần với các giá thị trường này càng tốt.
Nói cách khác, thị trường nói: "Tôi nghĩ các tỷ số này đáng giá khoảng từng đó tiền." Mô hình Poisson thì nhỏ giọng bên cạnh: "Tôi thử fit xem, để xem đằng sau bộ giá này ẩn chứa cường độ ghi bàn như thế nào."
Trong chiến lược có thể cấu hình:
python
CALIBRATE_LAMBDA_FROM_MARKET = True
MODEL_SCORE_SAMPLES = "0-0,0-1,1-0,1-1,2-0,2-1,3-0"
Các tỷ số này chỉ dùng để mô hình hóa, không tham gia đặt lệnh. Các chân thực sự giao dịch vẫn là:
text
Đội mục tiêu thắng
0:0
0:1
Code sử dụng grid search để fit λ. Nó không phức tạp, nhưng rất trực quan.
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
Trước trận đấu, λ này chỉ là hiệu chỉnh ban đầu. Bởi vì trận đấu chưa bắt đầu, không có đường đi thời gian thực để cập nhật, tỷ số mặc định vẫn là 0:0, thời gian còn lại là 90 phút. Ở giai đoạn này chúng ta dùng nó làm bộ lọc vào lệnh:
text
Xác suất bao phủ mô hình = P(đội mục tiêu thắng) + P(0:0) + P(0:1)
Sau đó yêu cầu:
text
Xác suất bao phủ mô hình - Chi phí thị trường >= Biên an toàn
Chỉ khi giá thị trường đủ rẻ, và mô hình cũng cho rằng rổ này có một chút lợi thế, mới cho phép mở vị thế.
Điều thực sự thú vị là sau khi trận đấu bắt đầu.
Một khi trận đấu đã bắt đầu, mô hình Poisson không còn tĩnh nữa. Giả sử trận đấu đến phút thứ 30, tỷ số hiện tại vẫn là 0:0, thì thời gian còn lại chỉ có 60 phút, cường độ ghi bàn trong tương lai phải được thu nhỏ theo thời gian còn lại:
text
λ_home_remaining = λ_home × (90 - t) / 90
λ_away_remaining = λ_away × (90 - t) / 90
Nếu tỷ số hiện tại đã là 1:0, thì 0:0 và 0:1 không thể xảy ra nữa. Lúc này mô hình phải xuất phát từ tỷ số hiện tại, chỉ tính toán số bàn thắng sẽ ghi được trong thời gian còn lại. Các tỷ số cuối trận như 2:0, 2:1, 3:0, 1:1 vẫn có thể xảy ra, mới đủ tư cách tham gia ước lượng mới.
Đây chính là điểm mấu chốt của cập nhật Poisson thời gian thực: không phải mỗi phút máy móc thu nhỏ λ trước trận, mà kết hợp tỷ số hiện tại, thời gian còn lại và các thị trường tỷ số chính xác vẫn có thể xảy ra, để ước lượng lại trận đấu này có thể diễn biến tiếp theo như thế nào.
Cuối cùng chiến lược trở thành ba lớp phán đoán.
Lớp thứ nhất là chi phí thị trường:
text
win_ask + 0:0_ask + 0:1_ask <= Chi phí tối đa cho phép
Lớp thứ hai là bộ lọc Poisson:
text
Xác suất bao phủ mô hình - Chi phí thị trường >= Biên an toàn
Lớp thứ ba là hội tụ đường đi:
text
Giá bid của tổ hợp hiện tại >= Chi phí ban đầu + Lợi nhuận mục tiêu
Chỉ khi đồng thời thỏa mãn lớp thứ nhất và lớp thứ hai, mới xem xét vào lệnh. Sau khi vào lệnh, không còn dựa vào mô hình để tưởng tượng kết quả cuối cùng, mà dùng bid thực tế của thị trường để phán đoán có thể đóng vị thế hay không. Mô hình chịu trách nhiệm nâng cao chất lượng mở vị thế, thị trường chịu trách nhiệm quyết định có thể chốt lời hay không.
Việc tra cứu hợp đồng cũng cố gắng làm đơn giản. Slug của thị trường World Cup trên Polymarket rất có quy luật. Ví dụ event slug của một trận đấu là:
python
EVENT_SLUG = "fifwc-aut-jor-2026-06-17"
Nếu chúng ta bảo vệ Jordan thắng, hậu tố của hợp đồng thắng tương ứng là:
python
WIN_SUFFIX = "jor"
Vậy ba hợp đồng cần thiết cho giao dịch có thể được ghép trực tiếp:
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
Ở đây cố gắng không dùng tên đội bóng để tìm kiếm mơ hồ. Ví dụ tìm Jordan, rất dễ tìm ra Michael B. Jordan, Jordan Pickford, Jordan Spieth, cuối cùng chiến lược bóng đá chưa bắt đầu, thì giới giải trí, thủ môn Anh và golf đã ngồi cùng bàn rồi. Dùng event slug để ghép hợp đồng, sạch sẽ hơn nhiều.
Trong trận đấu còn cần tỷ số thời gian thực. Phiên bản đầu tiên có thể lấy trực tiếp từ 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"),
}
Kết hợp giá trị bán khả dụng hiện tại bằng bid thực tế của sổ lệnh:
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
Xác định chốt lời:
python
cost = current_position_cost()
value = basket_bid_value(legs, quotes)
target = cost + TARGET_PROFIT * SHARES
if value >= target:
close_all()
Đây là phiên bản tối giản. Nó không giả vờ đã giải quyết được vấn đề dự đoán bóng đá, cũng không tuyên bố có thể arbitrage ổn định. Nó chỉ cố gắng nghiên cứu vùng xám giữa "arbitrage" và "dự đoán".
Vẻ đẹp của arbitrage nằm ở tính chắc chắn, nhưng tính chắc chắn rất hiếm. Sự hấp dẫn của dự đoán nằm ở khoảng không rộng lớn, nhưng tính ngẫu nhiên cũng lớn. Chiến lược này làm gì? Nó lấy giá dự đoán mà thị trường đưa ra làm nguyên liệu, sử dụng một nhận định chính có xác suất cao, kết hợp với hai đường bảo vệ có xác suất thấp, sau đó dùng mô hình Poisson để lọc thô một lớp, cố gắng xây dựng một cửa sổ có thể hội tụ sớm trong quá trình trận đấu.
Rủi ro phải được nói rõ. Danh mục này không phải là sự kiện hoàn chỉnh, không phải arbitrage phi rủi ro. Nó phù hợp với những trận đấu có chênh lệch sức mạnh lớn, đường chính đủ rõ ràng, giá của đường bảo vệ đủ thấp. Nếu trận đấu cân bằng 50-50, hoặc chân bảo vệ đã quá đắt, thì ép làm không có ý nghĩa. Rắc rối hơn là, nó không bao phủ tất cả các đường bất lợi, chẳng hạn như 1:1, 0:2, 2:2, đều có thể khiến danh mục thua lỗ rõ rệt. Vì vậy, phải đặt giới hạn vị thế, thua lỗ tối đa, quy tắc cắt lỗ, không thể vì "trông giống arbitrage" mà coi nó như arbitrage.
Mô hình Poisson cũng không phải phép màu. Nó chỉ là một nền tảng toán học rất đơn giản, giúp chúng ta từ "tôi cảm thấy mức giá này khá tốt" tiến thêm một bước thành "ít nhất đã kiểm tra mức giá này bằng một mô hình minh bạch". Nó sẽ sai, thị trường cũng sẽ sai, bản thân chúng ta càng sai nhiều hơn. Phần trung thực nhất trong giao dịch, có lẽ là thừa nhận tất cả những điều này đều có thể sai, và cố gắng để sai lầm không lật tung cả bàn cùng một lúc.
Lần thử nghiệm này rất nông. Nó giống như đang đặt một câu hỏi: Khi cơ hội arbitrage thuần túy ngày càng ít, và dự đoán thuần túy quá khó, liệu chúng ta có thể tận dụng xác suất mà thị trường đã đưa ra để xây dựng những giao dịch có cấu trúc hơn không? Không phải ảo tưởng loại bỏ rủi ro, mà là tách rủi ro ra, nhìn rõ nó đến từ những con đường nào.
Có lẽ đây không phải là câu trả lời, nhưng nó là một cái hố nhỏ đáng để tiếp tục đào. Dự đoán chịu trách nhiệm cho chúng ta biết con đường chính nào có thể rộng hơn, tư duy arbitrage nhắc nhở chúng ta không chỉ nhìn hướng mà còn phải nhìn cấu trúc danh mục. Giữa hai điều này, có lẽ còn rất nhiều không gian để khám phá.
Mã nguồn chiến lược: Chiến lược hội tụ đường bóng đá Polymarket
- 1




