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
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.23.0, 101 operations)
- OpenAPI spec: https://docs.kalshi.com/openapi.yaml (v3.24.0, 101 operations)
- 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ A professional, spec-first Python SDK for the [Kalshi](https://kalshi.com) predi
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Type checked: mypy strict](https://img.shields.io/badge/mypy-strict-blue.svg)](https://mypy.readthedocs.io/)

- **Full coverage** of the Kalshi REST API (101 operations across 19 resources, OpenAPI v3.23.0) and WebSocket API (12 typed `subscribe_*` channels + 2 escape-hatch).
- **Full coverage** of the Kalshi REST API (101 operations across 19 resources, OpenAPI v3.24.0) and WebSocket API (12 typed `subscribe_*` channels + 2 escape-hatch).
- **Perps (margin) API**: standalone `PerpsClient` / `AsyncPerpsClient` + `PerpsWebSocket` for the perpetual-futures exchange (34 REST operations, 6 WS channels), plus a `KlearClient` for the Self-Clearing-Member "Klear" settlement API (9 operations). See [Perps (margin) trading](#perps-margin-trading).
- **FIX protocol**: an async-first FIX engine (FIXT.1.1 / FIX50SP2) for both products — order-entry, drop-copy, market-data, post-trade (prediction), and RFQ (prediction) sessions (plus order-group management over the order-entry session) with typed message models, sequence recovery, and order-book / settlement reassembly. `from kalshi import FixClient` / `MarginFixClient`. See [FIX protocol](#fix-protocol-low-latency-trading).
- **V2 event-market orders**: `create_v2` / `amend_v2` / `decrease_v2` / `cancel_v2` plus batched variants on `/portfolio/events/orders/*` — the only order-write surface.
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
A professional, spec-first Python SDK for the [Kalshi](https://kalshi.com) prediction
markets API.

- **Full REST coverage** — 101 operations across 19 resources (OpenAPI v3.23.0),
- **Full REST coverage** — 101 operations across 19 resources (OpenAPI v3.24.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`
Expand Down
71 changes: 69 additions & 2 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,71 @@
# Migration

## v6 → v7.0.0

Syncs the SDK to OpenAPI/AsyncAPI spec **3.24.0**. One breaking change on the
subaccounts surface, one soft-deprecation, three new endpoints, and additive
field/param additions.

### Breaking: position-transfer price is fixed-point dollars, not integer cents

The per-contract price on `subaccounts.transfer_position()` (and the underlying
`ApplySubaccountPositionTransferRequest` / `SubaccountTransfer` models) is renamed
from **`price_cents`** (integer cents, 0–100) to **`price`** (`Decimal`,
fixed-point dollars, 0–1.0). Upstream renamed the wire field `price_cents` →
`price` (`FixedPointDollars`) in 3.24.0.

```python
from decimal import Decimal

# v6 (removed)
# client.subaccounts.transfer_position(
# client_transfer_id=..., from_subaccount=0, to_subaccount=1,
# market_ticker="MKT-A", side="yes", count=5, price_cents=55,
# )

# v7 — price is dollars, as a Decimal
client.subaccounts.transfer_position(
client_transfer_id=...,
from_subaccount=0,
to_subaccount=1,
market_ticker="MKT-A",
side="yes",
count=5,
price=Decimal("0.55"), # 55¢ cost basis
)
```

The old client-side `0–100` cap is gone. `price` uses `OrderPrice`, which guards
non-negativity and the `$0.0001` tick (matching `CreateOrderRequest`); the upper
bound is the server's to enforce.

### Deprecated: `exchange.announcements()`

Kalshi removed `GET /exchange/announcements` and the `Announcement` schema from
the spec in 3.24.0, so the live endpoint now 404s. `exchange.announcements()`
(sync + async) and the `Announcement` model are **retained** but emit a
`DeprecationWarning` — upstream has transiently dropped endpoints as publishing
glitches before, so the method is kept pending confirmation the removal is
permanent. A future major release removes them.

### Added

- **`communications.quotes.get_for_rfq(rfq_id, quote_id)`** (sync + async) —
`GET /communications/rfqs/{rfq_id}/quotes/{quote_id}`, the RFQ-scoped get-quote
(returns `GetQuoteResponse`, the same payload as the flat `quotes.get`).
- **`klear.margin.active_obligations()`** (sync + async) —
`GET /margin/active_obligations`, all currently-active settlement obligations.
- **`klear.margin.settlement_estimate_by_asset_class()`** (sync + async) —
`GET /margin/settlement_estimate_by_asset_class`, next-settlement estimates
keyed by asset class.
- **`SubaccountNettingConfig.exchange_index`** (`int`, required).
- **`portfolio.balance(*, exchange_index=...)`** — optional query param to target
a specific exchange shard (defaults to 0 server-side).
- **`ObligationEntry.asset_class`** (perps SCM / Klear; `Literal["Crypto"]`).

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

## v5 → v6.0.0

**Breaking: multivariate lookup-history is gone.** Kalshi removed the
Expand All @@ -24,7 +90,8 @@ Everything else in 6.0.0 is additive and needs no code changes:
subaccounts.
- `subaccounts.create()` gained an optional `exchange_index` argument.

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

## v4 → v5.0.0

Expand Down Expand Up @@ -435,7 +502,7 @@ instead. The endpoints still work; 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.)
entirely in 6.0.0 — see the [v5 → v6.0.0](#v5-v600) section above.)

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

Expand Down
3 changes: 2 additions & 1 deletion docs/pagination.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ There is **no** built-in 1000-page cap. If you want one, pass
A few list endpoints return a plain `list[T]`, not `Page[T]`:

- `client.series.list(...)` — flat list of series.
- `client.exchange.announcements()` — a flat list.
- `client.exchange.announcements()` — a flat list (deprecated in v7.0.0; the
endpoint was removed upstream and now 404s).
- `client.order_groups.list()` — no cursor.
- `client.account.limits()` / `client.exchange.status()` — single objects.
- `client.markets.bulk_orderbooks(...)` / `bulk_candlesticks(...)` — flat list of up to 100 items.
Expand Down
5 changes: 5 additions & 0 deletions docs/perps.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@ with KlearClient(admin_user_id="...", access_token="...", demo=True) as klear:
Credentials can also come from the environment via `KlearClient.from_env()` (reads
`KALSHI_KLEAR_ADMIN_USER_ID` / `KALSHI_KLEAR_ACCESS_TOKEN`).

New in spec v3.24.0: `klear.margin.active_obligations()` returns all
currently-active settlement obligations (the plural sibling of the single-obligation
`active_obligation()`), and `klear.margin.settlement_estimate_by_asset_class()`
returns next-settlement estimates keyed by asset class.

Money fields on the Klear margin schemas are integer **centicents** (`1 USD =
10,000 centicents`); only the withdrawal `amount` is a fixed-point dollar string.
`klear.margin.withdraw_settlement_balance(amount="500.00")` validates the amount as
Expand Down
13 changes: 10 additions & 3 deletions docs/resources/exchange.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Top-level exchange status, schedule, announcements, and your account's
|---|---|---|
| `status()` | `GET /exchange/status` | no |
| `schedule()` | `GET /exchange/schedule` | no |
| `announcements()` | `GET /exchange/announcements` | no |
| `announcements()` *(deprecated in v7.0.0 — 404s)* | `GET /exchange/announcements` | no |
| `user_data_timestamp()` | `GET /exchange/user_data_timestamp` | **yes** |

## Exchange status
Expand All @@ -36,9 +36,16 @@ for window in sched.maintenance_windows:

## Announcements

!!! warning "Deprecated in v7.0.0"
Kalshi removed `GET /exchange/announcements` and the `Announcement` schema
from the spec in 3.24.0, so the live endpoint now **404s**. `announcements()`
(sync + async) and the `Announcement` model are retained — each call emits a
`DeprecationWarning` — pending confirmation the removal is permanent, and will
be removed in a future major release.

```python
for a in client.exchange.announcements():
print(a.title, a.message, a.delivery_time)
for a in client.exchange.announcements(): # emits DeprecationWarning
print(a.type, a.message, a.delivery_time, a.status)
```

Plain list, not a `Page`.
Expand Down
5 changes: 3 additions & 2 deletions docs/resources/portfolio.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Auth required throughout.

| Method | Endpoint |
|---|---|
| `balance(*, subaccount=None)` | `GET /portfolio/balance` |
| `balance(*, subaccount=None, exchange_index=None)` | `GET /portfolio/balance` |
| `positions(*, ...)` | `GET /portfolio/positions` |
| `settlements(...)` / `settlements_all(...)` | `GET /portfolio/settlements` |
| `fills(...)` / `fills_all(...)` | `GET /portfolio/fills` |
Expand All @@ -18,7 +18,8 @@ Auth required throughout.
`balance()`, `positions()` / `positions_all()`, `settlements()` /
`settlements_all()`, and `fills()` / `fills_all()` all take an optional
`subaccount: int` to scope the read to a specific subaccount (omit for the
primary account).
primary account). `balance()` also takes an optional `exchange_index: int`
(spec v3.24.0) to target a specific exchange shard (defaults to 0 server-side).

## Balance

Expand Down
18 changes: 11 additions & 7 deletions docs/resources/subaccounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ primary; `1`–`63` are numbered extras. Auth required throughout.
|---|---|
| `create(*, exchange_index=None)` | `POST /portfolio/subaccounts` |
| `transfer(*, client_transfer_id, from_subaccount, to_subaccount, amount_cents)` | `POST /portfolio/subaccounts/transfer` |
| `transfer_position(*, client_transfer_id, from_subaccount, to_subaccount, market_ticker, side, count, price_cents)` | `POST /portfolio/subaccounts/positions/transfer` |
| `transfer_position(*, client_transfer_id, from_subaccount, to_subaccount, market_ticker, side, count, price)` | `POST /portfolio/subaccounts/positions/transfer` |
| `list_balances()` | `GET /portfolio/subaccounts/balances` |
| `list_transfers(*, cursor=None, limit=None)` | `GET /portfolio/subaccounts/transfers` |
| `list_all_transfers(*, limit=None, max_pages=None)` | walks `list_transfers` |
Expand Down Expand Up @@ -53,19 +53,21 @@ with the same id; the server dedupes.
## Transfer a position between subaccounts

Spec v3.23.0 added `transfer_position()` for moving open contracts (not cash)
between subaccounts. Unlike `transfer()`, it returns a
`position_transfer_id`. `price_cents` (0–100) sets the cost basis on the
destination:
between subaccounts. Unlike `transfer()`, it returns a `position_transfer_id`.
`price` (spec v3.24.0 renamed it from `price_cents`) is the per-contract cost
basis in **fixed-point dollars** (0–1.0) — pass a `Decimal`:

```python
from decimal import Decimal

resp = client.subaccounts.transfer_position(
client_transfer_id=uuid.uuid4(), # or str
from_subaccount=0,
to_subaccount=1,
market_ticker="KXBTC-25DEC31-B100000",
side="yes", # "yes" | "no"
count=10, # contracts (> 0)
price_cents=55, # per-contract cents, 0–100
price=Decimal("0.55"), # per-contract dollars, 0–1.0
)
print(resp.position_transfer_id)
```
Expand Down Expand Up @@ -101,8 +103,10 @@ Netting offsets positions across subaccounts so they consume one margin pool.

```python
client.subaccounts.update_netting(subaccount_number=1, enabled=True)
config = client.subaccounts.get_netting()
print(config.netting_enabled_subaccounts)
resp = client.subaccounts.get_netting()
for cfg in resp.netting_configs:
# `exchange_index` (int) added in spec v3.24.0.
print(cfg.subaccount_number, cfg.enabled, cfg.exchange_index)
```

## Reference
Expand Down