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.
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.
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))
Select the code to copy it.
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.
- Message @BotFather in Telegram, create a bot and copy its token.
- Send your bot any message, then read your chat ID from the bot's
getUpdatespage. - Export the four variables below and run the script on a machine that stays on.
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_dropto 8 or 10 for a quieter chat. The floor is 1. - Only valueCompare each alert's
nvpwith 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.
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