Track closing line value against Pinnacle's closing price
Closing line value (CLV) compares the price you took with the market's final price before kickoff. If you consistently beat Pinnacle's closing fair price, you are very likely a winning bettor, long before your profit and loss can prove it. PinnFeed records the closing Pinnacle price of every market when an event starts and serves it from /v1/closing.
Step 1 — Know the formula#
CLV = price_taken / closing_fair_price − 1
Use the no-vig closing price, not the raw one: beating a price that still contains Pinnacle's margin is easier and overstates your edge. If you took 2.10 and the market closed at a fair 1.95, your CLV is +7.7%.
Step 2 — Log each bet#
Every bet needs the event id, the market key and the outcome. You get all three from the API: the event id, the market key (s;0;m is the full-game moneyline, s;0;ou;2.5 the full-game total 2.5) and the outcome name (home, away, draw, over, under).
Step 3 — Run the tracker#
Install requests, save the script as clv.py, and log bets as you place them:
# clv.py: log your bets and measure closing line value (CLV) against Pinnacle's no-vig close.
# pip install requests Usage:
# python clv.py bet <event_id> <market_key> <outcome> <price> e.g. bet 1640141281 "s;0;m" home 2.10
# python clv.py report
import os, sqlite3, sys, requests
BASE = os.environ.get("PINNFEED_BASE", "https://pinnfeed.io")
KEY = os.environ["PINNFEED_KEY"]
db = sqlite3.connect(os.environ.get("CLV_DB", "bets.db"))
db.execute("CREATE TABLE IF NOT EXISTS bets (event_id INTEGER, market_key TEXT, outcome TEXT, price REAL, "
"close_fair REAL, placed_at TEXT DEFAULT CURRENT_TIMESTAMP)")
def closing_fair(event_id, market_key, outcome):
r = requests.get(f"{BASE}/v1/closing/{event_id}", headers={"x-api-key": KEY}, timeout=20)
if r.status_code == 404:
return None # not closed yet (or never captured)
r.raise_for_status()
for rec in r.json()["markets"]:
if rec["market"]["key"] == market_key:
for o in rec["market"]["outcomes"]:
if o["name"] == outcome:
return o["fair"]
return None
if sys.argv[1:2] == ["bet"]:
_, _, event_id, market_key, outcome, price = sys.argv
db.execute("INSERT INTO bets (event_id, market_key, outcome, price) VALUES (?,?,?,?)",
(int(event_id), market_key, outcome, float(price)))
db.commit()
print("logged")
else:
rows = db.execute("SELECT rowid, event_id, market_key, outcome, price, close_fair FROM bets").fetchall()
clvs = []
for rowid, event_id, key, outcome, price, close in rows:
if close is None:
close = closing_fair(event_id, key, outcome)
if close:
db.execute("UPDATE bets SET close_fair=? WHERE rowid=?", (close, rowid))
if close:
clv = price / close - 1
clvs.append(clv)
print(f"{event_id} {key} {outcome}: took {price}, closed fair {close:.3f} -> CLV {clv:+.2%}")
else:
print(f"{event_id} {key} {outcome}: took {price}, waiting for close")
db.commit()
if clvs:
print(f"average CLV over {len(clvs)} bets: {sum(clvs) / len(clvs):+.2%}")
python clv.py bet 1640229582 "s;0;m" home 2.10
python clv.py report
1640229582 s;0;m home: took 2.1, closed fair 3.181 -> CLV -33.99%
999 s;0;m home: took 1.9, waiting for close
average CLV over 1 bets: -33.99%
Run report from cron after kickoffs; each bet's closing price is fetched once and stored.
Step 4 — Read the result#
- Over a few hundred bets, an average CLV of +2% or more is a strong sign of a real edge.
- Negative CLV with positive profit usually means luck. Expect it to fade.
- Split CLV by sport, market and how early you bet: it shows where your edge actually comes from.
Step 5 — Pull a whole day#
For research or backtests, fetch every closing line for a UTC day:
curl -H "x-api-key: $PINNFEED_KEY" "https://pinnfeed.io/v1/closing?date=2026-11-08&sport=soccer&main=true"
Questions people ask#
Which plan includes closing odds?#
Closing-line history is included from Builder (€99/month) and on Pro and Enterprise.
When is the closing price captured?#
When the event starts: the last prematch price of each market is stored with a capture timestamp.
How far back does the archive go?#
It starts on the day the service launched and grows every day. Enterprise plans can export it in bulk as CSV or Parquet.