Skip to main content

DataVents Open SDK: unified clients and normalization for Kalshi & Polymarket

Project description

DataVents Open SDK

Unified Python SDK for Kalshi and Polymarket.

What’s inside

  • Unified, no‑auth REST façade over Kalshi and Polymarket public endpoints.
  • Normalization helpers and Pydantic models for events, markets, search, and history.
  • A multiplexed WebSocket client that streams from Kalshi and Polymarket concurrently.

Supported Python: 3.9+

Installation

From PyPI (preferred):

pip install datavents

From a local wheel (e.g., CI artifact):

pip install /path/to/datavents-0.1.0-py3-none-any.whl

Editable install for contributors:

pip install -e .[dev]

Quickstart

List events (both providers) and print a few titles:

from datavents import DataVentsNoAuthClient, DataVentsProviders, DataVentsOrderSortParams, DataVentsStatusParams

client = DataVentsNoAuthClient()
events = client.list_events(
    provider=DataVentsProviders.ALL,
    limit=5,
    page=0,
    status_params=DataVentsStatusParams.OPEN_MARKETS,
    order_sort_params=DataVentsOrderSortParams.ORDER_BY_TRENDING,
)
for payload in events:
    print(payload["provider"], "→ keys:", list(payload["data"].keys()))

Normalize provider search into one schema:

from datavents import normalize_search_response, Provider, OrderSort, StatusFilter

raw = events[0]["data"]  # e.g., Kalshi payload
normalized = normalize_search_response(
    Provider.kalshi,
    raw,
    q="election",
    page=1,
    limit=5,
    order=OrderSort.trending,
    status=StatusFilter.open,
)
print("Normalized results:", len(normalized.results))

Explore more complete runnable samples under examples/.


Unified Client

The DataVentsNoAuthClient exposes a small set of high‑leverage methods. All network calls hit live provider public APIs (no credentials needed for REST). Each method returns a list of provider‑tagged dictionaries like:

[{"provider": "kalshi", "data": {...}}, {"provider": "polymarket", "data": {...}}]

search_events

search_events(
    provider: DataVentsProviders,
    query: str,
    limit: int,
    page: int,
    order_sort_params: DataVentsOrderSortParams,
    status_params: DataVentsStatusParams,
    **params
) -> list[dict]
  • Provider‑specific mapped sorts and statuses (see Enums below).
  • When provider=ALL, Kalshi and Polymarket are called in parallel.
  • Returns raw provider search payloads (use normalization helpers to unify shape).

Common extra params

  • kalshi_params: dict – forwarded to Kalshi search. If scope="series" with a status other than ALL, client falls back to Kalshi events search (series endpoint doesn’t support status).
  • polymarket_params: dict – forwarded to Polymarket public‑search call.

list_events

list_events(
    provider: DataVentsProviders,
    limit: int = 50,
    page: int = 0,
    status_params: DataVentsStatusParams = DataVentsStatusParams.ALL_MARKETS,
    query: str = "",
    order_sort_params: DataVentsOrderSortParams = DataVentsOrderSortParams.ORDER_BY_TRENDING,
) -> list[dict]
  • Thin wrapper around provider search tuned for event discovery.
  • Use with normalize_search_response for unified typing.

list_markets

list_markets(
    provider: DataVentsProviders,
    limit: int = 50,
    page: int = 0,
    status_params: DataVentsStatusParams = DataVentsStatusParams.OPEN_MARKETS,
    query: str = "",
    order_sort_params: DataVentsOrderSortParams = DataVentsOrderSortParams.ORDER_BY_TRENDING,
) -> list[dict]
  • Kalshi path currently uses events search (markets are nested under events).
  • Polymarket path uses public‑search with type="markets" and exposes a top‑level markets list (flattened if needed).

get_event / get_market

get_event(provider, kalshi_event_ticker=None, polymarket_id=None, polymarket_slug=None, *, with_nested_markets=False, include_chat=False, include_template=False) -> list[dict]
get_market(provider, kalshi_ticker=None, polymarket_id=None, polymarket_slug=None, *, include_tag=False) -> list[dict]
  • Supply the proper identifier for each provider (Kalshi uses tickers; Polymarket supports id or slug).
  • With provider=ALL, only providers with identifiers provided are called.

