Skip to content

perps: docs, examples, README/CHANGELOG, demo integration tests & release closeout #401

Description

@TexasCoding

Epic: part of #387 · Depends on: #389, #390, #391, #392, #393, #394, #395, #396, #398, #400

Summary

Cross-cutting closeout for the PERPS (margin) API work: user-facing documentation (README section + docs/ page + mkdocs nav), runnable examples/, a CHANGELOG entry + version bump, the perps repo label, the spec-version banner update, and demo-environment integration tests gated exactly like the existing live tests but pointed at external-api.demo.kalshi.co. This issue ships last — it documents and exercises the PerpsClient / AsyncPerpsClient surface that the REST and WS feature issues build. No new SDK models or resource methods are introduced here; this is documentation, examples, tests, and release plumbing only.

This is the release-closeout issue: it depends on all perps REST resources, the WebSocket channels, and the SCM/Klear endpoints landing first. Docs, examples, and the CHANGELOG must cover the full shipped surface — REST, WS, and SCM/Klear — with no silent omissions.

Endpoints / scope

N/A — no new endpoints. This issue documents and integration-tests the already-implemented perps surface. For reference, the surface under documentation/test is the perps REST resource families and the perps WS channels:

Area Surface being documented / tested
REST exchange GetMarginExchangeStatus, GetMarginRiskParameters
REST orders GetMarginOrders, CreateMarginOrder, GetMarginOrder, CancelMarginOrder, DecreaseMarginOrder, AmendMarginOrder, GetMarginFCMOrders
REST markets GetMarginMarkets, GetMarginMarket, GetMarginMarketOrderbook, GetMarginMarketCandlesticks
REST portfolio/risk GetMarginFills, GetMarginPositions, GetMarginTrades, GetMarginBalance, GetMarginRisk, GetMarginEnabled, GetMarginNotionalRiskLimit, GetMarginFeeTiers
REST funding GetMarginFundingHistory, GetMarginHistoricalFundingRates, GetMarginFundingRateEstimate
REST subaccounts/transfer IntraExchangeInstanceTransfer, CreateMarginSubaccount, ApplyMarginSubaccountTransfer
REST order groups GetMarginOrderGroups, CreateMarginOrderGroup, GetMarginOrderGroup, DeleteMarginOrderGroup, ResetMarginOrderGroup, TriggerMarginOrderGroup, UpdateMarginOrderGroupLimit
WS channels orderbook_delta (snapshot + delta), ticker (carries funding_rate / next_funding_time_ms), trade, fill, user_orders, order_group_updates

Each implemented family must have at least one runnable example and at least one demo integration test (see Tests). Whichever families have NOT shipped at merge time are explicitly scoped out and noted as "pending" in the docs.

Models

N/A — no new Pydantic models. See the Deliverables checklist below in place of Models/Resource methods.

Deliverables checklist

