Find a market and check its tape
Search Polymarket markets by slug, take the first hit's condition and token ids, and ask whether that outcome token has a recorded tape.
Almost every Polymarket route needs an id that only /markets hands out.
This recipe searches by slug, then carries the ids through the two routes that use them:
/markets/{condition_id} takes the condition_id, and
/market_stats takes a token_id.
export VIKE_API_KEY=...
python pm-find-market.py # real run: needs the key
python pm-find-market.py --dry-run # prints the requests it would make, calls nothingIt prints the three latest-ending markets whose slug contains bitcoin, the first one's tick size and token
count, and that token's event and trade counts with the span of the recorded tape.
"""Search Polymarket markets by slug, then check whether the first hit's outcome token has a recorded tape.
Run: VIKE_API_KEY=... python pm-find-market.py (--dry-run lists the requests and makes none)
"""
import os
import sys
from datetime import datetime, timezone
from urllib.parse import urlencode
NAME = "pm-find-market"
BASE = "https://data.vike.io"
DRY = "--dry-run" in sys.argv
def fail(why):
sys.exit(f"{NAME}: {why}")
def call(path, method="GET", **params):
url = BASE + path + ("?" + urlencode(params) if params else "")
if DRY:
print(method, url)
return None
key = os.environ.get("VIKE_API_KEY") or fail("set VIKE_API_KEY")
import requests
r = requests.request(method, url, headers={"X-API-Key": key}, timeout=60)
if r.status_code != 200:
fail(f"{method} {path} answered HTTP {r.status_code}: {r.text[:200]}")
return r.json()
def when(ms):
return datetime.fromtimestamp(ms / 1000, timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
def main():
# A bare array, latest end_date first. Every other Polymarket route wants an id only this one hands out.
hits = call("/v1/polymarket/markets", query="bitcoin", limit=3)
cid = "0x7b9072e6a9cdcf022c4f098564e8ee612d544e179e4a33dcc2790fbaa778daa8" # --dry-run has no response to read
if not DRY:
if not hits:
fail("no market slug contains 'bitcoin'")
for m in hits:
print(f"{m['slug']} closed={m['closed']} ends {when(m['end_date'])}")
cid = hits[0]["condition_id"]
# A one-element array, not an object; an unknown id is [] with a 200, so test the length.
detail = call(f"/v1/polymarket/markets/{cid}")
token = "95532524407959903145510583684979049735028502452973932716346555811355282494630"
if not DRY:
if not detail:
fail(f"{cid} is not in the directory")
token = detail[0]["token_ids"][0]
print(f"condition_id {cid} tick_size {detail[0]['tick_size']} tokens {len(detail[0]['token_ids'])}")
# One row always comes back; total_events == 0 is how "never recorded" reads.
stats = call("/v1/polymarket/market_stats", token_id=token)
if DRY:
return
s = stats[0]
if s["total_events"] == 0:
print(f"token {token[:12]}...: no recorded tape")
else:
print(f"token {token[:12]}...: {s['total_events']} events, {s['trades']} trades, tape {when(s['first_ms'])} to {when(s['last_ms'])}")
if __name__ == "__main__":
try:
main()
except Exception as e: # a shape the recipe does not expect fails by name, not by traceback
fail(f"{type(e).__name__}: {e}")Read it this way
- Search is a case-insensitive substring match on the slug. Results come back latest
end_datefirst, with a cap of 100 rows and no cursor: to reach further, narrow the slug rather than page. - Detail is a one-element array. An unknown
condition_idis[]with a200, not a404, so the script tests the length. Atoken_idin that path also returns[]. market_statsalways returns one row. A token that was never recorded reads astotal_events: 0, which the script prints as "no recorded tape".
last_ms is where the recording ends, not now
The span the script prints is the range /events can serve for that token.
A request aimed at the current hour for a token whose tape ended weeks ago returns nothing, while a request
inside the span returns plenty. Read the span before asking for the tape.
Count liquidations around the biggest move
Find the largest BTC hourly candle of a day, then total the long and short liquidations that landed inside that hour.
Follow the profitable cohort
See where the wallets with a record of realized profit put money in the last day, which of those markets they also bought below the mid, and whether the top market is still open.