On the wire · 05:08:46 UTC Live 585 · Prematch 14,345 · Markets 57,038 Vol. I · No. 5 · Friday 13 November 2026 wss://pinnfeed.io/v1/stream
PinnFeed
Tutorial · Data · DuckDB

Pinnacle-Closing-Quoten in DuckDB und Parquet

Aktualisiert am · PinnFeed · 1 Min. Lesezeit

Antwort: auf Builder oder Pro führen Sie einen kleinen Tagesjob aus, der GET /v1/closing?date=YYYY-MM-DD paginiert (bis 2.000 Zeilen pro Aufruf), market und outcomes flacht und eine Parquet-Datei pro Tag schreibt. DuckDB fragt den Ordner danach mit SQL ab — ohne Datenbankserver. Datensätze existieren ab dem Start der Closing-Speicherung.

1. Daily export (Python)#

import os, sys, requests, pandas as pd
H = {"x-api-key": os.environ["PINNFEED_KEY"]}  # ps_live_...

def closing_day(day, sport):
    rows, offset = [], 0
    while True:
        r = requests.get("https://pinnfeed.io/v1/closing", headers=H, timeout=30,
                         params={"date": day, "sport": sport, "limit": 2000, "offset": offset})
        r.raise_for_status()                     # 403 plan_lacks_history on Free/Hobby
        batch = r.json()["closing"]
        rows += batch
        if len(batch) < 2000:
            return rows
        offset += 2000

day = sys.argv[1]                                # e.g. 2026-11-08
out = []
for row in closing_day(day, "soccer"):
    m = row["market"]
    for o in m["outcomes"] or []:
        out.append({
            "event_id": row["eventId"], "league": row["league"]["name"], "home": row["home"], "away": row["away"],
            "start_time": row["startTime"], "captured_at": row["capturedAt"],
            "market": m["type"], "period": m["period"], "line": m["line"], "main": m["main"],
            "margin": m["margin"], "max_stake": m["maxStake"],
            "outcome": o.get("name"), "decimal": o.get("decimal"), "fair": o.get("fair"),
        })
os.makedirs("closing", exist_ok=True)
pd.DataFrame(out).to_parquet(f"closing/soccer-{day}.parquet", index=False)   # needs pyarrow
print(len(out), "outcome rows")

2. Query with DuckDB#

-- duckdb shell, from the folder that contains closing/
SELECT league, avg(margin) AS avg_margin
FROM read_parquet('closing/*.parquet')
GROUP BY 1
ORDER BY 2 DESC
LIMIT 20;

CTA#

Builder (99 €/Monat). 3 Tage Testphase; Karte erforderlich. REST gratis: Signup. Related: closing/CLV, backtesting.

Häufige Fragen#

Reicht Free/Hobby?#

Nein — /v1/closing liefert 403 plan_lacks_history außerhalb Builder/Pro.

Bildungsinhalt für Erwachsene?#

Ja (18+).

Bildungsinhalt für Erwachsene (18+). Keine Tipps, kein Gewinnversprechen. In Deutschland nur bei Anbietern auf der GGL-Whitelist wetten.

Der WebSocket-Plan: Builder, 99 €/Monat.

Pinnacle-Quoten in Echtzeit über einen einzigen WebSocket: alle 13 Sportarten, alle Märkte, faire Quoten ohne Marge und Schlussquoten. 3 Tage kostenlos, mit einem Klick kündbar.

Form K-1 · Free API key

Get your free API key.

One field. No password, no card: enter your email, click the link we send, and your key is on screen.

By continuing you agree to the Terms and Privacy Policy.

One free key per email. Link valid for 20 minutes.