Metadata-Version: 2.4
Name: dino-markets
Version: 0.2.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/dino-markets/dino-markets-python
Author-email: Nusantara Ventures LLC <support@dino.markets>
License: MIT
License-File: LICENSE
Keywords: api,arbitrage,crypto,economics,kalshi,polymarket,prediction markets,sports,weather
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: 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

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

## Authentication

Create a key at [dino.markets](https://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:

```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")

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

```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)

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`:

```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 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](https://dino.markets/ja/docs) | [MCP](https://dino.markets/ja/docs/mcp) |
| 한국어 | [Docs](https://dino.markets/ko/docs) | [MCP](https://dino.markets/ko/docs/mcp) |
| 简体中文 | [Docs](https://dino.markets/zh/docs) | [MCP](https://dino.markets/zh/docs/mcp) |
| Español | [Docs](https://dino.markets/es/docs) | [MCP](https://dino.markets/es/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`.
