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.

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.0.tar.gz (162.1 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.0-py3-none-any.whl (52.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: datavents-0.1.0.tar.gz
  • Upload date:
  • Size: 162.1 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.0.tar.gz
Algorithm Hash digest
SHA256 2c326b8fabbd5ca2f00c7367cdfb508da4726cdbadd226c377fb7ee171fcdf6f
MD5 b3dbca50e9db143e1c2dabdbafd8bfd0
BLAKE2b-256 b2b72684071d16ff0d0799cdcf831aebf9567f2dac97d23107808c3176dfe93c

See more details on using hashes here.

File details

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

File metadata

  • Download URL: datavents-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 52.4 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a5de09fc7c084c47ea0444e04cf6a0c8434e302472cfece976526b9cd2404fc0
MD5 2f7d402e0ee8586693fb0080d887635b
BLAKE2b-256 51aed21c404cb05550734c8169d924d0ecca04778dfecd03d92be4920b002502

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