Orderbook (Kalshi, lazy auth)

While the client is "no‑auth" by default, it can lazily spin up a signed Kalshi REST client for auth‑only routes:

from datavents import DataVentsNoAuthClient, DataVentsProviders
from datavents.providers.config import Config as ProviderConfig

dv = DataVentsNoAuthClient()

# Direct helper (returns raw provider JSON)
ob = dv.get_kalshi_market_orderbook("ABC-24-XYZ-T50", depth=50, env=ProviderConfig.LIVE)

# Unified facade (list with provider tag)
res = dv.get_market_orderbook(DataVentsProviders.KALSHI, kalshi_ticker="ABC-24-XYZ-T50", depth=50)

Set environment variables for Kalshi auth:

  • LIVE: KALSHI_API_KEY, KALSHI_PRIVATE_KEY (PEM path)
  • PAPER: KALSHI_API_KEY_PAPER, KALSHI_PRIVATE_KEY_PAPER

Provider‑specific helpers

  • get_event_metadata(event_ticker: str) – Kalshi event metadata.
  • get_event_tags(event_id: int), get_market_tags(market_id: int) – Polymarket tags.

Normalization Layer

Convert raw provider payloads into consistent Pydantic models located in datavents.schemas.

Key entry points

  • normalize_search_response(provider, raw, q, order, status, page, limit)SearchResponseNormalized
  • normalize_event(provider, raw)Event
  • normalize_market(provider, raw)Market
  • normalize_market_history(provider, identifiers=..., start, end, interval, raw|points)MarketHistoryResponseNormalized

Highlights

  • Prices normalized to probability in [0,1] (accepts common provider units such as 0..1, percent, or bps‑like).
  • Timestamps normalized to epoch milliseconds.
  • status mapped to StatusNormalized (open/closed/settled/upcoming/unknown) while retaining status_raw.
  • Provider snapshots preserved under vendor_raw with optional structured vendor_fields.

Example (market → binary outcomes):

from datavents import normalize_market, Provider

raw_market = {"id": 123, "slug": "will-something-happen", "bestBid": 0.47, "bestAsk": 0.49}
m = normalize_market(Provider.polymarket, raw_market)
print(m.mid_price, [o.name for o in m.outcomes])

WebSockets

Use DvWsClient to multiplex Kalshi and Polymarket streams with a single async loop.

import asyncio
from datavents import DvWsClient, DvSubscription, DvVendors

async def main():
    dv = DvWsClient()

    async def on_event(evt):  # evt is datavents.ws.NormalizedEvent
        print(evt.vendor, evt.event, evt.market)

    sub = DvSubscription(
        vendors=(DvVendors.POLYMARKET,),
        polymarket_assets_ids=["asset-id-1", "asset-id-2"],
    )

    await dv.run(sub, on_event)

asyncio.run(main())

Kalshi WS requires valid API credentials in your environment. Polymarket market WS is public and needs only asset ids.

Environment variables (Kalshi; see provider docs)

  • KALSHI_API_KEY (live) or KALSHI_API_KEY_PAPER (paper)
  • KALSHI_PRIVATE_KEY (live) or KALSHI_PRIVATE_KEY_PAPER (paper) – path to PEM file used for RSA‑PSS signing

Enums and Mappings

Order sorts (DataVentsOrderSortParams) map to provider‑specific semantics, e.g.:

  • ORDER_BY_TRENDING → Kalshi trending, Polymarket volume_24hr (proxy).
  • ORDER_BY_CLOSING_SOON → Kalshi closing, Polymarket end_date.

Status filters (DataVentsStatusParams):

  • OPEN_MARKETS → Kalshi opened,unopened; Polymarket active.
  • CLOSED_MARKETS → Kalshi closed,settled; Polymarket closed.
  • ALL_MARKETS → no status filter.