1. README perps section (README.md)

  • Add a top-of-file feature bullet noting perps/margin support (mirror the existing terse bullet style, e.g. the V2 event-market orders bullet).
  • Add a ## Perps (margin) trading section after the WebSocket quickstart with:
    • a one-paragraph explainer (standalone PerpsClient / AsyncPerpsClient, own base URL https://external-api.kalshi.com/trade-api/v2 prod / https://external-api.demo.kalshi.co/trade-api/v2 demo, reuses the same RSA-PSS auth as KalshiClient).
    • a sync quickstart and an async quickstart, mirroring the existing ## Quickstart — sync / ## Quickstart — async blocks but constructing PerpsClient(key_id=..., private_key_path=...) / PerpsClient.from_env().
    • a short note that prices are DollarDecimal (FixedPointDollars, up to 6 decimals), counts are FixedPointCount (2 decimals, wire field suffix _fp), REST timestamps are RFC3339, and WS timestamps are Unix-epoch milliseconds (*_ms fields).

2. Docs page (docs/perps.md, NEW)

  • New page covering: client construction, auth (links to existing authentication.md), environment variables (from_env() + demo routing), the resource families, funding mechanics (funding rate, next_funding_time_ms), risk/balance introspection, and the perps WS channels (link to websockets.md patterns; note the WS host external-api-margin-ws.kalshi.com prod / external-api-margin-ws.demo.kalshi.co demo, path /trade-api/ws/v2/margin).
  • Register in mkdocs.yml nav: add a top-level - Perps: perps.md entry (place it after WebSocket: websockets.md). If per-resource pages are desired, add them under a Perps section mirroring the Resources: block — but a single perps.md is sufficient for this issue.
  • If the perps resources expose mkdocstrings-rendered API reference, add the module path to reference.md (mirror how existing resources are referenced).

3. Examples (examples/, NEW directory — none exists today)

  • examples/perps_create_order.py — construct PerpsClient.from_env(), place a resting (non-marketable) margin order via the perps orders create method, print the returned order, then cancel it. Mirror the safety pattern of tests/integration/conftest.py::non_marketable_price (far-from-market limit so it rests, not fills).
  • examples/perps_stream_ticker.py — async example: connect to the perps margin WS, subscribe to the ticker channel for a market, and print funding_rate + next_funding_time_ms as messages arrive (demonstrates funding mechanics).
  • examples/perps_balance_risk.py — call GetMarginBalance (balance()) and GetMarginRisk (risk()); print cash balance, position value, total balance, maintenance-margin requirement, account leverage, and per-position liquidation prices.
  • Each example must be runnable as python examples/perps_*.py, read credentials via from_env(), default to demo (KALSHI_DEMO=true or the perps demo base URL), and carry a top-of-file docstring stating the required env vars. Keep examples minimal — no argparse scaffolding unless a ticker arg is genuinely needed.

4. CHANGELOG + version bump

  • CHANGELOG.md: add a new top entry following the existing format (heading ## <new-version> — <date>, prose summary, ### Added bullets for PerpsClient / AsyncPerpsClient and the perps resource families + WS channels, ### Internal bullets for the vendored specs/perps_openapi.yaml (+ specs/perps_asyncapi.yaml) sha256 snapshots and the README/docs/index.md banner bump). Cross-link docs/perps.md.
  • Bump version in pyproject.toml:3 and __version__ in kalshi/__init__.py:356 to the same value. This is an additive release (new standalone client, no breaking changes to KalshiClient) → minor bump from 3.1.0 (e.g. 3.2.0). Do not use the breaking label.

5. Spec-version banner update

  • README.md and docs/index.md currently advertise "99 operations across 19 resources (OpenAPI v3.20.0)" and "13 channels"/"11 typed channels". Add a perps line to both banners stating the perps surface (operation count from /tmp/perps_openapi.yaml, WS channel count from /tmp/perps_asyncapi.yaml) and the perps spec version. Do not overwrite the existing core-spec banner — add a sibling line for perps.

6. perps repo label

  • Create the perps GitHub label on TexasCoding/kalshi-python-sdk (gh label create perps --description "Perps (margin) API" --color <hex>). All perps issues should carry it. (This issue itself is labeled documentation, testing per the planned labels; the foundation/REST/WS issues carry perps.)

Resource methods

N/A — no new resource methods. See Deliverables checklist above.

Contract-test wiring

N/A for this issue — METHOD_ENDPOINT_MAP / BODY_MODEL_MAP / EXCLUSIONS entries are owned by the REST and WS feature issues, not here.

This issue only consumes the contract-test harness parameterization established by the foundation issue (loading the vendored specs/perps_openapi.yaml). Acceptance for this issue includes confirming the full suite — including the perps drift tests added upstream — is green after the docs/version changes. If the version bump or banner edits touch anything the drift tests read, fix forward; do not add EXCLUSIONS to paper over a real drift.

Tests

New file(s) under tests/integration/ (one per family is fine; e.g. tests/integration/test_perps_orders.py, test_perps_markets.py, test_perps_balance_risk.py, test_perps_funding.py, test_perps_ws.py). These are live demo tests, not respx unit tests — mirror the existing tests/integration/ style exactly:

  • Reuse tests/integration/conftest.py fixture conventions. Add perps client fixtures (perps_sync_client, perps_async_client) that build PerpsClient.from_env() / AsyncPerpsClient.from_env(), auto-skip when KALSHI_KEY_ID is unset (_credentials_available()), and hard-fail unless pointed at demo — extend _assert_demo_url (or add a perps analog) to assert external-api.demo.kalshi.co is the resolved base URL and external-api-margin-ws.demo.kalshi.co for WS. Reuse the conftest RSA / from_env env-bridging plumbing; do not duplicate it.
  • Gate exactly like existing live tests: @pytest.mark.integration, auto-skip without credentials. Use @pytest.mark.integration_real_api_only (the existing marker, skipped unless KALSHI_ENABLE_REAL_API_ONLY=1) for any perps endpoint the demo server cannot service (e.g. SCM/Klear, or margin endpoints requiring a margin-enabled demo account).
  • Add skip_if_* guards mirroring skip_if_low_balance for: account not margin-enabled (GetMarginEnabled returns false → skip order/balance tests), and demo having no margin markets (GetMarginMarkets empty → skip).
  • Register tested methods in tests/integration/coverage_harness.py. Since perps resources live in kalshi/perps/resources/*, add the perps resource module paths to RESOURCE_MODULES (or introduce a parallel registry) so test_coverage.py introspects them; otherwise perps methods are invisible to the coverage check. Call register("PerpsOrdersResource", [...]) etc. from each test file.

Per-family coverage (each at least one happy-path live call; mark order-mutating tests with cleanup):

  • orders: create a resting margin order (non-marketable price), assert it returns, then cancel (cleanup in an autouse session sweep mirroring cleanup_orders); list orders; get a single order.
  • markets: list margin markets, get one, fetch its orderbook and candlesticks.
  • balance/risk: balance() returns cash/position/total/maintenance-margin fields; risk() returns leverage + liquidation prices; enabled() boolean.
  • funding: funding_history, historical_funding_rates, funding_rate_estimate return without error and parse funding_rate as Decimal.
  • ws (async): connect to demo margin WS, subscribe ticker, receive at least one message, assert funding_rate parses and next_funding_time_ms is an int epoch-ms; mirror the ws_session fixture pattern.
  • Add a session-end autouse cleanup sweep for any resting perps orders tagged with the run id (mirror cleanup_orders + TEST_RUN_ID), so live order tests never leak.

Examples themselves are not part of CI unit tests, but add a lightweight import/syntax check (e.g. a tests/test_examples_importable.py that imports each examples/perps_*.py module without executing main()) so a broken example reds CI.

Acceptance criteria

  • README has a perps feature bullet + ## Perps (margin) trading section with sync and async quickstarts using PerpsClient / AsyncPerpsClient.
  • docs/perps.md created and added to mkdocs.yml nav; mkdocs build --strict passes (no broken links / orphan pages).
  • examples/ directory created with perps_create_order.py, perps_stream_ticker.py (funding), perps_balance_risk.py — each runnable, demo-defaulted, credential-via-from_env().
  • CHANGELOG.md has a new top entry; version in pyproject.toml and __version__ in kalshi/__init__.py bumped to the same new minor version.
  • README + docs/index.md banners updated with a perps line (operation/channel counts from the perps specs + perps spec version); existing core-spec banner left intact.
  • perps GitHub label created on the repo.
  • Demo integration tests added under tests/integration/ for every shipped perps family, gated by @pytest.mark.integration, auto-skipping without KALSHI_KEY_ID, hard-failing unless resolved to external-api.demo.kalshi.co (and the margin WS demo host). Order-mutating tests have a cleanup sweep.
  • Perps resource modules registered in coverage_harness.RESOURCE_MODULES (or a parallel registry) and register(...) called from each perps integration test file; test_coverage.py is green for perps resources.
  • Examples are import-checked in CI (tests/test_examples_importable.py).
  • uv run ruff check . clean (incl. new examples/ and tests).
  • uv run mypy kalshi/ strict clean (no perps-source changes here, but version-file edits must not regress); examples annotated enough to not break if mypy scope includes them, using builtins.list[T] if any example touches a resource .list() return inside a shadowed scope.
  • uv run pytest tests/ -v green including the perps contract/drift tests added by upstream issues (the docs/version edits must not red them).
  • No markdown trackers (TODOS/BACKLOG) added to the repo (per CLAUDE.md); all follow-ups go to GitHub Issues.

Dependencies

  • perps: foundation — PerpsClient/AsyncPerpsClient, PerpsConfig, spec vendoring & contract-test parameterization (provides the clients, vendored specs/perps_openapi.yaml / specs/perps_asyncapi.yaml, and the contract-test harness parameterization this issue's tests rely on).
  • Implicitly depends on the perps REST resource issues and the perps WebSocket issue landing first — this closeout documents and integration-tests their surface. Whichever families have not merged at the time this lands are scoped out of docs/examples/tests and noted as "pending".

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationperpsPerps / margin (perpetual futures) APItestingTest coverage

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions