Cotes Pinnacle dans un DataFrame pandas
Réponse : appelez GET /v1/odds puis parcourez événements → marchés → issues pour construire une ligne par issue. Vous obtenez un DataFrame propre avec decimal, fair, fairProb, margin et maxStake pour chaque prix, prêt pour groupby, Parquet ou un notebook. Fonctionne sur tous les plans ; sur Free, les données ont 30 secondes de retard.
Code#
# pip install requests pandas
import os, requests, pandas as pd
r = requests.get(
"https://pinnfeed.io/v1/odds",
headers={"x-api-key": os.environ["PINNFEED_KEY"]}, # ps_live_...
params={"sport": "soccer", "main": "true", "limit": 200},
timeout=20,
)
r.raise_for_status()
rows = []
for ev in r.json()["events"]:
for m in ev.get("markets", []):
for o in m.get("outcomes", []):
rows.append({
"event_id": ev["id"], "start": ev.get("startTime"), "live": ev.get("live"),
"league": (ev.get("league") or {}).get("name"),
"home": ev.get("home"), "away": ev.get("away"),
"market": m.get("type"), "period": m.get("period"), "line": m.get("line"),
"margin": m.get("margin"), "max_stake": m.get("maxStake"),
"outcome": o.get("name"), "decimal": o.get("decimal"),
"fair": o.get("fair"), "fair_prob": o.get("fairProb"),
})
df = pd.DataFrame(rows)
df["start"] = pd.to_datetime(df["start"], utc=True)
print(df.groupby("market")["margin"].describe())
df.to_csv("pinnacle_soccer.csv", index=False)
Étapes suivantes#
- Marchés avec volume :
df[df.max_stake >= 100]. - Plus de 200 événements : paginez avec
offset(doc REST). - Cotes de clôture pour le CLV sur Builder :
/v1/closing/{id}. - Changements en direct sans polling : client WebSocket.
Offres#
Free (0 €) : 30 s de retard, 2 sports, marchés principaux, 1 000 requêtes par jour. Hobby (29 €/mois) : REST en temps réel. Builder (99 €/mois) : WebSocket, tous les marchés et historique des clôtures. Essai de 3 jours ; carte requise, débitée après le jour 3 sauf résiliation.
Contenu éducatif pour adultes (18+) : ni pronostics ni promesse de gain. En France, seuls les opérateurs agréés par l'ANJ peuvent proposer des paris en ligne.
Questions fréquentes#
Pourquoi une ligne par issue ?#
Chaque prix tient dans une colonne, ce qui simplifie filtres, pivots et jointures. Une ligne par marché : df.pivot_table(index=["event_id","market","line"], columns="outcome", values="decimal").
Cela marche-t-il dans Jupyter ou Colab ?#
Oui. Définissez la clé avec os.environ["PINNFEED_KEY"] = "ps_live_..." dans une cellule que vous ne partagez pas.
Existe-t-il une version polars ?#
Passez la même liste rows à polars.DataFrame(rows).