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
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,40 @@

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

## 7.4.0 — 2026-07-26

Reconciles upstream core OpenAPI content under version string **3.26.0**
(paths 92→93, 103→105 operations; 104 mapped) for the settlement-advance
subaccount surface (Closes #486). Additive only — no breaking public-API
removals.

### Added

- **`subaccounts.lock_settlement_advance()` / `unlock_settlement_advance()`**
(sync + async) — `PUT` / `DELETE`
`/portfolio/subaccounts/settlement-advance-lock`. Lock cancels resting
orders, prevents trading, and returns
`LockSubaccountForSettlementAdvanceResponse.settlement_advance_state`
(UUID CAS token). Unlock returns `None` (empty success body) and is
rejected while an outstanding settlement advance remains. Body:
required `subaccount_number`, optional `exchange_index`. Auth required.
Request models: `LockSubaccountForSettlementAdvanceRequest`,
`UnlockSubaccountForSettlementAdvanceRequest` (`extra="forbid"`).
- **`SubaccountBalance.voluntarily_locked`** (`bool`, required) — whether
the subaccount is voluntarily locked for settlement-advance computation.
- **`SubaccountBalance.settlement_advance`** (`DollarDecimal`, required) —
outstanding settlement advance in dollars.
- **`SubaccountBalance.settlement_advance_state`** (`UUID | None`) —
current CAS token when one has been established.

### Spec notes

- Core OpenAPI `info.version` still **3.26.0** (content-only change; paths
92→93, 105 operations / 104 mapped). Still unimplemented:
`POST /portfolio/intra_exchange_instance_transfer` (use
`PerpsClient.transfers.transfer_instance()` on the margin product).
- Perps OpenAPI / AsyncAPI / SCM specs unchanged for this release.

## 7.3.0 — 2026-07-23

Syncs the upstream core OpenAPI **3.25.0 → 3.26.0** and closes the remaining
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.26.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.26.0, 105 operations; 104 mapped in the core SDK — `POST /portfolio/intra_exchange_instance_transfer` is currently not available upstream)
- 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 (102 operations across 19 resources, OpenAPI v3.26.0) and WebSocket API (12 typed `subscribe_*` channels + 2 escape-hatch).
- **Full coverage** of the Kalshi REST API (104 operations across 19 resources, OpenAPI v3.26.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 (11 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
4 changes: 4 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Shipped

- **v7.4.0 (2026-07-26)** — OpenAPI 3.26.0 content reconcile (#486). Additive:
`subaccounts.lock_settlement_advance()` / `unlock_settlement_advance()`, and
`SubaccountBalance` settlement-advance fields (`voluntarily_locked`,
`settlement_advance`, `settlement_advance_state`).
- **v7.3.0 (2026-07-23)** — OpenAPI sync 3.25.0 → 3.26.0 (#484). Additive:
`historical.positions()` / `positions_all()` (`GET /historical/positions`),
`HistoricalCutoff.market_positions_last_updated_ts`, and Klear
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** — 102 operations across 19 resources (OpenAPI v3.26.0),
- **Full REST coverage** — 104 operations across 19 resources (OpenAPI v3.26.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
28 changes: 28 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# Migration

## v7.3 → v7.4.0

Reconciles upstream core OpenAPI content under version string **3.26.0** for
the settlement-advance subaccount surface (Closes #486). **No breaking
public-API removals.** Response parsing for `list_balances()` now expects the
new required balance fields from the live API.

### Added

- **`subaccounts.lock_settlement_advance()` / `unlock_settlement_advance()`**
(sync + async) — lock/unlock a subaccount for settlement-advance work.
- **`SubaccountBalance.voluntarily_locked`**, **`settlement_advance`**,
optional **`settlement_advance_state`**.

```python
lock = client.subaccounts.lock_settlement_advance(subaccount_number=1)
print(lock.settlement_advance_state)

resp = client.subaccounts.list_balances()
for bal in resp.subaccount_balances:
print(bal.voluntarily_locked, bal.settlement_advance)

client.subaccounts.unlock_settlement_advance(subaccount_number=1)
```

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

## v7.2 → v7.3.0

Syncs the SDK to core OpenAPI **3.26.0** and closes residual Klear settlement
Expand Down
3 changes: 3 additions & 0 deletions docs/request-models.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ exposed by each resource method stays in lockstep with the OpenAPI spec.
| `client.order_groups.create` | `CreateOrderGroupRequest` |
| `client.order_groups.update_limit` | `UpdateOrderGroupLimitRequest` |
| `client.subaccounts.transfer` | `ApplySubaccountTransferRequest` |
| `client.subaccounts.transfer_position` | `ApplySubaccountPositionTransferRequest` |
| `client.subaccounts.update_netting` | `UpdateSubaccountNettingRequest` |
| `client.subaccounts.lock_settlement_advance` | `LockSubaccountForSettlementAdvanceRequest` |
| `client.subaccounts.unlock_settlement_advance` | `UnlockSubaccountForSettlementAdvanceRequest` |

All are importable from the top-level `kalshi` package.

Expand Down
38 changes: 35 additions & 3 deletions docs/resources/subaccounts.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ primary; `1`–`63` are numbered extras. Auth required throughout.
| `list_all_transfers(*, limit=None, max_pages=None)` | walks `list_transfers` |
| `update_netting(*, subaccount_number, enabled)` | `PUT /portfolio/subaccounts/netting` |
| `get_netting()` | `GET /portfolio/subaccounts/netting` |
| `lock_settlement_advance(*, subaccount_number, exchange_index=None)` | `PUT /portfolio/subaccounts/settlement-advance-lock` |
| `unlock_settlement_advance(*, subaccount_number, exchange_index=None)` | `DELETE /portfolio/subaccounts/settlement-advance-lock` |

## Create a subaccount

Expand Down Expand Up @@ -77,11 +79,41 @@ print(resp.position_transfer_id)
```python
resp = client.subaccounts.list_balances()
for bal in resp.subaccount_balances:
print(bal.subaccount_number, bal.balance, bal.updated_ts)
print(
bal.subaccount_number,
bal.balance,
bal.updated_ts,
bal.voluntarily_locked,
bal.settlement_advance,
bal.settlement_advance_state,
)
```

`bal.balance` is a `DollarDecimal` (dollars). `bal.updated_ts` is Unix seconds
(not ISO datetime).
`bal.balance` and `bal.settlement_advance` are `DollarDecimal` (dollars).
`bal.updated_ts` is Unix seconds (not ISO datetime). `bal.voluntarily_locked`
is whether the subaccount is locked for settlement-advance computation;
`bal.settlement_advance_state` is the optional CAS token (`UUID | None`).

## Settlement advance lock

Lock a subaccount before settlement-advance work (cancels resting orders and
prevents trading). Unlock is rejected while an outstanding settlement advance
remains.

```python
lock = client.subaccounts.lock_settlement_advance(
subaccount_number=1,
exchange_index=0, # optional; defaults to 0 server-side
)
print(lock.settlement_advance_state) # UUID CAS token

# After the advance is cleared:
client.subaccounts.unlock_settlement_advance(subaccount_number=1)
```

Both methods also accept a pre-built request model
(`LockSubaccountForSettlementAdvanceRequest` /
`UnlockSubaccountForSettlementAdvanceRequest`). Auth required.

## List transfers

Expand Down
8 changes: 7 additions & 1 deletion kalshi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@
IncentiveProgramTypeLiteral,
IndexedBalance,
LiveData,
LockSubaccountForSettlementAdvanceRequest,
LockSubaccountForSettlementAdvanceResponse,
LookupTickersForMarketInMultivariateEventCollectionRequest,
LookupTickersResponse,
MaintenanceWindow,
Expand Down Expand Up @@ -164,6 +166,7 @@
TimeInForceLiteral,
TotalRestingOrderValue,
Trade,
UnlockSubaccountForSettlementAdvanceRequest,
UpdateOrderGroupLimitRequest,
UpdateSubaccountNettingRequest,
UserDataTimestamp,
Expand Down Expand Up @@ -311,6 +314,8 @@
"KlearClient",
"KlearConfig",
"LiveData",
"LockSubaccountForSettlementAdvanceRequest",
"LockSubaccountForSettlementAdvanceResponse",
"LookupTickersForMarketInMultivariateEventCollectionRequest",
"LookupTickersResponse",
"MaintenanceWindow",
Expand Down Expand Up @@ -371,6 +376,7 @@
"TimeInForceLiteral",
"TotalRestingOrderValue",
"Trade",
"UnlockSubaccountForSettlementAdvanceRequest",
"UpdateOrderGroupLimitRequest",
"UpdateSubaccountNettingRequest",
"UserDataTimestamp",
Expand All @@ -379,4 +385,4 @@
"Withdrawal",
]

__version__ = "7.3.0"
__version__ = "7.4.0"
18 changes: 17 additions & 1 deletion kalshi/_contract_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,10 @@ class ContractEntry:
ContractEntry(
sdk_model="kalshi.models.subaccounts.SubaccountBalance",
spec_schema="SubaccountBalance",
notes="balance uses DollarDecimal; updated_ts is Unix int",
notes=(
"balance + settlement_advance use DollarDecimal; updated_ts is Unix int; "
"settlement_advance_state is UUID | None"
),
),
ContractEntry(
sdk_model="kalshi.models.subaccounts.SubaccountTransfer",
Expand All @@ -182,6 +185,19 @@ class ContractEntry:
sdk_model="kalshi.models.subaccounts.ApplySubaccountPositionTransferResponse",
spec_schema="ApplySubaccountPositionTransferResponse",
),
ContractEntry(
sdk_model="kalshi.models.subaccounts.LockSubaccountForSettlementAdvanceRequest",
spec_schema="LockSubaccountForSettlementAdvanceRequest",
),
ContractEntry(
sdk_model="kalshi.models.subaccounts.LockSubaccountForSettlementAdvanceResponse",
spec_schema="LockSubaccountForSettlementAdvanceResponse",
notes="settlement_advance_state is UUID",
),
ContractEntry(
sdk_model="kalshi.models.subaccounts.UnlockSubaccountForSettlementAdvanceRequest",
spec_schema="UnlockSubaccountForSettlementAdvanceRequest",
),
ContractEntry(
sdk_model="kalshi.models.subaccounts.CreateSubaccountRequest",
spec_schema="CreateSubaccountRequest",
Expand Down
6 changes: 6 additions & 0 deletions kalshi/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,12 @@
CreateSubaccountResponse,
GetSubaccountBalancesResponse,
GetSubaccountNettingResponse,
LockSubaccountForSettlementAdvanceRequest,
LockSubaccountForSettlementAdvanceResponse,
SubaccountBalance,
SubaccountNettingConfig,
SubaccountTransfer,
UnlockSubaccountForSettlementAdvanceRequest,
UpdateSubaccountNettingRequest,
)

Expand Down Expand Up @@ -266,6 +269,8 @@
"IncentiveProgramTypeLiteral",
"IndexedBalance",
"LiveData",
"LockSubaccountForSettlementAdvanceRequest",
"LockSubaccountForSettlementAdvanceResponse",
"LookupTickersForMarketInMultivariateEventCollectionRequest",
"LookupTickersResponse",
"MaintenanceWindow",
Expand Down Expand Up @@ -318,6 +323,7 @@
"TimeInForceLiteral",
"TotalRestingOrderValue",
"Trade",
"UnlockSubaccountForSettlementAdvanceRequest",
"UpdateOrderGroupLimitRequest",
"UpdateSubaccountNettingRequest",
"UserDataTimestamp",
Expand Down
49 changes: 49 additions & 0 deletions kalshi/models/subaccounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,22 @@ class SubaccountBalance(BaseModel):
``format: date-time`` and surface as ``datetime``; subaccount
timestamps follow the spec's int wire format. Callers wanting a
``datetime`` can ``datetime.fromtimestamp(obj.updated_ts, tz=timezone.utc)``.

Spec content under OpenAPI 3.26.0 (2026-07-25) added settlement-advance
fields: ``voluntarily_locked`` / ``settlement_advance`` (required) and
optional ``settlement_advance_state`` (CAS token from
:meth:`~kalshi.resources.subaccounts.SubaccountsResource.lock_settlement_advance`).
"""

subaccount_number: int
# Spec v3.22.0: exchange shard the balance is held on (required).
exchange_index: int
balance: DollarDecimal
updated_ts: int
# Settlement-advance surface (OpenAPI 3.26.0 content, 2026-07-25).
voluntarily_locked: bool
settlement_advance: DollarDecimal
settlement_advance_state: UUID | None = None

model_config = {"extra": "allow"}

Expand All @@ -124,6 +133,46 @@ class GetSubaccountBalancesResponse(BaseModel):
model_config = {"extra": "allow"}


class LockSubaccountForSettlementAdvanceRequest(BaseModel):
"""Body for PUT /portfolio/subaccounts/settlement-advance-lock.

Locks a subaccount for settlement-advance computation (cancels resting
orders and prevents trading). ``subaccount_number`` uses ``0`` for the
primary account; ``exchange_index`` defaults to ``0`` when omitted.
"""

subaccount_number: StrictInt = Field(ge=0)
exchange_index: StrictInt | None = Field(default=None, ge=0)

model_config = {"extra": "forbid"}


class LockSubaccountForSettlementAdvanceResponse(BaseModel):
"""Response from PUT /portfolio/subaccounts/settlement-advance-lock.

``settlement_advance_state`` is the new compare-and-swap token for
subsequent settlement-advance requests.
"""

settlement_advance_state: UUID

model_config = {"extra": "allow"}


class UnlockSubaccountForSettlementAdvanceRequest(BaseModel):
"""Body for DELETE /portfolio/subaccounts/settlement-advance-lock.

Unlock is rejected while the subaccount has an outstanding settlement
advance. Same ``subaccount_number`` / ``exchange_index`` semantics as
:class:`LockSubaccountForSettlementAdvanceRequest`.
"""

subaccount_number: StrictInt = Field(ge=0)
exchange_index: StrictInt | None = Field(default=None, ge=0)

model_config = {"extra": "forbid"}


class SubaccountTransfer(BaseModel):
"""A past **cash** transfer between subaccounts.

Expand Down
Loading
Loading