Skip to main content

auspicium

Python SDK for the Auspicium market data platform — crypto OHLCV, order books, trades, Polymarket prediction markets, and cross-market signals.

Install

pip install auspicium

Quick start

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

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

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 for the full per-version history. The most recent entries (newest first):

Version Date Headline
0.9.15 2026-08-19 A TAKER fill recorded the COUNTERPARTY's price (AUS-215). _order_execution_from_trades priced our fill from maker_orders[].price, on the stated assumption that the per-maker legs are "true per-level prices". That holds when the maker sold the SAME token we bought; on a binary market's mint path the maker fills the other side by buying the complementary token, so their price is 1 - ours and we recorded the complement. Measured on a live production bot: a fill that executed at 0.87 was recorded at 0.13, and the cost basis read $5.78 for a fill that cost $39.01. Confirmed three ways — the Polygon receipt (OrderFilled for our own order hash: makerAmountFilled 38.6628 / takerAmountFilled 44.44 = 0.87), Polymarket's public Data API (0.870000), and the operator's activity feed. The bot's logs also settle intent: it submitted price=0.9000 on all 14 orders, so this was never an execution problem — the trade it asked for is the trade it got, mis-recorded. Our execution is now the trade's own top-level price; the maker legs are read only to CORROBORATE it (VWAP ≈ price → same-token; VWAP ≈ 1 − price → complementary; neither → claim nothing and let the caller fall back with a label). The maker branch, which selects our own leg by order id, was always correct and is untouched — every maker-branch fill in the incident recorded the right price and every taker-branch one recorded the complement. Also: get_trades is now filtered to the market (TradeParams supports it and the SDK passed nothing, scanning page one of the account's entire history — a bot's own recent trades eventually fall off it and the lookup silently returns nothing), and new Fill.price_source records WHICH rung of the price ladder produced price, so a consumer can finally tell a measured execution (response_amounts / venue_trade_log) from the price we merely asked for (order_status_limit / requested). None on pre-0.9.15 fills. No state.db action.
0.9.14 2026-08-18 Fix — a LIMIT/GTD fill lost the strategy's order id; new Fill.order_type. state.db stays v5, do NOT delete it. The order-status polling path — which serves every LIMIT/LIMIT_GTD order and every plain MARKET (FOK) whose POST response carried no two-sided amounts — recorded the venue's 0x… hash as Fill.order_id, replacing the strategy's <reason>:<uuid> tag. That broke three things at once: the dashboard's REASON and exit-path badges (parsed off the tag) went blank; StrategyRunner._on_fill frees the open-order slot by fill.order_id on a dict keyed by order.id, so the pop missed and after max_open_orders leaked fills the bot bricked itself at the risk check; and cancel() was unreachable, since Strategy.submit discards the exchange id and the venue does not know order.id. The fill keeps the strategy's id; the venue id moves to the new Fill.exchange_order_id; cancel() takes either. New Fill.order_type records what produced the fill — stamped on every Polymarket path plus paper and backtest, so a trades table reads identically in a notebook and in a live bot. None means "not recorded", never "MARKET" (guessing from the 0x shape is the AUS-192/AUS-198 defect — that shape cannot tell a maker GTD hash from a FOK CLOB orderID). The two columns are added in place by an additive migration, so no bot loses its portfolio state for a display field
0.9.13 2026-08-14 Fix — live plain-MARKET (FOK) Polymarket fills recorded fiction; state.db → v5, delete it on upgrade. Five real-money fills, five-for-five on-chain confirmation (2026-08-14): the SDK recorded Fill.size = actual_shares ÷ order_price (11.235954 executed → 12.2797 recorded), Fill.price = the tick-rounded quote (0.91 recorded, 0.89 executed) and Fill.fee = 0.0 (chain collected $0.0770). The 0.9.0 "legacy converter" assumed the polling response's size_matched was USDC on BUY; it is shares on both sides, on every shape that carries it — no published py-clob-client-v2 ever produced a USDC one, so the division is deleted. Executed price now comes from the response's two-sided amounts (a FOK that matches at submit is recorded there, like FAK) or the venue's trade log, with labelled fallbacks; fees are venue-reported or computed role-aware from the market's own fd schedule via auspicium.fees (the FAK path's hardcoded fee=0.0 closed too). Recorded live numbers move — to the truth; backtest/paper unchanged
0.9.12 2026-08-11 Fix — live orders on Up/Down Polymarket markets were impossible; no state.db action. The Polymarket adapter matched an order's canonical outcome ("YES"/"NO" — all Order.binary_buy accepts) against the venue's token label by exact string equality, and Polymarket's hourly Bitcoin markets label their tokens Up/Down. Every live entry on one raised OrderRejectedError: outcome 'YES' not found — a production bot logged 260 raises and 0 orders. Exact match still wins; when it misses, the lookup now falls back to the pole vocabulary (YES ↔ Up/Over/Above/Higher, NO ↔ Down/Under/Below/Lower), refuses to guess when two tokens share a pole, and lists the market's actual labels when nothing matches. Same fix reaches get_order_book / book_depth_at_or_better. New auspicium.outcomes module holds that vocabulary once (three copies before); pole_of("Up") == "YES" converts a wire label in strategy code
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) 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) 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 and the bundled 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 devmain (PRs into main require green CI).

  5. Human tags and pushes the tag — tags are human-only; agents never create or push tags:

    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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