Note: Kalshi series search does not accept a status filter; when you request scope="series" with a non‑ALL status, the client uses events search under the hood.


Configuration, Timeouts, and Rate Limiting

  • HTTP timeout (seconds): HTTP_TIMEOUT_SECONDS env (default 15s).
  • Basic pacing between requests via RateLimitConfig (default ~100ms between calls).
  • Logging: the SDK uses the standard library’s logging module; enable debug logs by configuring handlers in your app.

Examples

See examples/ for small, runnable scripts:

  • search_events.py – search across providers.
  • list_markets.py – get Polymarket markets and Kalshi event‑nested markets.
  • get_event.py / get_market.py – fetch single resources by id/ticker/slug.
  • ws_multiplex.py – stream from Polymarket and/or Kalshi in one loop.
  • normalize_examples.py – convert raw payloads into normalized Pydantic models.

Run like:

python -m venv .venv && source .venv/bin/activate
pip install -e .
python examples/search_events.py --q "election" --limit 5

Utilities

  • extract_vendors(value, *, strict=False)[DvVendors, ...]
    • Accepts flexible input such as "kalshi", "poly,kalshi", "all", Provider.kalshi, or a list of mixed tokens.
    • Returns a stable, de‑duplicated order: [DvVendors.KALSHI, DvVendors.POLYMARKET] when both.
    • Back‑compat alias: _extract_vendors(...).
from datavents import extract_vendors, DvVendors

assert extract_vendors("all") == [DvVendors.KALSHI, DvVendors.POLYMARKET]
assert extract_vendors(["k", "pm"]) == [DvVendors.KALSHI, DvVendors.POLYMARKET]
  • build_ws_info(subscription) → dict summarizing a DvSubscription (WS URLs, channels, identifiers).
    • Back‑compat alias: _send_ws_info(subscription) for legacy callers.
from datavents import DvSubscription, DvVendors, build_ws_info

sub = DvSubscription(
    vendors=(DvVendors.KALSHI, DvVendors.POLYMARKET),
    kalshi_market_tickers=["SER-ABC-123"],
    polymarket_assets_ids=["asset-1"],
)
info = build_ws_info(sub)
print(info["kalshi"]["ws_url"], info["polymarket"]["ws_url"])  # ready for UIs/logging

Limitations & Notes

  • This SDK targets provider public endpoints. Some features (e.g., private Kalshi WS) require valid credentials.
  • list_markets on Kalshi returns markets nested inside events; flatten as needed.
  • Provider APIs evolve; enums map to best‑available sorts/filters and may be updated across releases.

Development

python -m venv .venv
source .venv/bin/activate
pip install -e .[dev]
pytest

To publish artifacts:

make build   # dist/*.whl + dist/*.tar.gz
make check   # twine check dist
make publish # twine upload dist/*

License

MIT

Project details


Download files

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

Source Distribution

datavents-0.1.1.tar.gz (169.4 kB view details)

Uploaded Source

Built Distribution

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

datavents-0.1.1-py3-none-any.whl (57.3 kB view details)

Uploaded Python 3

File details

Details for the file datavents-0.1.1.tar.gz.

File metadata

  • Download URL: datavents-0.1.1.tar.gz
  • Upload date:
  • Size: 169.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for datavents-0.1.1.tar.gz
Algorithm Hash digest
SHA256 eeb3fdbc224f2fab113ca88e83c366c23a791f6417a21a9f89830c50f83dd017
MD5 347417d5a3d11b7d03742f2dd2f5057a
BLAKE2b-256 0bc0264f74be62981f961f29a25ad7c2b936cc3ec2027b114d6635a823277bb7

See more details on using hashes here.

File details

Details for the file datavents-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: datavents-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 57.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for datavents-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 12ee85231c20c5cce9dc802d3ba3c1bc9311ec394aac7c3248c3d60619dbf0fa
MD5 b41c8f2bc9f36730b76ed417e606271e
BLAKE2b-256 4a070bd0393bd620ac7e980fe6cc0d9629eea93a3302f9d1b074db88831aa620

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page