104 lines
2.7 KiB
Python
104 lines
2.7 KiB
Python
|
|
"""
|
||
|
|
Fetch sports odds from The Odds API and save JSON snapshots.
|
||
|
|
|
||
|
|
Requires ODDS_API_KEY in environment or .env (see project .env.example).
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
python odds/scripts/fetch_odds.py --sport boxing_boxing --out odds/data/samples/boxing_odds.json
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
try:
|
||
|
|
import requests
|
||
|
|
except ImportError:
|
||
|
|
print("Install dependencies: pip install -r requirements.txt", file=sys.stderr)
|
||
|
|
raise
|
||
|
|
|
||
|
|
API_BASE = "https://api.the-odds-api.com/v4"
|
||
|
|
DEFAULT_SPORT = "boxing_boxing"
|
||
|
|
DEFAULT_REGIONS = "uk,eu"
|
||
|
|
DEFAULT_MARKETS = "h2h"
|
||
|
|
|
||
|
|
|
||
|
|
def get_api_key() -> str:
|
||
|
|
"""Read API key from ODDS_API_KEY environment variable."""
|
||
|
|
key = os.environ.get("ODDS_API_KEY", "").strip()
|
||
|
|
if not key:
|
||
|
|
raise SystemExit(
|
||
|
|
"Missing ODDS_API_KEY. Copy .env.example to .env and set your key."
|
||
|
|
)
|
||
|
|
return key
|
||
|
|
|
||
|
|
|
||
|
|
def fetch_odds(
|
||
|
|
sport: str,
|
||
|
|
regions: str,
|
||
|
|
markets: str,
|
||
|
|
api_key: str,
|
||
|
|
) -> list[dict]:
|
||
|
|
"""
|
||
|
|
GET odds for a sport from The Odds API.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
sport: Sport key (e.g. boxing_boxing).
|
||
|
|
regions: Comma-separated region codes.
|
||
|
|
markets: Comma-separated market keys.
|
||
|
|
api_key: The Odds API key.
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
Parsed JSON list of events.
|
||
|
|
|
||
|
|
Raises:
|
||
|
|
requests.HTTPError: On non-2xx response.
|
||
|
|
"""
|
||
|
|
url = f"{API_BASE}/sports/{sport}/odds"
|
||
|
|
params = {
|
||
|
|
"apiKey": api_key,
|
||
|
|
"regions": regions,
|
||
|
|
"markets": markets,
|
||
|
|
"oddsFormat": "decimal",
|
||
|
|
}
|
||
|
|
response = requests.get(url, params=params, timeout=60)
|
||
|
|
response.raise_for_status()
|
||
|
|
return response.json()
|
||
|
|
|
||
|
|
|
||
|
|
def save_odds(data: list[dict], output_path: Path) -> None:
|
||
|
|
"""Write odds JSON to disk with stable formatting."""
|
||
|
|
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||
|
|
with output_path.open("w", encoding="utf-8") as f:
|
||
|
|
json.dump(data, f, indent=4, ensure_ascii=False)
|
||
|
|
print(f"Saved {len(data)} events to {output_path}")
|
||
|
|
|
||
|
|
|
||
|
|
def parse_args() -> argparse.Namespace:
|
||
|
|
parser = argparse.ArgumentParser(description="Fetch odds from The Odds API")
|
||
|
|
parser.add_argument("--sport", default=DEFAULT_SPORT, help="Sport key")
|
||
|
|
parser.add_argument("--regions", default=DEFAULT_REGIONS, help="Region codes")
|
||
|
|
parser.add_argument("--markets", default=DEFAULT_MARKETS, help="Market keys")
|
||
|
|
parser.add_argument(
|
||
|
|
"--out",
|
||
|
|
type=Path,
|
||
|
|
default=Path("odds/data/samples/boxing_odds.json"),
|
||
|
|
help="Output JSON path",
|
||
|
|
)
|
||
|
|
return parser.parse_args()
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
args = parse_args()
|
||
|
|
api_key = get_api_key()
|
||
|
|
data = fetch_odds(args.sport, args.regions, args.markets, api_key)
|
||
|
|
save_odds(data, args.out)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|