auspicium-0.9.15.tar.gz (197.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

auspicium-0.9.15-py3-none-any.whl (201.8 kB view details)

Uploaded Python 3

File details

Details for the file auspicium-0.9.15.tar.gz.

File metadata

  • Download URL: auspicium-0.9.15.tar.gz
  • Upload date:
  • Size: 197.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.11.16

File hashes

Hashes for auspicium-0.9.15.tar.gz
Algorithm Hash digest
SHA256 5a006228f68c2290720f28ef79ea07670d66f832372248f7148b63f4cf530375
MD5 b02e0426ab4b8d61aa6740d89b649ea6
BLAKE2b-256 cb8e9ef9e6736641c32d508d93954e82ff61a7d48ecda4300a3a59b7f3290daa

See more details on using hashes here.

File details

Details for the file auspicium-0.9.15-py3-none-any.whl.

File metadata

  • Download URL: auspicium-0.9.15-py3-none-any.whl
  • Upload date:
  • Size: 201.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.11.16

File hashes

Hashes for auspicium-0.9.15-py3-none-any.whl
Algorithm Hash digest
SHA256 c5c1e469bec7a236a9552078e94304af570110e2582de2e676bc6f5ce151523c
MD5 15f10257173ebb74581ac05ed06d5752
BLAKE2b-256 05de14eaffe80e68f199e3076e4edcc9e8953de645be9c054170fc58cc7a2f4f

See more details on using hashes here.

Release history Release notifications | RSS feed

0.11.2

2 files

0.11.1

2 files

0.11.0

2 files

0.10.1

2 files

0.10.0

2 files

0.9.21

2 files

0.9.20

2 files

0.9.19

2 files

0.9.18

2 files

0.9.17

2 files

0.9.16

2 files

This release

0.9.15 This release

2 files

0.9.14

2 files

0.9.13

2 files

0.9.12

2 files

0.9.11

2 files

0.9.10

2 files

0.9.9

2 files

0.9.8

2 files

0.9.7

2 files

0.9.6

2 files

0.9.5

2 files

0.9.4

2 files

0.9.3

2 files

0.9.2

2 files

0.9.1

2 files

0.9.0

2 files

0.8.0

2 files

0.7.20

2 files

0.7.19

2 files

0.7.18

2 files

0.7.17

2 files

0.7.16

2 files

0.7.15

2 files

0.7.14

2 files

0.7.13

2 files

0.7.12

2 files

0.7.11

2 files

0.7.10

2 files

0.7.9

2 files

0.7.8

2 files

0.7.7

2 files

0.7.6

2 files

0.7.5

2 files

0.7.4

2 files

0.7.3

2 files

0.7.2

2 files

0.7.1

2 files

0.7.0

2 files

0.6.0

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.3

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page