Metadata-Version: 2.4
Name: dino-markets
Version: 0.1.0
Summary: Official Python SDK for the dino.markets API: matched cross-venue prediction market data and real-time arbitrage signal.
Project-URL: Homepage, https://dino.markets
Project-URL: Documentation, https://dino.markets/docs
Project-URL: Repository, https://github.com/nusantara-ventures/dino-markets-python
Author-email: Nusantara Ventures LLC <support@dino.markets>
License: MIT
License-File: LICENSE
Keywords: api,arbitrage,kalshi,polymarket,prediction markets,sports
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Provides-Extra: stream
Requires-Dist: centrifuge-python; extra == 'stream'
Description-Content-Type: text/markdown

# dino-markets

Official Python client for the [dino.markets](https://dino.markets) API: a matched catalog of Kalshi and Polymarket sports markets, plus a real-time signal for when the same outcome is priced apart across venues.

Zero runtime dependencies. Requires Python 3.9 or later.

## Install

```bash
pip install dino-markets
```

## Authentication

Create a key at [dino.markets](https://dino.markets). The dashboard issues a free-tier key immediately with no card required; upgrade later for the WebSocket stream and a higher rate limit.

Pass the key directly, or set it once in the environment:

```bash
export DINO_API_KEY=sk_live_...
```

```python
from dino_markets import Dino

client = Dino()                       # reads DINO_API_KEY
client = Dino(api_key="sk_live_...")  # or pass it explicitly
```

## Quickstart

```python
from dino_markets import Dino

client = Dino()

# The matched catalog, open and live markets by default
markets = client.markets(sport="baseball")

# Confirmed cross-venue arbitrage
arbs = client.find_arbitrage(sport="baseball", limit=20)
for m in arbs["markets"]:
    print(m["title"], m["potential_arb_pct"])

# 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
client.report_bad_arb(opp_id=market["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; it is the same policy for Free, Basic, and Pro. If you need the current price the instant it changes, use the WebSocket stream below.

## Streaming

The WebSocket stream pushes each market's price the moment it changes. It needs the `stream` extra and a Basic or Pro plan; a Free key gets a `PlanError` back from `stream_token()` before any socket opens.

```bash
pip install "dino-markets[stream]"
```

```python
import asyncio
from dino_markets import Dino
from dino_markets.stream import watch

client = Dino()

def on_publication(channel, data):
    print(channel, data)

asyncio.run(watch(client, on_publication))
```

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.

## Error handling

Every non-2xx response raises a subclass of `DinoError`, carrying the HTTP `status` and the parsed response `body`:

```python
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 this feature needs a paid plan")
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 minute, per key:

| Plan | Requests per minute | WebSocket |
| --- | --- | --- |
| Free | 60 | not available |
| Basic | 300 | up to 3 connections |
| Pro | 1200 | up to 10 connections |

## 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`.
