Metadata-Version: 2.4
Name: auspicium
Version: 0.9.11
Summary: Auspicium DaaS SDK — market data for crypto and prediction market quants
Author-email: Auspicium <technical.account@auspicium.io>
License: MIT
Keywords: market-data,crypto,polymarket,quant,finance,binance
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: Intended Audience :: Developers
Classifier: Topic :: Office/Business :: Financial
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: httpx>=0.27
Requires-Dist: websockets>=13.0
Requires-Dist: pydantic>=2.6
Requires-Dist: pandas>=2.2
Requires-Dist: pyarrow>=15.0
Requires-Dist: typer>=0.12
Requires-Dist: rich>=13.7
Requires-Dist: pyyaml>=6.0
Provides-Extra: strategy
Requires-Dist: prometheus_client>=0.20; extra == "strategy"
Provides-Extra: backtest
Requires-Dist: vectorbt>=0.26; extra == "backtest"
Requires-Dist: plotly>=5.20; extra == "backtest"
Requires-Dist: scipy>=1.13; extra == "backtest"
Requires-Dist: auspicium[strategy]; extra == "backtest"
Provides-Extra: exchange
Requires-Dist: py-clob-client-v2>=1.0.1; extra == "exchange"
Requires-Dist: python-binance>=1.0.19; extra == "exchange"
Provides-Extra: api
Requires-Dist: fastapi>=0.110; extra == "api"
Requires-Dist: uvicorn>=0.29; extra == "api"
Provides-Extra: production
Requires-Dist: auspicium[strategy]; extra == "production"
Requires-Dist: auspicium[exchange]; extra == "production"
Requires-Dist: auspicium[api]; extra == "production"
Provides-Extra: all
Requires-Dist: auspicium[strategy]; extra == "all"
Requires-Dist: auspicium[backtest]; extra == "all"
Requires-Dist: auspicium[exchange]; extra == "all"
Requires-Dist: auspicium[api]; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
Requires-Dist: pytest-cov>=5.0; extra == "dev"
Requires-Dist: respx>=0.21; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"

# auspicium

