Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,47 @@

All notable changes to kalshi-sdk will be documented in this file.

## 10.0.0 — 2026-08-06

Reconciles upstream OpenAPI **3.27.0** content drift plus AsyncAPI / perps
OpenAPI changes (Closes #496, #497). **Breaking** for callers of multivariate
lookup (REST + WS).

### Removed (breaking)

- **`multivariate_collections.lookup_tickers()`** (sync + async) and models
`LookupTickersForMarketInMultivariateEventCollectionRequest` /
`LookupTickersResponse`. Upstream deleted
`PUT /multivariate_event_collections/{collection_ticker}/lookup` and the
matching schemas. `create_market()` remains (still deprecated).
- **WS `subscribe_multivariate()`** plus `MultivariateMessage` /
`MultivariatePayload` / `SelectedMarket`. AsyncAPI removed the
`multivariate` channel and `multivariateLookupPayload` schema.
`subscribe_multivariate_lifecycle()` is unchanged.

### Added

- **`portfolio.intra_exchange_transfers()`** /
**`intra_exchange_transfers_all()`** /
**`get_intra_exchange_transfer(transfer_id)`** (sync + async) —
`GET /portfolio/intra_exchange_instance_transfers` and
`GET /portfolio/intra_exchange_instance_transfers/{transfer_id}`.
Model: `IntraExchangeInstanceTransfer` (`amount` is fixed-point dollars).
Complements `PerpsClient.transfers.transfer_instance()` (POST create).
- **`MultivariateEventCollection.exchange_index`** (`int | None`) — optional
exchange shard inherited from the collection's series.
- **Perps** `MarginMarket.long_leverage_estimates` /
`short_leverage_estimates` (`dict[str, MultiplierDecimal] | None`).

### Spec notes

- Core OpenAPI `info.version` still **3.27.0** (paths 92→92; 103→104 operations;
103 mapped). Still unimplemented on the core client:
`POST /portfolio/intra_exchange_instance_transfer` (use
`PerpsClient.transfers.transfer_instance()`).
- AsyncAPI: channels 15→14 (`multivariate` removed).
- Perps OpenAPI: additive optional leverage side maps on `MarginMarket`.

## 9.0.0 — 2026-07-31

Syncs upstream core OpenAPI **3.26.0 → 3.27.0** (paths stay 92; 103 operations /
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ tests/

## API Reference

- OpenAPI spec: https://docs.kalshi.com/openapi.yaml (v3.27.0, 103 operations; 102 mapped in the core SDK — `POST /portfolio/intra_exchange_instance_transfer` is currently not available upstream)
- OpenAPI spec: https://docs.kalshi.com/openapi.yaml (v3.27.0, 104 operations; 103 mapped in the core SDK — `POST /portfolio/intra_exchange_instance_transfer` is implemented on `PerpsClient.transfers.transfer_instance` and left unimplemented on the core client)
- AsyncAPI spec: https://docs.kalshi.com/asyncapi.yaml (13 WebSocket channels)
- Base URL: https://api.elections.kalshi.com/trade-api/v2
- Demo URL: https://demo-api.kalshi.co/trade-api/v2
Expand Down
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,13 +171,12 @@ async def main() -> None:
asyncio.run(main())
```

Available channels (12 typed + 2 escape-hatch). Twelve have dedicated
Available channels (11 typed + 2 escape-hatch). Eleven have dedicated
`subscribe_*` methods — `subscribe_ticker`, `subscribe_trade`,
`subscribe_orderbook_delta`, `subscribe_fill`, `subscribe_market_positions`,
`subscribe_user_orders`, `subscribe_order_group`,
`subscribe_market_lifecycle`, `subscribe_multivariate`,
`subscribe_multivariate_lifecycle`, `subscribe_communications`,
`subscribe_cfbenchmarks_value`. The
`subscribe_market_lifecycle`, `subscribe_multivariate_lifecycle`,
`subscribe_communications`, `subscribe_cfbenchmarks_value`. The
AsyncAPI-declared `control_frames` and `root` channels are reachable
through the generic `subscribe(channel, ...)` escape hatch. See
[docs/websockets.md](docs/websockets.md#the-12-channels) for the full
Expand Down
7 changes: 7 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

## Shipped

- **v10.0.0 (2026-08-06)** — Spec-drift reconcile (#496 / #497). **Breaking:**
removed `multivariate_collections.lookup_tickers()` and WS
`subscribe_multivariate()` after upstream deleted the REST lookup endpoint
and AsyncAPI `multivariate` channel. Additive:
`portfolio.intra_exchange_transfers()` / `get_intra_exchange_transfer()`,
`MultivariateEventCollection.exchange_index`, perps
`MarginMarket.long_leverage_estimates` / `short_leverage_estimates`.
- **v9.0.0 (2026-07-31)** — OpenAPI sync 3.26.0 → 3.27.0 (#492). **Breaking:**
removed `subaccounts.transfer_position()` after upstream deleted position
transfers. Additive: `live_data.get_event()`,
Expand Down
7 changes: 4 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
A professional, spec-first Python SDK for the [Kalshi](https://kalshi.com) prediction
markets API.

- **Full REST coverage** — 102 operations across 19 resources (OpenAPI v3.27.0),
- **Full REST coverage** — 103 operations across 19 resources (OpenAPI v3.27.0),
every kwarg drift-tested against the spec.
- **V2 event-market orders** — new `create_v2` / `amend_v2` / `decrease_v2` /
`cancel_v2` family on `/portfolio/events/orders/*`. Legacy `/portfolio/orders`
keeps working; deprecation no earlier than May 6, 2026.
- **Funding + cost introspection** — `portfolio.deposits()`,
`portfolio.withdrawals()`, `account.endpoint_costs()`.
- **Full WebSocket coverage** — 12 channels with sequence-gap detection, automatic
`portfolio.withdrawals()`, `portfolio.intra_exchange_transfers()`,
`account.endpoint_costs()`.
- **Full WebSocket coverage** — 11 channels with sequence-gap detection, automatic
reconnection (with resubscribe-window frame stashing for high-volume channels),
backpressure strategies, and an in-memory orderbook builder. Async-only —
access via `AsyncKalshiClient.ws`.
Expand Down
53 changes: 46 additions & 7 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,45 @@
# Migration

## v9.0 → v10.0.0

Reconciles upstream OpenAPI **3.27.0** content (paths still 92; +2 GET
transfer-history ops), AsyncAPI removal of the `multivariate` channel, and
perps `MarginMarket` leverage side maps (Closes #496, #497). **Breaking** for
callers of multivariate lookup (REST + WS).

### Removed

- **`multivariate_collections.lookup_tickers()`** (sync + async) and
`LookupTickersForMarketInMultivariateEventCollectionRequest` /
`LookupTickersResponse`. Upstream deleted
`PUT /multivariate_event_collections/{collection_ticker}/lookup`.
- **WS `subscribe_multivariate()`** and `MultivariateMessage` /
`MultivariatePayload`. Use RFQs for new multivariate integrations; lifecycle
remains on `subscribe_multivariate_lifecycle()`.

```python
# No longer available — the upstream REST endpoint and WS channel are gone:
# client.multivariate_collections.lookup_tickers("MVC-1", selected_markets=[...])
# await ws.subscribe_multivariate()

# create_market is still present (deprecated; predates RFQs):
# client.multivariate_collections.create_market(...)
```

### Added (non-breaking)

- **`portfolio.intra_exchange_transfers()`** /
**`intra_exchange_transfers_all()`** /
**`get_intra_exchange_transfer(transfer_id)`** — history/detail for
event↔margined fund moves. Create transfers still via
`PerpsClient.transfers.transfer_instance()`.
- **`MultivariateEventCollection.exchange_index`** (optional).
- **Perps** `MarginMarket.long_leverage_estimates` /
`short_leverage_estimates` (optional).

See the [changelog](https://github.com/TexasCoding/kalshi-python-sdk/blob/main/CHANGELOG.md)
for the full list.

## v8.0 → v9.0.0

Syncs the SDK to core OpenAPI **3.27.0** (and the matching perps / SCM
Expand Down Expand Up @@ -713,14 +753,13 @@ for position in client.portfolio.positions_all():

### Multivariate endpoints emit `DeprecationWarning`

Per #269, `multivariate.lookup_tickers` and `multivariate.create_market`
(sync + async) carry `@typing_extensions.deprecated` decorators citing
the spec's "should not be used for new integrations" guidance. Use RFQs
instead. The endpoints still work; calls just emit a `DeprecationWarning`
on first use.
Per #269, `multivariate.create_market` (sync + async) carries a
`@typing_extensions.deprecated` decorator citing the spec's "should not be
used for new integrations" guidance. Use RFQs instead. The endpoint still
works; calls just emit a `DeprecationWarning` on first use.

(`multivariate.lookup_history`, also deprecated here in #269, was removed
entirely in 6.0.0 — see the [v5 → v6.0.0](#v5-v600) section above.)
(`multivariate.lookup_history` was removed in 6.0.0;
`multivariate.lookup_tickers` was removed in 10.0.0 — see the sections above.)

### `orders.list(event_ticker=...)` accepts lists

Expand Down
2 changes: 0 additions & 2 deletions docs/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ every exception class.

::: kalshi.models.multivariate.CreateMarketInMultivariateEventCollectionRequest

::: kalshi.models.multivariate.LookupTickersForMarketInMultivariateEventCollectionRequest

::: kalshi.models.order_groups.CreateOrderGroupRequest

::: kalshi.models.order_groups.UpdateOrderGroupLimitRequest
Expand Down
1 change: 0 additions & 1 deletion docs/request-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ exposed by each resource method stays in lockstep with the OpenAPI spec.
| `client.communications.block_trade_proposals.create` | `ProposeBlockTradeRequest` |
| `client.communications.block_trade_proposals.accept` | `AcceptBlockTradeProposalRequest` |
| `client.multivariate_collections.create_market` | `CreateMarketInMultivariateEventCollectionRequest` |
| `client.multivariate_collections.lookup_tickers` | `LookupTickersForMarketInMultivariateEventCollectionRequest` |
| `client.order_groups.create` | `CreateOrderGroupRequest` |
| `client.order_groups.update_limit` | `UpdateOrderGroupLimitRequest` |
| `client.subaccounts.transfer` | `ApplySubaccountTransferRequest` |
Expand Down
33 changes: 13 additions & 20 deletions docs/resources/multivariate.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,18 @@ Public listing, auth-required minting. Attribute name on the client:
`multivariate_collections`.

!!! warning "Deprecated methods"
`create_market()` and `lookup_tickers()` are deprecated — "This endpoint
predates RFQs and should not be used for new integrations." Calling them
emits a `DeprecationWarning`. Use the
[Communications (RFQ/Quote)](communications.md) surface instead. `list()` /
`list_all()` / `get()` remain supported.
`create_market()` is deprecated — "This endpoint predates RFQs and should
not be used for new integrations." Calling it emits a `DeprecationWarning`.
Use the [Communications (RFQ/Quote)](communications.md) surface instead.
`list()` / `list_all()` / `get()` remain supported.

!!! danger "Removed in 10.0.0"
`lookup_tickers()` and the
`LookupTickersForMarketInMultivariateEventCollectionRequest` /
`LookupTickersResponse` models were removed — Kalshi deleted
`PUT /multivariate_event_collections/{ticker}/lookup` from the OpenAPI
spec, and the AsyncAPI `multivariate` / `multivariate_lookup` channel
with it.

!!! danger "Removed in 6.0.0"
`lookup_history()` and the `LookupPoint` model were removed — Kalshi deleted
Expand All @@ -27,7 +34,6 @@ Public listing, auth-required minting. Attribute name on the client:
| `list(...)` / `list_all(...)` | `GET /multivariate_event_collections` | no |
| `get(collection_ticker)` | `GET /multivariate_event_collections/{ticker}` | no |
| `create_market(collection_ticker, *, selected_markets, with_market_payload=False)` | `POST /multivariate_event_collections/{ticker}` | yes |
| `lookup_tickers(collection_ticker, *, selected_markets)` | `PUT /multivariate_event_collections/{ticker}/lookup` | yes |

## List collections

Expand All @@ -38,7 +44,7 @@ page = client.multivariate_collections.list(
limit=100,
)
for c in page:
print(c.collection_ticker, c.title)
print(c.collection_ticker, c.title, c.exchange_index)
```

## Select legs
Expand All @@ -55,19 +61,6 @@ legs = [
]
```

## Lookup the auto-generated ticker (no mint)

```python
resp = client.multivariate_collections.lookup_tickers(
"KXWEATHER-SPORTS-COMBO",
selected_markets=legs,
)
print(resp.market_ticker, resp.event_ticker)
```

Wire-level note: this endpoint is a `PUT` — unusual for a read operation, but
matches the OpenAPI spec.

## Mint a combo market

```python
Expand Down
25 changes: 25 additions & 0 deletions docs/resources/portfolio.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Auth required throughout.
| `total_resting_order_value()` | `GET /portfolio/summary/total_resting_order_value` (FCM only) |
| `deposits(*, limit, cursor)` / `deposits_all(*, limit, max_pages)` | `GET /portfolio/deposits` |
| `withdrawals(*, limit, cursor)` / `withdrawals_all(*, limit, max_pages)` | `GET /portfolio/withdrawals` |
| `intra_exchange_transfers(...)` / `intra_exchange_transfers_all(...)` | `GET /portfolio/intra_exchange_instance_transfers` |
| `get_intra_exchange_transfer(transfer_id)` | `GET /portfolio/intra_exchange_instance_transfers/{transfer_id}` |

`balance()`, `positions()` / `positions_all()`, `settlements()` /
`settlements_all()`, and `fills()` / `fills_all()` all take an optional
Expand Down Expand Up @@ -186,6 +188,29 @@ which is `None` until the transfer settles.

Both `*_all` variants accept `max_pages=N` to bound iteration.

## Intra-exchange instance transfers

New in v10.0.0. History and detail for fund moves between the
`event_contract` and `margined` exchange instances. **Creating** a transfer
is still on the perps surface
(`PerpsClient.transfers.transfer_instance()`); these GETs are on the core
portfolio API.

```python
page = client.portfolio.intra_exchange_transfers(limit=50)
for t in page:
print(t.transfer_id, t.source, t.destination, t.amount, t.status)

for t in client.portfolio.intra_exchange_transfers_all():
...

t = client.portfolio.get_intra_exchange_transfer("xfer-...")
print(t.status, t.created_ts)
```

`IntraExchangeInstanceTransfer.amount` is a fixed-point dollar
`DollarDecimal` (not the integer centicents used on the POST create body).

## Position fields

`MarketPosition` and `EventPosition` use the standard `_dollars` / `_fp`
Expand Down
7 changes: 3 additions & 4 deletions docs/websockets.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,14 @@ SDK's perspective on it.
on every delta.
- `on_state_change=` and `on_error=` hooks on the constructor for observability.

## The 12 channels
## The 11 channels

| SDK method | Wire channel | Message `type` field | Message class | Auth |
|---|---|---|---|---|
| `subscribe_ticker` | `ticker` | `ticker` | `TickerMessage` | public |
| `subscribe_trade` | `trade` | `trade` | `TradeMessage` | public |
| `subscribe_orderbook_delta` | `orderbook_delta` | `orderbook_snapshot` → `orderbook_delta` | `OrderbookSnapshotMessage` / `OrderbookDeltaMessage` | public |
| `subscribe_market_lifecycle` | `market_lifecycle_v2` | `market_lifecycle_v2` / `event_fee_update` | `MarketLifecycleMessage` / `EventFeeUpdateMessage` | public |
| `subscribe_multivariate` | `multivariate` | `multivariate_lookup` | `MultivariateMessage` | public |
| `subscribe_multivariate_lifecycle` | `multivariate_market_lifecycle` | `multivariate_market_lifecycle` | `MultivariateLifecycleMessage` | public |
| `subscribe_fill` | `fill` | `fill` | `FillMessage` | private |
| `subscribe_user_orders` | `user_orders` | `user_order` (singular) | `UserOrdersMessage` | private |
Expand All @@ -47,8 +46,8 @@ SDK's perspective on it.
| `subscribe_cfbenchmarks_value` | `cfbenchmarks_value` | `cfbenchmarks_value` / `cfbenchmarks_value_indexlist` | `CFBenchmarksValueMessage` / `CFBenchmarksIndexListMessage` | private |

The `type` column matters when filtering raw logs — note the singular forms
for `user_order`, `market_position`, and the `multivariate_lookup` /
`multivariate` mismatch.
for `user_order` and `market_position`. The standalone `multivariate` /
`multivariate_lookup` channel was removed from AsyncAPI (SDK v10.0.0).

!!! warning "Migration (v3.1.0): `event_fee_update` rides `market_lifecycle_v2`"
Since the v3.20.0 spec sync (SDK v3.1.0) the `market_lifecycle_v2` channel
Expand Down
12 changes: 7 additions & 5 deletions kalshi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
EventPosition,
EventStatusLiteral,
ExchangeIndexStatus,
ExchangeInstanceLiteral,
ExchangeStatus,
Fill,
ForecastPercentilesPoint,
Expand Down Expand Up @@ -111,9 +112,9 @@
IncentiveProgramStatusLiteral,
IncentiveProgramTypeLiteral,
IndexedBalance,
IntraExchangeInstanceTransfer,
IntraExchangeInstanceTransferStatusLiteral,
LiveData,
LookupTickersForMarketInMultivariateEventCollectionRequest,
LookupTickersResponse,
MaintenanceWindow,
Market,
MarketCandlesticks,
Expand Down Expand Up @@ -253,6 +254,7 @@
"EventPosition",
"EventStatusLiteral",
"ExchangeIndexStatus",
"ExchangeInstanceLiteral",
"ExchangeStatus",
"Fill",
"FixClient",
Expand Down Expand Up @@ -288,6 +290,8 @@
"IncentiveProgramStatusLiteral",
"IncentiveProgramTypeLiteral",
"IndexedBalance",
"IntraExchangeInstanceTransfer",
"IntraExchangeInstanceTransferStatusLiteral",
"KalshiAuth",
"KalshiAuthError",
"KalshiBackpressureError",
Expand All @@ -311,8 +315,6 @@
"KlearClient",
"KlearConfig",
"LiveData",
"LookupTickersForMarketInMultivariateEventCollectionRequest",
"LookupTickersResponse",
"MaintenanceWindow",
"MarginFixClient",
"Market",
Expand Down Expand Up @@ -379,4 +381,4 @@
"Withdrawal",
]

__version__ = "9.0.0"
__version__ = "10.0.0"
Loading
Loading