Laoma Predictor v0.5 - Technical Documentation
Based on Chinese Sports Lottery official odds analysis. Converts decimal odds to implied probabilities, removes overround (bookmaker margin), and generates score predictions.
# Chinese Sports Lottery Official API
GET https://webapi.sporttery.cn/gateway/jc/football/getMatchCalculatorV1.qry
# Parameters
poolCode=HAD,HHAD,CRS,TTG,HAFU
# Response fields:
- matchInfoList[].subMatchList[]
- matchNumStr: "周一001"
- leagueAbbName: "芬超"
- homeTeamAbbName / awayTeamAbbName
- had.h/d/a: Home/Draw/Away odds (decimal)
- crs: Correct Score odds (all score combinations)
def decimal_to_implied_probability(decimal_odds):
"""Convert decimal odds to implied probability"""
if decimal_odds is None or decimal_odds <= 1:
return 0
return 1 / decimal_odds
# Example: odds 2.24 → probability 44.6%
def remove_overround(probabilities):
"""Normalize probabilities to remove bookmaker margin"""
total = sum(probabilities.values())
return {k: v / total for k, v in probabilities.items()}
# Example: Home 44.6% + Draw 29.9% + Away 38.5% = 113%
# After normalization: Home 39.5% + Draw 26.4% + Away 34.1% = 100%
# Parse correct score odds from API
# Format: s01s02 → 1-2 (home 1, away 2)
for key, value in crs.items():
if key.startswith("s") and "s" in key[1:]:
parts = key[1:].split("s")
home_goals = int(parts[0])
away_goals = int(parts[1])
score = f"{home_goals}-{away_goals}"
# Convert odds to probability
prob = decimal_to_implied_probability(float(value))
score_probs[score] = prob
# Remove overround and sort
score_probs = remove_overround(score_probs)
sorted_scores = sorted(score_probs.items(), key=lambda x: x[1], reverse=True)
top5 = sorted_scores[:5]
File: laoma_v05.py
#!/usr/bin/env python3
"""
老马足彩算法 v0.5 — 基于体彩赔率分析
输入:体彩赔率数据(独赢+比分赔率)
输出:5个比分预测 + 概率 + 推理链
"""
import json
import math
def decimal_to_implied_probability(decimal_odds):
"""欧赔转隐含概率"""
if decimal_odds is None or decimal_odds <= 1:
return 0
return 1 / decimal_odds
def remove_overround(probabilities):
"""去除抽水,归一化概率"""
total = sum(probabilities.values())
if total == 0:
return probabilities
return {k: v / total for k, v in probabilities.items()}
def predict_from_odds(match_data):
"""
基于体彩赔率生成预测
match_data格式:
{
"home_team": "赫尔火花",
"away_team": "坦山猫",
"odds_h": 2.24, # 主胜赔率
"odds_d": 3.35, # 平局赔率
"odds_a": 2.60, # 客胜赔率
"odds_crs": { # 比分赔率(体彩格式)
"s00s00": "18.00", # 0-0
"s01s00": "11.00", # 1-0
"s00s01": "12.00", # 0-1
...
}
}
"""
home = match_data.get("home_team", "主队")
away = match_data.get("away_team", "客队")
odds_h = match_data.get("odds_h")
odds_d = match_data.get("odds_d")
odds_a = match_data.get("odds_a")
crs = match_data.get("odds_crs", {})
# 1. 分析独赢赔率
if odds_h and odds_d and odds_a:
prob_h = decimal_to_implied_probability(odds_h)
prob_d = decimal_to_implied_probability(odds_d)
prob_a = decimal_to_implied_probability(odds_a)
# 去除抽水
total = prob_h + prob_d + prob_a
prob_h_norm = prob_h / total
prob_d_norm = prob_d / total
prob_a_norm = prob_a / total
result_1x2 = {
"home_win": round(prob_h_norm * 100, 1),
"draw": round(prob_d_norm * 100, 1),
"away_win": round(prob_a_norm * 100, 1)
}
else:
result_1x2 = {"home_win": 33.3, "draw": 33.3, "away_win": 33.4}
# 2. 分析比分赔率
score_probs = {}
if crs:
for key, value in crs.items():
# 解析比分:s01s02 -> 1-2
if key.startswith("s") and "s" in key[1:]:
try:
parts = key[1:].split("s")
home_goals = int(parts[0])
away_goals = int(parts[1])
score = f"{home_goals}-{away_goals}"
if isinstance(value, str):
decimal_odds = float(value)
else:
decimal_odds = value
prob = decimal_to_implied_probability(decimal_odds)
score_probs[score] = prob
except:
pass
# 去除抽水
if score_probs:
score_probs = remove_overround(score_probs)
score_probs_pct = {k: round(v * 100, 1) for k, v in score_probs.items()}
# 排序取前5
sorted_scores = sorted(score_probs_pct.items(), key=lambda x: x[1], reverse=True)
top5 = sorted_scores[:5]
predictions = [
{"score": score, "probability": prob}
for score, prob in top5
]
else:
predictions = _fallback_predictions(result_1x2)
else:
predictions = _fallback_predictions(result_1x2)
# 3. 生成推理链
reasoning = _generate_reasoning(home, away, result_1x2, predictions)
return {
"agent": "老马v0.5",
"match": f"{home} vs {away}",
"result_1x2": result_1x2,
"predictions": predictions,
"reasoning": reasoning
}
def _fallback_predictions(result_1x2):
"""如果没有比分赔率,基于独赢赔率生成默认预测"""
home_prob = result_1x2["home_win"]
away_prob = result_1x2["away_win"]
if home_prob > 50:
return [
{"score": "2-0", "probability": 25},
{"score": "2-1", "probability": 20},
{"score": "1-0", "probability": 18},
{"score": "3-1", "probability": 12},
{"score": "3-0", "probability": 10}
]
elif away_prob > 50:
return [
{"score": "0-2", "probability": 25},
{"score": "1-2", "probability": 20},
{"score": "0-1", "probability": 18},
{"score": "1-3", "probability": 12},
{"score": "0-3", "probability": 10}
]
else:
return [
{"score": "1-1", "probability": 22},
{"score": "1-0", "probability": 18},
{"score": "0-1", "probability": 18},
{"score": "2-1", "probability": 15},
{"score": "1-2", "probability": 15}
]
def _generate_reasoning(home, away, result_1x2, predictions):
"""生成推理链"""
home_prob = result_1x2["home_win"]
draw_prob = result_1x2["draw"]
away_prob = result_1x2["away_win"]
if home_prob > 50:
advantage = f"{home}明显占优(胜率{home_prob}%)"
elif away_prob > 50:
advantage = f"{away}明显占优(胜率{away_prob}%)"
elif home_prob > away_prob:
advantage = f"{home}略占优势({home_prob}% vs {away_prob}%)"
elif away_prob > home_prob:
advantage = f"{away}略占优势({away_prob}% vs {home_prob}%)"
else:
advantage = "双方势均力敌"
top_score = predictions[0]["score"] if predictions else "未知"
top_prob = predictions[0]["probability"] if predictions else 0
reasoning = f"""基于体彩赔率分析:
1. 独赢概率:{home}胜{home_prob}% | 平局{draw_prob}% | {away}胜{away_prob}%
2. {advantage}
3. 最可能比分:{top_score}(概率{top_prob}%)
4. 推荐投注:前3个比分覆盖率高,建议4串2容错
注意:赔率已去除抽水,概率已归一化。实际投注请结合近期战绩和伤停信息。"""
return reasoning
# Get all matches
curl https://predict.houyuanbar.com/api/matches
# Response:
{
"matches": [
{
"id": 1,
"match_num": "周一001",
"league": "芬超",
"home_team": "赫尔火花",
"away_team": "坦山猫",
"odds_h": 2.24,
"odds_d": 3.35,
"odds_a": 2.60
}
]
}
# Generate prediction (Laoma v0.5 + GPT prompt)
curl -X POST https://predict.houyuanbar.com/api/predict/1
# Response:
{
"success": true,
"laoma": {
"agent": "老马v0.5",
"predictions": [
{"score": "1-1", "probability": 19.2},
{"score": "2-1", "probability": 16.8}
],
"reasoning": "..."
},
"gpt_prompt": "..."
}