Python SDK for the [Auspicium](https://auspicium.io) market data platform — crypto OHLCV, order books, trades, Polymarket prediction markets, and cross-market signals.

## Install

```bash
pip install auspicium
```

## Quick start

```python
import os
os.environ["AUSP_API_KEY"]     = "your-api-key"
os.environ["AUSP_GATEWAY_URL"] = "https://api.auspicium.io"

from auspicium import rest

# OHLCV candlestick data
df = rest.ohlcv("binance", "BTC-USDT", interval="5m", days=7)

# Order book snapshot
book = rest.orderbook("binance", "BTC-USDT", depth=20)

# Polymarket prediction markets
markets = rest.markets(status="active", base_asset="BTC")

# Cross-market signal (Binance x Polymarket)
cross = rest.cross_market(granularity="5m", base_asset="BTC", hours=48)
```

## WebSocket streaming

```python
from auspicium import stream

async with stream.connect() as ws:
    await ws.subscribe("ohlcv", source="binance", symbol="BTC-USDT")
    async for msg in ws:
        print(msg.channel, msg.payload)
```

## Get your API key

Sign up at [auspicium.io](https://auspicium.io) — free tier included.

## Pointing the SDK at another environment

The SDK talks to whatever gateway `AUSP_GATEWAY_URL` points at (default
`https://api.auspicium.io`). To exercise it against the **Quality** DaaS:

```bash
export AUSP_GATEWAY_URL=https://api.quality.auspicium.io
export AUSP_API_KEY=<your quality API key>
```

No localhost DaaS is ever required. The unit test suite is fully mocked;
only `tests/test_rest.py` and `tests/test_stream.py` are integration tests
that need a live gateway (set the two variables above to run them).

## Changelog

See [CHANGELOG.md](https://github.com/auspicium1/auspicium-sdk/blob/main/CHANGELOG.md)
for the full per-version history. The most recent entries (newest first):

| Version | Date       | Headline                                                                                                     |
| ------- | ---------- | ------------------------------------------------------------------------------------------------------------ |
| 0.9.11  | 2026-08-09 | **Fix — `win_rate` counted fills, not round trips; the reported rate was about half the real one. No `state.db` action (stays v4).** Backtest and live `/api/status` both divided winning rows by every row of `_compute_trade_pnl`, a table with one row per **fill**; opening BUYs carry `pnl` exactly 0.0, so the reported rate **could not exceed 50%** and a true 146/165 = 88.5% strike rate printed as 44.2%. Now wins over round trips, with the counts published: new `closed_trades` / `winning_trades` / `losing_trades` stats keys and a new `closed_size` column on the trades table (shares an exit matched against open lots). `total_trades` still counts fills. No other number moves — `total_return` was correct all along |
| 0.9.10  | 2026-08-05 | **Fix — realized-PnL accounting; reported numbers move; `state.db` → v4, delete it on upgrade.** The `realized_pnl … diverges from FIFO gross` WARNING was a false positive (it reconstructed gross as `net + every fee`, so drift equalled the fee total); it now replays the persisted fills through the same `apply_fill` the runner uses. `_compute_trade_pnl` now sorts fills chronologically (the live feed is newest-first), keys queues by `(market, outcome)`, charges each closing trade its **entry** fee as well as its exit fee, and no longer mutates the caller's fills; new `gross_pnl` column. The runner deletes closed positions from `state.db` and rebuilds cash / realized PnL / positions from the fill log on start |
| 0.9.9   | 2026-08-01 | **Behaviour change.** New `auspicium.fees` — one role-aware, schedule-driven fee model shared by backtest and paper (market schedule → published category table → highest published rate; takers pay, makers pay 0 + rebate). Simulated Polymarket fees rise from a flat `0.02` to the resolved rate (**crypto `0.07`, 3.5×**); the new number is the correct one. Binance unchanged |
| 0.9.8   | 2026-07-30 | `Strategy.stake_amount()` — launch-time position sizing from the per-instance config (`stake_mode` fixed / `pct_cash` / `pct_equity`, `stake_pct`, floor, cap); returns `0.0` below the floor and clamps to the risk limit `max_position_usd` instead of failing at submit |
| 0.9.7   | 2026-07-29 | Per-instance risk-limit overrides: the platform-delivered instance config's `risk` section merges per key over `manifest.yaml`'s (instance config > manifest > `RiskGuardian` defaults); bad overrides warn and fall back instead of blocking a start. Changelog/README overhaul + drift guard |
| 0.9.6   | 2026-07-19 | Fix (live-bot reliability): symbol-less `subscribe()` on a symbol-keyed channel fails loudly at startup (was a silent 0-tick no-op); tick-freshness watchdog scales to the slowest ohlcv interval; runtime `TIER_LIMIT` on re-subscribe is recoverable, not fatal; disconnect reasons logged via `repr()` |
| 0.9.5   | 2026-07-16 | Fix: WebSocket URL now derives from `AUSP_GATEWAY_URL` (same host, `wss`, `/v1/ws`) instead of a hardcoded apex default; explicit `AUSP_WS_URL` still overrides                      |
| 0.9.4   | 2026-06-28 | `RestConnector.address_trades` accepts a `period` preset (`"7d"`/`"30d"`/`"all"`), mirroring `address_stats` |
| 0.9.3   | 2026-06-17 | Packaging: bundle `auspicium/CLAUDE.md` + `auspicium/CHANGELOG.md` inside the wheel — no runtime/API change  |
| 0.9.2   | 2026-06-09 | Billing: `account.me()`, `billing.create_checkout/create_portal`, `DaasRateLimitError`; HTTP 429 is surfaced immediately (no auto-retry) |
| 0.9.1   | 2026-05-22 | Tests-only patch; runtime code identical to 0.9.0 (recommended pin over 0.9.0 for the cleaner sdist)         |
| **0.9.0** | **2026-05-22** | **BREAKING:** `Fill.size` for Polymarket BUYs is now shares (was USDC). New `Fill.notional_usd`. state.db must be deleted on upgrade. |
| 0.8.0   | 2026-05-19 | Fix: `ProductionExchange.get_order_book` now delegates to the polymarket adapter (was returning `None`)      |
| 0.7.20  | 2026-05-19 | `MARKET_FAK` / `LIMIT_GTD` order types + `get_order_book` + `Strategy.book_depth_at_or_better`                |
| 0.7.19  | 2026-05-18 | Fix: `Strategy.submit()` pops `_open_orders` on `exchange.submit()` failure                                  |
| 0.7.18  | 2026-05-17 | Polymarket WS payload carries market metadata (`candle_open/close`, `active`, …). `BinaryMarketAggregator`. Heartbeat silent-reject WARN. |
| 0.7.17  | 2026-05-16 | Fix: `BacktestPaperExchange._positions` re-keyed by `(market, outcome)` — YES + NO no longer net             |
| 0.7.16  | 2026-05-15 | `RestConnector.address_stats` accepts arbitrary windows via `from_ts` / `to_ts`                              |
| 0.7.15  | 2026-05-15 | Copy-trading SDK (`address_trades`, `address_stats`, `tracked_addresses`, `address` WS channel, notebook helper) |

## Releasing

Releases are cut from `main` and published to public PyPI by Cloud Build
(project `auspicium`). CI ([cloudbuild.ci.yaml](cloudbuild.ci.yaml)) runs
`ruff` + the unit suite on Python 3.11 and 3.12 for every push to `dev` and
every PR; the release pipeline ([cloudbuild.release.yaml](cloudbuild.release.yaml))
runs only on `v*` tags and publishes via PyPI Trusted Publishing (OIDC) — no
PyPI credential is stored anywhere.

To ship a change as, e.g., **0.9.5**:

1. Develop on `dev`.
2. In the **same change** as the feature/fix, bump `auspicium/_version.py` →
   `"0.9.5"` and add the entry to **both** changelogs — the repo-root
   [`CHANGELOG.md`](CHANGELOG.md) and the bundled
   [`auspicium/CHANGELOG.md`](auspicium/CHANGELOG.md) (including its
   "Current pin" line). Keep the two in sync: the bundled copy is frozen
   into the wheel at tag time and is what a stack pinned to this version
   reads forever (same for `auspicium/CLAUDE.md`, the bundled operator
   guide — update it if behavior it describes changed).
   SemVer: **patch** = bugfix, **minor** = feature, **major** = breaking.
3. Push `dev` → CI runs pytest + ruff. Nothing is published.
4. **Human** merges `dev` → `main` (PRs into `main` require green CI).
5. **Human** tags and pushes the tag — **tags are human-only; agents never
   create or push tags**:

   ```bash
   git tag v0.9.5
   git push origin v0.9.5
   ```

6. The release trigger then:
   - **guards**: fails the build if the tag (`v0.9.5`) ≠ `_version.py`
     (`0.9.5`), so a mislabeled wheel can never ship;
   - re-runs the unit suite;
   - builds `auspicium-0.9.5-py3-none-any.whl` + `.tar.gz`;
   - uploads to PyPI with a short-lived OIDC-minted token.
7. `pip install -U auspicium` now resolves 0.9.5.

**PyPI versions are immutable.** A version number uploads exactly once and
can never be re-uploaded — even after deleting it on PyPI. If 0.9.5 ships
broken, fix it by releasing **0.9.6**; never try to re-tag or re-upload
0.9.5 — a wrong tag burns the version number permanently. (This is also why
the tag-vs-version guard exists: get the bump in *before* tagging.)

### Versions are live runtimes (stacks)

Platform users run the SDK through **stacks**, each pinned to a released
version. The **default stack** runs whatever version is **baked into the
Studio workspace image** (`auspicium/workspace:latest`) — it does *not*
track PyPI automatically. Consequences:

- **Publishing makes a version *available*, not *live*.** Uploading
  `vX.Y.Z` to PyPI is step one. It reaches default-stack users only after
  the studio repo bumps its `AUSPICIUM_SDK_VERSION` pin (`.env`) and
  rebuilds the workspace/bot images — a separate, gated flow (tracked as
  AUS-42). Users who want a published version sooner can create a custom
  stack pinned to it.
- **Old versions never die.** Any released version remains a selectable
  stack runtime. Never yank or delete a PyPI release — existing stacks pin
  exact versions (and deletion wouldn't free the number anyway).
- **The changelog is the version picker.** Stack owners choose a pin from
  the At-a-glance table — headlines must be accurate, and breaking changes
  must be flagged explicitly.

### History note — do NOT retro-tag ≤ 0.9.4

This repo currently has **no git tags**: releases 0.8.0 → 0.9.4 on PyPI were
published outside the tag-triggered pipeline, and the release guard has never
fired. Do **not** create tags `v0.9.4` or earlier "to backfill history" —
each would trigger a doomed re-publish of an already-immutable version and a
red build. The next tagged release is the **first live run** of this
pipeline: watch it end-to-end.
