pnclDATA Free key

pinnacle dropping odds / telegram bot / python

Pinnacle dropping odds in Telegram

A short Python script holds the Pinnacle odds API drop stream open and posts every alert to your Telegram chat: the line that moved, the price before and after, and the fair price. Your phone buzzes while the gap at other books is still open.

The drop stream comes with Drop alerts at $99 a month, Alerts + scanning and Full volume.

From the stream to your chat, using the documented example alert

what the stream sends

data: [{
  "home": "Sunshine Coast Phoenix",
  "away": "Cairns Dolphins",
  "league": "Australia - NBL1 Women",
  "sport": "Basketball",
  "sect": "Moneyline",
  "outcome": "Home",
  "from_price": 2.86,
  "to_price": 2.7,
  "nvp": 3.04,
  ...
}]

what your chat shows

Sunshine Coast Phoenix v Cairns Dolphins

Moneyline Home

2.86 -> 2.7 (-5.59%)

fair 3.04

Soccer, tennis and basketball, 5% drops and bigger: both are settings at the top of the script.

bot.py
import json
import os
import requests

BASE = os.environ["ODDS_BASE_URL"]
KEY = os.environ["ODDS_API_KEY"]
BOT = os.environ["TG_BOT_TOKEN"]
CHAT = os.environ["TG_CHAT_ID"]
SPORTS = {"Soccer", "Tennis",
          "Basketball"}
SEND = ("https://api.telegram.org/bot"
        + BOT + "/sendMessage")


def send(text):
    requests.post(SEND,
                  data={"chat_id": CHAT,
                        "text": text},
                  timeout=10)


def line(a):
    was = a["from_price"]
    now = a["to_price"]
    pct = 100 * (was - now) / was
    return "\n".join([
        f"{a['home']} v {a['away']}",
        f"{a['sect']} {a['outcome']}",
        f"{was} -> {now} (-{pct:.2f}%)",
        f"fair {a['nvp']}",
    ])


r = requests.get(
    BASE + "/odds-drop",
    params={"min_drop": 5, "key": KEY},
    stream=True,
    timeout=(10, None),
)
r.raise_for_status()

for raw in r.iter_lines():
    if not raw.startswith(b"data:"):
        continue
    msg = json.loads(raw[5:])
    if isinstance(msg, dict):
        continue  # connected or error
    for a in msg:
        if a["sport"] in SPORTS:
            send(line(a))

The whole bot

It opens one request to the live drop stream with your threshold, reads each data: line and skips control messages such as the connection greeting. Every alert in the sports you listed becomes a four-line message; the drop size is worked out from the two prices, because the stream sends the prices rather than the percentage.

The stream has no sport filter of its own, which is why the script checks sport. For prematch drops, point a second copy at /odds-drop-prematch: live and prematch each get their own connection.

  1. Message @BotFather in Telegram, create a bot and copy its token.
  2. Send your bot any message, then read your chat ID from the bot's getUpdates page.
  3. Export the four variables below and run the script on a machine that stays on.
terminal
pip install requests
export ODDS_API_KEY="your key"
export ODDS_BASE_URL="https://..."
export TG_BOT_TOKEN="from BotFather"
export TG_CHAT_ID="your chat id"
python bot.py
  • Fewer, bigger dropsRaise min_drop to 8 or 10 for a quieter chat. The floor is 1.
  • Only valueCompare each alert's nvp with your bookmaker's price before sending, and post only the ones above fair.
  • Stay connectedWrap the request in a loop that reconnects after a network error, waiting longer after each failure; drops during the gap are not replayed.

Three changes worth making

The script is deliberately small. These are the edits most people make in the first week.

Check a price against fair by hand

How thresholds and windows define a drop, on pnclPULSE

Running your own model? Take the raw frames instead

The alert stream is processed for you: one message per drop, with the fair price attached. If your code keeps its own market state, the raw WebSocket feed sends every raw frame instead and leaves the processing to you. It is a $99 per 30 days add-on on Alerts + scanning and Full volume, not a separate plan.

stream to bot.py to chat · fair 2.34 · drop 5.06%

The script is free; the stream it listens to comes with Drop alerts, Alerts + scanning and Full volume