Metadata-Version: 2.4
Name: kresmion
Version: 0.1.0
Summary: Official Python SDK for the Kresmion financial-intelligence API
Author-email: Kresmion <solalguillemois@gmail.com>
License: MIT
Project-URL: Homepage, https://kresmion.com
Project-URL: Documentation, https://kresmion.com/developers
Project-URL: Download, https://kresmion.com/sdk/kresmion.py
Keywords: kresmion,finance,prediction-markets,crypto,equities,macro,api,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.28
Dynamic: license-file

# Kresmion Python SDK

Official Python client for the [Kresmion](https://kresmion.com) financial
intelligence API: prediction markets, on-chain crypto flows, equities
signals, macro regime, cross-market signals, and bulk historical data.

The SDK targets the versioned `/v1` API. It depends only on the Python
standard library plus [`requests`](https://pypi.org/project/requests/).
It returns data for you to work with; it never returns advice.

Version 0.1.0. Python 3.9 and newer.

## Install

Two ways, pick one.

**Single file download (no packaging):**

```bash
curl -O https://kresmion.com/sdk/kresmion.py
pip install "requests>=2.28"
```

Drop `kresmion.py` next to your script and `import kresmion` works.

**Install from source (pip, from a git checkout):**

```bash
pip install "git+https://github.com/kresmion/kresmion-python.git#subdirectory=sdk/python"
# or, from a local clone of the repo:
pip install ./sdk/python
```

Both forms expose the identical `kresmion` module. The single file is a
verbatim build of the package (`build_singlefile.py` keeps them in sync).

## Quickstart

```python
from kresmion import Kresmion

# api_key falls back to the KRESMION_API_KEY environment variable.
k = Kresmion(api_key="krm_your_key_here")

markets = k.prediction.markets(category="crypto", limit=10)
for m in markets:
    print(m["question"], m.get("yes_probability"))

# List results are a plain list plus .count and .as_of metadata.
print("returned", len(markets), "of", markets.count, "as of", markets.as_of)

# Single-object results are a plain dict plus .as_of.
regime = k.macro.regime()
print(regime["bucket"], "as of", regime.as_of)
```

Every list method returns an `ApiList` (a `list` subclass carrying
`.count` and `.as_of`). Every single-object method returns an `ApiDict`
(a `dict` subclass carrying `.as_of`). You can treat them as ordinary
`list` / `dict` and reach for the metadata attributes when you need them.

## Compound brief (start here)

`k.brief(asset_class, symbol)` is the fastest way in: one call assembles
the full cross-product digest for a single symbol from every relevant
product family, so you do not have to stitch the family endpoints
together yourself.

```python
btc = k.brief("crypto", "BTC")
# crypto: derivatives + cross-exchange funding, liquidations, on-chain /
# stablecoin flows, ETF flows, related prediction markets, macro regime.

nvda = k.brief("equity", "NVDA")
# equity: signals, insider + congress, 13F, modeled dealer gamma, related
# prediction markets.
```

Each sub-section carries its own `as_of`, so you can tell which legs are
fresh and which are stale. The digest is descriptive and event-framed,
never advice. Reach for the family methods below when you need to drill
deeper than the digest returns.

## Configuration

```python
k = Kresmion(
    api_key=None,                      # else env KRESMION_API_KEY
    base_url="https://kresmion.com/api",
    timeout=30,                        # seconds per request
    max_retries=3,                     # extra attempts on 429 / 5xx / connection error
)
```

The client keeps a persistent HTTP session for connection reuse. Use it
as a context manager to close the session automatically:

```python
with Kresmion() as k:
    print(k.status())
```

## Namespaces

One example per namespace. Every method has a full docstring, so
`help(k.prediction.markets)` is your inline reference.

### `k.prediction` - prediction markets

```python
k.prediction.markets(category="crypto", min_volume=10000, q="fed", limit=50)
k.prediction.market("0xabc123")                  # one market
k.prediction.history("0xabc123", days=7)         # probability history
k.prediction.book("0xabc123")                    # order book
k.prediction.book_history("0xabc123", hours=24)  # depth/spread over time
k.prediction.execution_cost("0xabc123", notionals=[100, 1000, 10000])  # one-leg fill cost
k.prediction.algo_flags("0xabc123")              # algorithmic-flow flags
k.prediction.flow("0xabc123")                    # recent flow
k.prediction.movers(limit=25)
k.prediction.consensus()
k.prediction.divergence(executable_size=1000)    # cross-venue gaps, netted vs Polymarket-leg cost at $1k
k.prediction.calendar(days=14)                   # upcoming resolutions (scheduled dates)
k.prediction.calibration()
k.prediction.resolutions(limit=25)
```

### `k.crypto` - on-chain flows, ETFs, derivatives, options

```python
whales = k.crypto.whales(min_usd=1_000_000, hours=24)
k.crypto.exchange_holdings()
k.crypto.exchange_history("binance", days=30)
k.crypto.etf_flows()
k.crypto.etf_history("IBIT", days=30)
k.crypto.derivatives("BTC")
k.crypto.funding()                    # cross-exchange funding surface
k.crypto.funding("BTC")               # one symbol's funding history
k.crypto.liquidations("BTC", hours=24)  # forced deleveraging (single venue, OKX)
k.crypto.stablecoins()                # aggregate stablecoin supply / issuance
k.crypto.unlocks(days=90)             # forward token-unlock calendar
k.crypto.funding_history("BTC", days=30)
k.crypto.oi_history("BTC", days=30)
k.crypto.options("BTC")
```

### `k.equities` - signals, insiders, congress, 13F

```python
k.equities.signals(limit=50)
k.equities.insider_clusters(limit=50)
k.equities.congress(limit=50)
k.equities.institutional(limit=50)
k.equities.price_history("AAPL", days=90)
k.equities.gamma()               # modeled dealer-gamma surface
k.equities.gamma("NVDA")         # one ticker: gamma by strike, flip level, walls
```

### `k.macro` - regime, COT, TIC, BIS

```python
k.macro.regime()                    # current cross-asset Risk-On/Off score and factors
k.macro.regime_history(days=365)    # the regime score time series
k.macro.correlations()              # cross-asset correlation breaks (latest snapshot)
k.macro.cot()
k.macro.tic()
k.macro.bis()
```

### `k.signals` - cross-market signal feed

The signals namespace is callable, and it carries an `accuracy` method:

```python
feed = k.signals(limit=50, severity="high")   # GET /v1/signals
stats = k.signals.accuracy()                  # GET /v1/signals/accuracy
```

### `k.status()` and `k.openapi()`

```python
k.status()      # service status and your quota snapshot
k.openapi()     # the raw OpenAPI 3 document for /v1
```

### `k.bulk` - bulk historical downloads

Streams a gzip-compressed CSV for a date range straight to disk, with an
optional progress callback:

```python
import gzip, csv

def show(done, total):
    print(done, "/", total, "bytes")

k.bulk.download("prediction_markets", "2026-01-01", "2026-06-30",
                "pm.csv.gz", progress=show)

with gzip.open("pm.csv.gz", "rt") as fh:
    for row in csv.DictReader(fh):
        print(row)
```

## Webhook verification

Kresmion signs every webhook delivery with HMAC-SHA256 over the raw
request body and sends the result in the `X-Kresmion-Signature` header as
`sha256=<hex>`. Verify it with the shared secret you received when you
created the webhook. Always hash the exact raw bytes, never re-serialized
JSON.

```python
from kresmion import verify_webhook

# secret: the value handed to you once at webhook-create time.
# raw:    the exact request body bytes.
# sig:    the X-Kresmion-Signature request header.
if verify_webhook(secret, raw, sig):
    handle(raw)
else:
    reject()  # 400
```

`verify_webhook` does a constant-time comparison and returns `False`
(never raises) on a bad or missing signature. See
`examples/webhook_receiver.py` for a complete stdlib receiver.

### Global market events

Subscribe a webhook to any of these global market events (envelope
`{"event", "fired_at", "data"}`). The authoritative catalog, with an
example body and expected cadence per event, is served live at
`GET /v1/webhooks/events`.

| Event | Fires when |
| --- | --- |
| `signal.created` | A new cross-asset signal fires at the top (critical) severity tier. |
| `whale.transfer` | A single on-chain transfer >= $1M (self-transfer artifacts excluded). |
| `prediction.repricing` | A market (>= $50k volume) whose YES probability moved >= 10pp in 24h. |
| `prediction.divergence` | A linked Polymarket/Kalshi pair whose cross-venue \|spread\| crossed >= 5pp. |
| `prediction.resolution_imminent` | A contested market (>= $50k volume) whose scheduled close is within 48h. |
| `prediction.algo_flow` | A high-conviction algorithmic-flow flag on a market (confidence >= 85, notional >= $25k). |
| `etf.flow` | A new daily crypto-ETF flow print (once per new date per asset). |
| `regime.change` | The daily macro Risk-On/Off regime crossed into a new bucket. |

## Rate limits and error handling

Keyed responses carry rate-limit headers. After every call, the client
refreshes `k.last_rate_status`:

```python
k.prediction.markets(limit=1)
print(k.last_rate_status)
# {'limit_minute': 60, 'remaining_minute': 59,
#  'monthly_limit': 10000, 'monthly_used': 42}
```

The client retries transient failures for you with exponential backoff
and jitter, up to `max_retries`:

- On `429`, it honors the `Retry-After` header exactly when the server
  sends one, otherwise it backs off exponentially.
- On `5xx` and connection errors, it backs off exponentially.

When retries are exhausted, or on an error that is not retried, the
client raises a typed exception:

| Exception | Raised on | Carries |
| --- | --- | --- |
| `KresmionAuthError` | `401` (not retried) | `.status`, `.detail` |
| `KresmionRateLimitError` | `429` after retries | `.retry_after`, `.rate_status` |
| `KresmionAPIError` | other `4xx` / `5xx`, or connection failure | `.status`, `.detail` |

All three subclass `KresmionError`, so you can catch broadly or narrowly:

```python
from kresmion import (
    KresmionAuthError, KresmionRateLimitError, KresmionAPIError, KresmionError,
)

try:
    data = k.crypto.whales(min_usd=5_000_000)
except KresmionRateLimitError as exc:
    print("slow down for", exc.retry_after, "seconds")
except KresmionAuthError:
    print("check your API key")
except KresmionAPIError as exc:
    print("api error", exc.status, exc.detail)
except KresmionError as exc:
    print("kresmion error", exc)
```

## Examples

- `examples/divergence_monitor.py` polls prediction divergence every 60
  seconds and prints crossings.
- `examples/webhook_receiver.py` is a stdlib `http.server` receiver that
  verifies signatures.
- `examples/backtest_download.py` bulk-fetches a dataset and parses the
  gzip CSV into rows.

## License

MIT.
