dino-markets
Official Python client for the dino.markets API: related Kalshi and Polymarket prediction markets across sports, crypto, weather, and economics, plus confirmed cross-venue arbitrage and a real-time stream.
Zero runtime dependencies. Requires Python 3.9 or later.
Install
pip install dino-markets
Authentication
Create a key at dino.markets. The dashboard issues a Free-plan key immediately with no card required. Free includes one real-time sample connection; paid plans add the full market stream and higher limits.
Pass the key directly, or set it once in the environment:
export DINO_API_KEY=sk_live_...
from dino_markets import Dino
client = Dino() # reads DINO_API_KEY
client = Dino(api_key="sk_live_...") # or pass it explicitly
Quickstart
from dino_markets import Dino
client = Dino()
# The matched catalog, open and live markets by default
markets = client.markets(sport="baseball")
# A non-sports market family
crypto_thresholds = client.markets(market_type="crypto_above")
# Confirmed cross-venue arbitrage -- v0.2.0: a dedicated Opportunity envelope, not a
# filtered Market collection. Each opportunity carries its own exact selected legs.
arbs = client.find_arbitrage(sport="baseball", limit=20)
for opportunity in arbs["opportunities"]:
print(opportunity["title"], opportunity["roi_pct"], opportunity["fee_model"], opportunity["max_wager_usd"])
# One market by id, and its price history
market = client.market("dino_8f3a1c92-47e8-4c3f-b9d2-f1a8e6c4d5f2")
history = client.history("dino_8f3a1c92-47e8-4c3f-b9d2-f1a8e6c4d5f2")
# Sports and leagues currently in season
leagues = client.leagues()
# Flag an opportunity that looks wrong -- opp_id is the Opportunity's own id, not a market id
client.report_bad_arb(opp_id=arbs["opportunities"][0]["id"], reason="legs settle on different terms")
REST reads are priced roughly two minutes behind live on every plan. That delay is not a paywall. If you need the current price when it changes, use the WebSocket stream below.
Streaming
The WebSocket stream pushes market updates as they happen and needs the stream extra. Every active plan can mint a ticket. Free receives the curated sample channel; Basic, Premium, and Pro receive the full market stream.
pip install "dino-markets[stream]"
import asyncio
from dino_markets import Dino
from dino_markets.stream import watch
client = Dino()
def on_publication(channel, data):
print(channel, data)
def on_recovery_failed(channel):
bootstrap_from_rest(channel)
asyncio.run(watch(
client,
on_publication,
on_recovery_failed=on_recovery_failed,
))
The server reads your plan from the connect ticket and subscribes the connection to exactly the channels it grants. There is no client-side channel selection to configure. Treat the ticket response's allowed.channels and allowed.max_conns as the source of truth.
watch() mints one short-lived ticket per connection attempt, including automatic reconnects: it disconnects cleanly on cancellation, retries only transient reconnect-ticket failures, and surfaces a permanent authorization/plan change or stream-endpoint change without looping forever. Initial admission is fenced to about 15 seconds; the first successful plan-matching refresh then grants the normal 15-minute renewal. If the five-minute recovery history can't fill a reconnect gap, on_recovery_failed receives the channel that must be reloaded from REST.
Error handling
Every non-2xx response raises a subclass of DinoError, carrying the HTTP status and the parsed response body:
from dino_markets import Dino, AuthenticationError, PlanError, RateLimitError, ServerError
client = Dino()
try:
client.markets()
except AuthenticationError:
print("bad or revoked key")
except PlanError:
print("subscription inactive or plan not recognized")
except RateLimitError as e:
print("over the rate limit, retry after", e.retry_after, "seconds")
except ServerError:
print("dino.markets is having a bad moment, try again shortly")
A 429 or 5xx response is retried automatically, honoring a Retry-After header when the API sends one and backing off otherwise. A 400 or other client error is never retried. Tune this with Dino(max_retries=...).
Rate limits
REST requests are metered per key:
| Plan | Requests/month | Requests/sec | WebSocket |
|---|---|---|---|
| Free | 10,000 | 10 | Curated sample, 1 connection |
| Basic ($30/month) | 1,000,000 | 10 | Full market stream, 3 connections |
| Premium ($100/month) | 5,000,000 | 25 | Full market stream, 10 connections |
| Pro ($200/month) | 5,000,000 | 25 | Full stream plus raw quotes and early candidates, 10 connections |
Localized documentation
| Language | Docs | MCP server |
|---|---|---|
| 日本語 | Docs | MCP |
| 한국어 | Docs | MCP |
| 简体中文 | Docs | MCP |
| Español | Docs | MCP |
Support
Questions or a key that needs attention: support@dino.markets
Disclaimer
Informational data. Not investment advice. You trade on your own venue accounts at your own risk.
License
MIT, copyright Nusantara Ventures LLC. See LICENSE.
Metadata
Release files for dino-markets 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| dino_markets-0.2.0.tar.gz | 20.8 kB | Without provenance | Details for dino_markets-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| dino_markets-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for dino_markets-0.2.0-py3-none-any.whl |
Total release size: 35.6 kB
Release files / dino_markets-0.2.0.tar.gz
| Download URL | dino_markets-0.2.0.tar.gz |
|---|---|
| Size | 20.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d44e1a6d44b0ab1419e246f8eaa064dd082b6bdde3723aa5c764239ed3617c0d
|
|
BLAKE2b-256 checksum How to use checksums |
0934fcc9de77a14a0ce1db37060bdaf4f99fda220e8db7135f83cdbec86de9fc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|
Release files / dino_markets-0.2.0-py3-none-any.whl
| Download URL | dino_markets-0.2.0-py3-none-any.whl |
|---|---|
| Size | 14.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
441ec2172be8d5860329ec412fa25956af2300c3547620701690b13226ba5e34
|
|
BLAKE2b-256 checksum How to use checksums |
56ce247a11f6ba2109cb51892be747d3a798eadf046ed824e8b6f99cffdb79d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|
Security for dino-markets 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.