pnclFEED Chave gratuita

Notas de quickstart

Salve preços da API de odds da Pinnacle em CSV com Python

Estenda o loop de polling em Python: grave uma linha CSV por mudança de preço, deduplique contra o último valor e fique dentro da cota diária gratuita.

O quickstart de Python deste site faz polling na API de odds da Pinnacle e imprime a linha money line. A próxima pergunta que a maioria dos leitores faz é como guardar o que buscou. Um arquivo CSV basta para um primeiro armazenamento: uma linha por seleção por mudança, anexada a cada poll, legível pelo Excel, pandas ou uma importação de banco de dados depois.

O que uma linha deve conter

Guarde a observação, não só o preço. Uma linha útil nomeia o evento (id, liga, times), as coordenadas do mercado (período, mercado, lado) e a própria observação: o preço decimal e a hora em que você o viu. Some o cursor last da resposta se quiser rastrear qual poll gravou a linha. Os preços chegam como odds decimais, então guarde-os exatamente como servidos e converta depois, se precisar de outro formato.

Escreva o timestamp em UTC e em um formato estrito. Um preço que você não consegue posicionar no tempo é difícil de comparar com um preço de fechamento depois, e fusos misturados corrompem uma semana de registros cuidadosos em uma tarde.

Anexe na mudança, não no poll

O cursor since já limita cada resposta aos eventos que mudaram, mas um evento alterado ainda contém muitas seleções sem mudança. Mantenha um pequeno dicionário do último preço gravado por seleção e escreva uma linha só quando o valor diferir. Sem essa regra, o arquivo cresce com a sua taxa de poll em vez do movimento do mercado, e um loop de dia inteiro grava centenas de linhas idênticas.

Um detalhe: o dicionário começa vazio após um reinício. Se você quer deduplicação limpa entre reinícios, alimente-o na inicialização lendo o arquivo e guardando a última linha de cada chave de seleção.

O loop, estendido

import csv, os, time, requests

BASE = os.environ["ODDS_BASE_URL"]
KEY = os.environ["ODDS_API_KEY"]
URL = BASE + "/kit/v1/markets"
s = requests.Session()
s.headers["x-portal-apikey"] = KEY

last_seen = {}   # (event_id, side) -> price
since = None

def rows(ev, seen_at):
    ml = ev.get("periods", {}).get("num_0", {}).get("money_line", {})
    for side in ("home", "draw", "away"):
        price = ml.get(side)
        if price is None:
            continue
        key = (ev["id"], side)
        if last_seen.get(key) != price:
            last_seen[key] = price
            yield [seen_at, ev["id"], ev.get("league_name", ""),
                   ev["home"], ev["away"], side, price]

with open("odds.csv", "a", newline="") as f:
    w = csv.writer(f)
    if f.tell() == 0:
        w.writerow(["observed_at", "event_id", "league", "home",
                    "away", "side", "price"])
    while True:
        q = {"sport_id": 2}
        if since is not None:
            q["since"] = since
        r = s.get(URL, params=q, timeout=10)
        if r.status_code == 429:
            time.sleep(int(r.headers.get("Retry-After", "5")))
            continue
        r.raise_for_status()
        data = r.json()
        since = data["last"]
        seen_at = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
        for ev in data["events"]:
            w.writerows(rows(ev, seen_at))
        f.flush()
        time.sleep(900)

A pausa de 900 segundos mantém o dia inteiro dentro das 100 chamadas da chave gratuita, o mesmo orçamento que o quickstart de Python usa para um teste de dia inteiro. O nível gratuito aparece como 20 chamadas por minuto e 100 por dia na página de preços, verificado em 2026-09-29. Num plano pago, o mesmo script roda sem mudanças com uma pausa menor.

Onde isso para

CSV é um bom primeiro armazenamento e um mau armazenamento de longo prazo. Não tem transações, não tem deduplicação entre reinícios a menos que você recarregue os últimos preços do arquivo, e não tem compressão. Quando o arquivo passar de algumas centenas de milhares de linhas, ou quando mais de um processo precisar lê-lo, mova a mesma lógica de mudança para uma tabela. Até lá, um arquivo simples que você abre numa planilha é o jeito mais rápido de ver o seu próprio polling funcionando.