From 84dc4ada8017b340d93f7bf88c06d3d1698854f9 Mon Sep 17 00:00:00 2001 From: Jeff West Date: Mon, 27 Jul 2026 18:47:42 -0500 Subject: [PATCH] Reconcile OpenAPI/AsyncAPI settlement-advance removal (v8.0.0) Upstream removed PUT/DELETE /portfolio/subaccounts/settlement-advance-lock and the SubaccountBalance settlement-advance fields from OpenAPI 3.26.0 content. Drop the matching SDK methods, models, and contract map entries. Add optional WS quote rfq_creator_id/subaccount fields from AsyncAPI. Closes #489 Closes #490 --- CHANGELOG.md | 36 +++++ CLAUDE.md | 2 +- README.md | 2 +- ROADMAP.md | 6 + docs/index.md | 2 +- docs/migration.md | 37 +++++ docs/request-models.md | 2 - docs/resources/subaccounts.md | 39 +---- kalshi/__init__.py | 8 +- kalshi/_contract_map.py | 18 +-- kalshi/models/__init__.py | 6 - kalshi/models/subaccounts.py | 49 ------- kalshi/resources/subaccounts.py | 211 --------------------------- kalshi/ws/models/communications.py | 8 ++ pyproject.toml | 2 +- specs/asyncapi.yaml | 35 +++++ specs/openapi.yaml | 131 ----------------- tests/_contract_support.py | 45 ------ tests/test_contracts.py | 6 - tests/test_models.py | 20 --- tests/test_subaccounts.py | 221 ----------------------------- 21 files changed, 132 insertions(+), 754 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c467a00..1d33f25f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,42 @@ All notable changes to kalshi-sdk will be documented in this file. +## 8.0.0 — 2026-07-27 + +Reconciles upstream core OpenAPI / AsyncAPI content under version string +**3.26.0** (paths 93→92, 105→103 operations; 102 mapped) after Kalshi removed +the short-lived settlement-advance subaccount surface (Closes #489, #490). +**Breaking** for callers that adopted the v7.4.0 settlement-advance API. + +### Removed (breaking) + +- **`subaccounts.lock_settlement_advance()` / `unlock_settlement_advance()`** + (sync + async) and request/response models + `LockSubaccountForSettlementAdvanceRequest`, + `LockSubaccountForSettlementAdvanceResponse`, + `UnlockSubaccountForSettlementAdvanceRequest`. Upstream deleted + `PUT`/`DELETE` `/portfolio/subaccounts/settlement-advance-lock` and the + matching schemas from OpenAPI 3.26.0 content. +- **`SubaccountBalance.voluntarily_locked`**, **`settlement_advance`**, and + **`settlement_advance_state`** — also dropped from the upstream + `SubaccountBalance` schema. `list_balances()` responses no longer include + these fields. + +### Added + +- **WebSocket quote payloads** (AsyncAPI content): optional + `rfq_creator_id` and `subaccount` on `QuoteCreatedPayload` / + `QuoteAcceptedPayload`, and optional `subaccount` on + `QuoteExecutedPayload` (own subaccount only; never the counterparty's). + +### Spec notes + +- Core OpenAPI `info.version` still **3.26.0** (content-only change; paths + 93→92, 103 operations / 102 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.4.0 — 2026-07-26 Reconciles upstream core OpenAPI content under version string **3.26.0** diff --git a/CLAUDE.md b/CLAUDE.md index f4afa172..a6c536c1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -122,7 +122,7 @@ tests/ ## API Reference -- 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) +- 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) - 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 diff --git a/README.md b/README.md index 27e9fefd..53b36ac7 100644 --- a/README.md +++ b/README.md @@ -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 (104 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 (102 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. diff --git a/ROADMAP.md b/ROADMAP.md index 0df5a5c1..06445f92 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -2,6 +2,12 @@ ## Shipped +- **v8.0.0 (2026-07-27)** — Spec-drift reconcile under OpenAPI 3.26.0 + (#489 / #490). **Breaking:** removed the settlement-advance subaccount + surface added in v7.4.0 (`lock_settlement_advance` / + `unlock_settlement_advance` + models + `SubaccountBalance` advance fields) + after upstream deleted the endpoint. Additive: WS quote payload + `rfq_creator_id` / `subaccount` fields. - **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`, diff --git a/docs/index.md b/docs/index.md index 7136c3e9..5fe11057 100644 --- a/docs/index.md +++ b/docs/index.md @@ -3,7 +3,7 @@ A professional, spec-first Python SDK for the [Kalshi](https://kalshi.com) prediction markets API. -- **Full REST coverage** — 104 operations across 19 resources (OpenAPI v3.26.0), +- **Full REST coverage** — 102 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` diff --git a/docs/migration.md b/docs/migration.md index 510a80c6..271fc982 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -1,5 +1,42 @@ # Migration +## v7.4 → v8.0.0 + +Reconciles upstream core OpenAPI / AsyncAPI content under version string +**3.26.0** after Kalshi removed the settlement-advance subaccount surface +(Closes #489, #490). **Breaking** for callers that adopted the v7.4.0 +settlement-advance API (methods, request models, and balance fields). + +### Removed + +- **`subaccounts.lock_settlement_advance()` / `unlock_settlement_advance()`** + (sync + async) and + `LockSubaccountForSettlementAdvanceRequest` / + `LockSubaccountForSettlementAdvanceResponse` / + `UnlockSubaccountForSettlementAdvanceRequest`. +- **`SubaccountBalance.voluntarily_locked`**, **`settlement_advance`**, + **`settlement_advance_state`**. + +```python +# No longer available — the upstream endpoints 404: +# client.subaccounts.lock_settlement_advance(subaccount_number=1) +# client.subaccounts.unlock_settlement_advance(subaccount_number=1) + +resp = client.subaccounts.list_balances() +for bal in resp.subaccount_balances: + print(bal.subaccount_number, bal.balance, bal.updated_ts) + # bal.voluntarily_locked / bal.settlement_advance removed +``` + +### Added (non-breaking) + +- Optional **`rfq_creator_id`** / **`subaccount`** on WS + `QuoteCreatedPayload` / `QuoteAcceptedPayload`, and optional + **`subaccount`** on `QuoteExecutedPayload`. + +See the [changelog](https://github.com/TexasCoding/kalshi-python-sdk/blob/main/CHANGELOG.md) +for the full list. + ## v7.3 → v7.4.0 Reconciles upstream core OpenAPI content under version string **3.26.0** for diff --git a/docs/request-models.md b/docs/request-models.md index e7e8ad4e..a79123eb 100644 --- a/docs/request-models.md +++ b/docs/request-models.md @@ -70,8 +70,6 @@ exposed by each resource method stays in lockstep with the OpenAPI spec. | `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. diff --git a/docs/resources/subaccounts.md b/docs/resources/subaccounts.md index 3914067f..c750e976 100644 --- a/docs/resources/subaccounts.md +++ b/docs/resources/subaccounts.md @@ -15,8 +15,6 @@ 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 @@ -79,41 +77,12 @@ 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, - bal.voluntarily_locked, - bal.settlement_advance, - bal.settlement_advance_state, - ) + print(bal.subaccount_number, bal.balance, bal.updated_ts, bal.exchange_index) ``` -`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. +`bal.balance` is `DollarDecimal` (dollars). `bal.updated_ts` is Unix seconds +(not ISO datetime). `bal.exchange_index` is the exchange shard the balance is +held on. ## List transfers diff --git a/kalshi/__init__.py b/kalshi/__init__.py index 8c67feb9..c8045161 100644 --- a/kalshi/__init__.py +++ b/kalshi/__init__.py @@ -112,8 +112,6 @@ IncentiveProgramTypeLiteral, IndexedBalance, LiveData, - LockSubaccountForSettlementAdvanceRequest, - LockSubaccountForSettlementAdvanceResponse, LookupTickersForMarketInMultivariateEventCollectionRequest, LookupTickersResponse, MaintenanceWindow, @@ -166,7 +164,6 @@ TimeInForceLiteral, TotalRestingOrderValue, Trade, - UnlockSubaccountForSettlementAdvanceRequest, UpdateOrderGroupLimitRequest, UpdateSubaccountNettingRequest, UserDataTimestamp, @@ -314,8 +311,6 @@ "KlearClient", "KlearConfig", "LiveData", - "LockSubaccountForSettlementAdvanceRequest", - "LockSubaccountForSettlementAdvanceResponse", "LookupTickersForMarketInMultivariateEventCollectionRequest", "LookupTickersResponse", "MaintenanceWindow", @@ -376,7 +371,6 @@ "TimeInForceLiteral", "TotalRestingOrderValue", "Trade", - "UnlockSubaccountForSettlementAdvanceRequest", "UpdateOrderGroupLimitRequest", "UpdateSubaccountNettingRequest", "UserDataTimestamp", @@ -385,4 +379,4 @@ "Withdrawal", ] -__version__ = "7.4.0" +__version__ = "8.0.0" diff --git a/kalshi/_contract_map.py b/kalshi/_contract_map.py index ccc72bc0..bfdbbe4a 100644 --- a/kalshi/_contract_map.py +++ b/kalshi/_contract_map.py @@ -160,10 +160,7 @@ class ContractEntry: ContractEntry( sdk_model="kalshi.models.subaccounts.SubaccountBalance", spec_schema="SubaccountBalance", - notes=( - "balance + settlement_advance use DollarDecimal; updated_ts is Unix int; " - "settlement_advance_state is UUID | None" - ), + notes="balance uses DollarDecimal; updated_ts is Unix int", ), ContractEntry( sdk_model="kalshi.models.subaccounts.SubaccountTransfer", @@ -185,19 +182,6 @@ 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", diff --git a/kalshi/models/__init__.py b/kalshi/models/__init__.py index 67b9eaa6..3c1907a0 100644 --- a/kalshi/models/__init__.py +++ b/kalshi/models/__init__.py @@ -172,12 +172,9 @@ CreateSubaccountResponse, GetSubaccountBalancesResponse, GetSubaccountNettingResponse, - LockSubaccountForSettlementAdvanceRequest, - LockSubaccountForSettlementAdvanceResponse, SubaccountBalance, SubaccountNettingConfig, SubaccountTransfer, - UnlockSubaccountForSettlementAdvanceRequest, UpdateSubaccountNettingRequest, ) @@ -269,8 +266,6 @@ "IncentiveProgramTypeLiteral", "IndexedBalance", "LiveData", - "LockSubaccountForSettlementAdvanceRequest", - "LockSubaccountForSettlementAdvanceResponse", "LookupTickersForMarketInMultivariateEventCollectionRequest", "LookupTickersResponse", "MaintenanceWindow", @@ -323,7 +318,6 @@ "TimeInForceLiteral", "TotalRestingOrderValue", "Trade", - "UnlockSubaccountForSettlementAdvanceRequest", "UpdateOrderGroupLimitRequest", "UpdateSubaccountNettingRequest", "UserDataTimestamp", diff --git a/kalshi/models/subaccounts.py b/kalshi/models/subaccounts.py index 08161ebf..f42eeffe 100644 --- a/kalshi/models/subaccounts.py +++ b/kalshi/models/subaccounts.py @@ -105,11 +105,6 @@ 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 @@ -117,10 +112,6 @@ class SubaccountBalance(BaseModel): 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"} @@ -133,46 +124,6 @@ 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. diff --git a/kalshi/resources/subaccounts.py b/kalshi/resources/subaccounts.py index 60f3c4bd..4cdf6be3 100644 --- a/kalshi/resources/subaccounts.py +++ b/kalshi/resources/subaccounts.py @@ -16,10 +16,7 @@ CreateSubaccountResponse, GetSubaccountBalancesResponse, GetSubaccountNettingResponse, - LockSubaccountForSettlementAdvanceRequest, - LockSubaccountForSettlementAdvanceResponse, SubaccountTransfer, - UnlockSubaccountForSettlementAdvanceRequest, UpdateSubaccountNettingRequest, ) from kalshi.resources._base import ( @@ -151,54 +148,6 @@ def _build_update_netting_body( return request.model_dump(exclude_none=True, by_alias=True, mode="json") -def _build_lock_settlement_advance_body( - request: LockSubaccountForSettlementAdvanceRequest | None, - *, - subaccount_number: int | None, - exchange_index: int | None, -) -> dict[str, Any]: - _check_request_exclusive( - request, - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - if request is None: - if subaccount_number is None: - raise TypeError( - "lock_settlement_advance() requires `subaccount_number` " - "(or pass `request=...`)" - ) - request = LockSubaccountForSettlementAdvanceRequest( - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - return request.model_dump(exclude_none=True, by_alias=True, mode="json") - - -def _build_unlock_settlement_advance_body( - request: UnlockSubaccountForSettlementAdvanceRequest | None, - *, - subaccount_number: int | None, - exchange_index: int | None, -) -> dict[str, Any]: - _check_request_exclusive( - request, - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - if request is None: - if subaccount_number is None: - raise TypeError( - "unlock_settlement_advance() requires `subaccount_number` " - "(or pass `request=...`)" - ) - request = UnlockSubaccountForSettlementAdvanceRequest( - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - return request.model_dump(exclude_none=True, by_alias=True, mode="json") - - class SubaccountsResource(SyncResource): """Sync subaccounts API. @@ -399,87 +348,6 @@ def get_netting( data = self._get("/portfolio/subaccounts/netting", extra_headers=extra_headers) return GetSubaccountNettingResponse.model_validate(data) - @overload - def lock_settlement_advance( - self, - *, - request: LockSubaccountForSettlementAdvanceRequest, - extra_headers: dict[str, str] | None = None, - ) -> LockSubaccountForSettlementAdvanceResponse: ... - @overload - def lock_settlement_advance( - self, - *, - subaccount_number: int, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> LockSubaccountForSettlementAdvanceResponse: ... - def lock_settlement_advance( - self, - *, - request: LockSubaccountForSettlementAdvanceRequest | None = None, - subaccount_number: int | None = None, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> LockSubaccountForSettlementAdvanceResponse: - """Lock a subaccount for settlement-advance computation. - - Cancels resting orders, prevents trading, and returns a new - ``settlement_advance_state`` CAS token. Auth required. - """ - self._require_auth() - body = _build_lock_settlement_advance_body( - request, - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - data = self._put( - "/portfolio/subaccounts/settlement-advance-lock", - json=body, - extra_headers=extra_headers, - ) - return LockSubaccountForSettlementAdvanceResponse.model_validate(data) - - @overload - def unlock_settlement_advance( - self, - *, - request: UnlockSubaccountForSettlementAdvanceRequest, - extra_headers: dict[str, str] | None = None, - ) -> None: ... - @overload - def unlock_settlement_advance( - self, - *, - subaccount_number: int, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> None: ... - def unlock_settlement_advance( - self, - *, - request: UnlockSubaccountForSettlementAdvanceRequest | None = None, - subaccount_number: int | None = None, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> None: - """Unlock a subaccount previously locked for settlement advance. - - Rejected while the subaccount has an outstanding settlement advance. - Auth required. Returns ``None`` (empty success body). - """ - self._require_auth() - body = _build_unlock_settlement_advance_body( - request, - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - self._delete_with_body( - "/portfolio/subaccounts/settlement-advance-lock", - json=body, - extra_headers=extra_headers, - ) - class AsyncSubaccountsResource(AsyncResource): """Async subaccounts API.""" @@ -670,82 +538,3 @@ async def get_netting( self._require_auth() data = await self._get("/portfolio/subaccounts/netting", extra_headers=extra_headers) return GetSubaccountNettingResponse.model_validate(data) - - @overload - async def lock_settlement_advance( - self, - *, - request: LockSubaccountForSettlementAdvanceRequest, - extra_headers: dict[str, str] | None = None, - ) -> LockSubaccountForSettlementAdvanceResponse: ... - @overload - async def lock_settlement_advance( - self, - *, - subaccount_number: int, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> LockSubaccountForSettlementAdvanceResponse: ... - async def lock_settlement_advance( - self, - *, - request: LockSubaccountForSettlementAdvanceRequest | None = None, - subaccount_number: int | None = None, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> LockSubaccountForSettlementAdvanceResponse: - """Lock a subaccount for settlement-advance computation. - - Async counterpart of :meth:`SubaccountsResource.lock_settlement_advance`. - """ - self._require_auth() - body = _build_lock_settlement_advance_body( - request, - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - data = await self._put( - "/portfolio/subaccounts/settlement-advance-lock", - json=body, - extra_headers=extra_headers, - ) - return LockSubaccountForSettlementAdvanceResponse.model_validate(data) - - @overload - async def unlock_settlement_advance( - self, - *, - request: UnlockSubaccountForSettlementAdvanceRequest, - extra_headers: dict[str, str] | None = None, - ) -> None: ... - @overload - async def unlock_settlement_advance( - self, - *, - subaccount_number: int, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> None: ... - async def unlock_settlement_advance( - self, - *, - request: UnlockSubaccountForSettlementAdvanceRequest | None = None, - subaccount_number: int | None = None, - exchange_index: int | None = None, - extra_headers: dict[str, str] | None = None, - ) -> None: - """Unlock a subaccount previously locked for settlement advance. - - Async counterpart of :meth:`SubaccountsResource.unlock_settlement_advance`. - """ - self._require_auth() - body = _build_unlock_settlement_advance_body( - request, - subaccount_number=subaccount_number, - exchange_index=exchange_index, - ) - await self._delete_with_body( - "/portfolio/subaccounts/settlement-advance-lock", - json=body, - extra_headers=extra_headers, - ) diff --git a/kalshi/ws/models/communications.py b/kalshi/ws/models/communications.py index d7f85ea7..931d6c85 100644 --- a/kalshi/ws/models/communications.py +++ b/kalshi/ws/models/communications.py @@ -93,6 +93,9 @@ class QuoteCreatedPayload(BaseModel): default=None, validation_alias=AliasChoices("rfq_target_cost_dollars", "rfq_target_cost"), ) + # AsyncAPI content (2026-07-27): RFQ creator + own subaccount when applicable. + rfq_creator_id: str | None = None + subaccount: int | None = None model_config = {"extra": "allow", "populate_by_name": True} @@ -130,6 +133,9 @@ class QuoteAcceptedPayload(BaseModel): default=None, validation_alias=AliasChoices("rfq_target_cost_dollars", "rfq_target_cost"), ) + # AsyncAPI content (2026-07-27): RFQ creator + own subaccount when applicable. + rfq_creator_id: str | None = None + subaccount: int | None = None model_config = {"extra": "allow", "populate_by_name": True} @@ -144,6 +150,8 @@ class QuoteExecutedPayload(BaseModel): client_order_id: str market_ticker: str executed_ts: AwareDatetime + # AsyncAPI content (2026-07-27): own subaccount when the quote used one. + subaccount: int | None = None model_config = {"extra": "allow", "populate_by_name": True} diff --git a/pyproject.toml b/pyproject.toml index d344f5d3..81225b32 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "kalshi-sdk" -version = "7.4.0" +version = "8.0.0" description = "A professional Python SDK for the Kalshi prediction markets and Perps (margin) APIs" readme = "README.md" license = { text = "MIT" } diff --git a/specs/asyncapi.yaml b/specs/asyncapi.yaml index 2335a642..8bcfa6e9 100644 --- a/specs/asyncapi.yaml +++ b/specs/asyncapi.yaml @@ -2115,6 +2115,7 @@ components: quote_id: quote_456 rfq_id: rfq_123 quote_creator_id: comm_def456 + rfq_creator_id: comm_abc123 market_ticker: FED-23DEC-T3.00 event_ticker: FED-23DEC yes_bid_dollars: '0.35' @@ -2123,6 +2124,7 @@ components: no_contracts_offered_fp: '200.00' rfq_target_cost_dollars: '0.35' created_ts: '2024-12-01T10:02:00Z' + subaccount: 3 quoteAccepted: name: quote_accepted title: Quote Accepted @@ -2140,6 +2142,7 @@ components: quote_id: quote_456 rfq_id: rfq_123 quote_creator_id: comm_def456 + rfq_creator_id: comm_abc123 market_ticker: FED-23DEC-T3.00 event_ticker: FED-23DEC yes_bid_dollars: '0.35' @@ -2149,6 +2152,7 @@ components: yes_contracts_offered_fp: '100.00' no_contracts_offered_fp: '200.00' rfq_target_cost_dollars: '0.35' + subaccount: 3 quoteExecuted: name: quote_executed title: Quote Executed @@ -2179,6 +2183,7 @@ components: client_order_id: my_client_order_123 market_ticker: FED-23DEC-T3.00 executed_ts: '2024-12-01T10:05:00Z' + subaccount: 3 schemas: commandId: type: integer @@ -4098,6 +4103,9 @@ components: quote_creator_id: type: string description: Public communications ID of the quote creator (anonymized) + rfq_creator_id: + type: string + description: Public communications ID of the RFQ creator (anonymized) market_ticker: type: string description: Market ticker for the quote @@ -4123,6 +4131,14 @@ components: type: string description: Timestamp when the quote was created format: date-time + subaccount: + type: integer + description: > + Optional - Present only when your side of this quote used a + subaccount. + + Contains your own subaccount number; the counterparty's + subaccount is never shared. quoteAcceptedPayload: type: object required: @@ -4154,6 +4170,9 @@ components: quote_creator_id: type: string description: Public communications ID of the quote creator (anonymized) + rfq_creator_id: + type: string + description: Public communications ID of the RFQ creator (anonymized) market_ticker: type: string description: Market ticker for the quote @@ -4184,6 +4203,14 @@ components: rfq_target_cost_dollars: type: string description: Target cost from the RFQ in dollars (optional) + subaccount: + type: integer + description: > + Optional - Present only when your side of this quote used a + subaccount. + + Contains your own subaccount number; the counterparty's + subaccount is never shared. quoteExecutedPayload: type: object required: @@ -4237,6 +4264,14 @@ components: type: string description: Timestamp when the quote was executed and orders were placed format: date-time + subaccount: + type: integer + description: > + Optional - Present only when your side of this quote used a + subaccount. + + Contains your own subaccount number; the counterparty's + subaccount is never shared. securitySchemes: apiKey: type: apiKey diff --git a/specs/openapi.yaml b/specs/openapi.yaml index d9f5cfcf..0144ee1e 100644 --- a/specs/openapi.yaml +++ b/specs/openapi.yaml @@ -1730,75 +1730,6 @@ paths: $ref: '#/components/responses/UnauthorizedError' '500': $ref: '#/components/responses/InternalServerError' - /portfolio/subaccounts/settlement-advance-lock: - put: - operationId: LockSubaccountForSettlementAdvance - summary: Lock Subaccount for Settlement Advance - description: >- - Locks a subaccount for settlement advance computation. Locking cancels - resting orders, prevents trading, and returns a new state token. - tags: - - portfolio - security: - - kalshiAccessKey: [] - kalshiAccessSignature: [] - kalshiAccessTimestamp: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/LockSubaccountForSettlementAdvanceRequest' - responses: - '200': - description: Subaccount locked successfully - content: - application/json: - schema: - $ref: >- - #/components/schemas/LockSubaccountForSettlementAdvanceResponse - '400': - $ref: '#/components/responses/BadRequestError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '409': - $ref: '#/components/responses/ConflictError' - '500': - $ref: '#/components/responses/InternalServerError' - delete: - operationId: UnlockSubaccountForSettlementAdvance - summary: Unlock Subaccount for Settlement Advance - description: >- - Unlocks a subaccount. Unlocking is rejected while the subaccount has an - outstanding settlement advance. - tags: - - portfolio - security: - - kalshiAccessKey: [] - kalshiAccessSignature: [] - kalshiAccessTimestamp: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UnlockSubaccountForSettlementAdvanceRequest' - responses: - '200': - description: Subaccount unlocked successfully - content: - application/json: - schema: - $ref: >- - #/components/schemas/UnlockSubaccountForSettlementAdvanceResponse - '400': - $ref: '#/components/responses/BadRequestError' - '401': - $ref: '#/components/responses/UnauthorizedError' - '409': - $ref: '#/components/responses/ConflictError' - '500': - $ref: '#/components/responses/InternalServerError' /portfolio/subaccounts/positions/transfer: post: x-excluded: true @@ -5652,54 +5583,6 @@ components: ApplySubaccountTransferResponse: type: object description: Empty response indicating successful transfer. - LockSubaccountForSettlementAdvanceRequest: - type: object - required: - - subaccount_number - properties: - subaccount_number: - type: integer - nullable: true - description: Subaccount number (0 for primary, 1-63 for numbered subaccounts). - x-oapi-codegen-extra-tags: - validate: required - exchange_index: - allOf: - - $ref: '#/components/schemas/ExchangeIndex' - description: Identifier for an exchange shard. Defaults to 0 if unspecified. - x-go-type-skip-optional-pointer: true - x-oapi-codegen-extra-tags: - validate: gte=0 - LockSubaccountForSettlementAdvanceResponse: - type: object - required: - - settlement_advance_state - properties: - settlement_advance_state: - type: string - format: uuid - description: New state token for settlement advance compare-and-swap requests. - UnlockSubaccountForSettlementAdvanceRequest: - type: object - required: - - subaccount_number - properties: - subaccount_number: - type: integer - nullable: true - description: Subaccount number (0 for primary, 1-63 for numbered subaccounts). - x-oapi-codegen-extra-tags: - validate: required - exchange_index: - allOf: - - $ref: '#/components/schemas/ExchangeIndex' - description: Identifier for an exchange shard. Defaults to 0 if unspecified. - x-go-type-skip-optional-pointer: true - x-oapi-codegen-extra-tags: - validate: gte=0 - UnlockSubaccountForSettlementAdvanceResponse: - type: object - description: Empty response indicating the subaccount was unlocked successfully. ApplySubaccountPositionTransferRequest: type: object required: @@ -5789,8 +5672,6 @@ components: - exchange_index - balance - updated_ts - - voluntarily_locked - - settlement_advance properties: subaccount_number: type: integer @@ -5805,18 +5686,6 @@ components: type: integer format: int64 description: Unix timestamp of last balance update. - voluntarily_locked: - type: boolean - description: >- - Whether this subaccount is voluntarily locked for settlement advance - computation. - settlement_advance_state: - type: string - format: uuid - description: Current settlement advance state token, if one has been established. - settlement_advance: - $ref: '#/components/schemas/FixedPointDollars' - description: Outstanding settlement advance in dollars. GetSubaccountTransfersResponse: type: object required: diff --git a/tests/_contract_support.py b/tests/_contract_support.py index 0a75e7fd..8dbc955d 100644 --- a/tests/_contract_support.py +++ b/tests/_contract_support.py @@ -699,18 +699,6 @@ class Exclusion: http_method="GET", path_template="/portfolio/subaccounts/netting", ), - MethodEndpointEntry( - sdk_method="kalshi.resources.subaccounts.SubaccountsResource.lock_settlement_advance", - http_method="PUT", - path_template="/portfolio/subaccounts/settlement-advance-lock", - request_body_schema="#/components/schemas/LockSubaccountForSettlementAdvanceRequest", - ), - MethodEndpointEntry( - sdk_method="kalshi.resources.subaccounts.SubaccountsResource.unlock_settlement_advance", - http_method="DELETE", - path_template="/portfolio/subaccounts/settlement-advance-lock", - request_body_schema="#/components/schemas/UnlockSubaccountForSettlementAdvanceRequest", - ), # ── portfolio ─────────────────────────────────────────────────────────── MethodEndpointEntry( sdk_method="kalshi.resources.portfolio.PortfolioResource.balance", @@ -994,39 +982,6 @@ class Exclusion: ), kind="body_param", ), - # unlock_settlement_advance (DELETE with requestBody): TestRequestParamDrift - # only compares query/path params, so body kwargs + the model-first - # `request` overload must be allowlisted. Body shape is covered by - # TestRequestBodyDrift via UnlockSubaccountForSettlementAdvanceRequest. - ("kalshi.resources.subaccounts.SubaccountsResource.unlock_settlement_advance", "request"): ( - Exclusion( - reason=( - "Model-first overload for DELETE-with-body settlement-advance unlock; " - "not a query/path param. Body checked via TestRequestBodyDrift." - ), - kind="body_param", - ) - ), - ( - "kalshi.resources.subaccounts.SubaccountsResource.unlock_settlement_advance", - "subaccount_number", - ): Exclusion( - reason=( - "Request-body field on DELETE /portfolio/subaccounts/settlement-advance-lock; " - "not a query/path param. Body checked via TestRequestBodyDrift." - ), - kind="body_param", - ), - ( - "kalshi.resources.subaccounts.SubaccountsResource.unlock_settlement_advance", - "exchange_index", - ): Exclusion( - reason=( - "Request-body field on DELETE /portfolio/subaccounts/settlement-advance-lock; " - "not a query/path param. Body checked via TestRequestBodyDrift." - ), - kind="body_param", - ), # --- CreateOrderGroupRequest / UpdateOrderGroupLimitRequest _fp variants --- # Spec has both contracts_limit (int) and contracts_limit_fp (FixedPointCount # string) as mutually-compatible representations. SDK commits to the integer diff --git a/tests/test_contracts.py b/tests/test_contracts.py index 93f75adc..766b9c06 100644 --- a/tests/test_contracts.py +++ b/tests/test_contracts.py @@ -1452,12 +1452,6 @@ def _assert_params_match( "#/components/schemas/UpdateSubaccountNettingRequest": ( "kalshi.models.subaccounts.UpdateSubaccountNettingRequest" ), - "#/components/schemas/LockSubaccountForSettlementAdvanceRequest": ( - "kalshi.models.subaccounts.LockSubaccountForSettlementAdvanceRequest" - ), - "#/components/schemas/UnlockSubaccountForSettlementAdvanceRequest": ( - "kalshi.models.subaccounts.UnlockSubaccountForSettlementAdvanceRequest" - ), "#/components/schemas/CreateApiKeyRequest": ("kalshi.models.api_keys.CreateApiKeyRequest"), "#/components/schemas/GenerateApiKeyRequest": ("kalshi.models.api_keys.GenerateApiKeyRequest"), } diff --git a/tests/test_models.py b/tests/test_models.py index 6d28a610..9da96861 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1070,26 +1070,6 @@ class TestStrictIntRejectsBoolOnRequestModels: "subaccount_number", {"enabled": True}, ), - ( - "kalshi.models.subaccounts:LockSubaccountForSettlementAdvanceRequest", - "subaccount_number", - {}, - ), - ( - "kalshi.models.subaccounts:LockSubaccountForSettlementAdvanceRequest", - "exchange_index", - {"subaccount_number": 0}, - ), - ( - "kalshi.models.subaccounts:UnlockSubaccountForSettlementAdvanceRequest", - "subaccount_number", - {}, - ), - ( - "kalshi.models.subaccounts:UnlockSubaccountForSettlementAdvanceRequest", - "exchange_index", - {"subaccount_number": 0}, - ), ( "kalshi.models.communications:CreateQuoteRequest", "subaccount", diff --git a/tests/test_subaccounts.py b/tests/test_subaccounts.py index 8a98b011..6adc1f82 100644 --- a/tests/test_subaccounts.py +++ b/tests/test_subaccounts.py @@ -28,12 +28,9 @@ CreateSubaccountResponse, GetSubaccountBalancesResponse, GetSubaccountNettingResponse, - LockSubaccountForSettlementAdvanceRequest, - LockSubaccountForSettlementAdvanceResponse, SubaccountBalance, SubaccountNettingConfig, SubaccountTransfer, - UnlockSubaccountForSettlementAdvanceRequest, UpdateSubaccountNettingRequest, ) from kalshi.resources.subaccounts import ( @@ -41,14 +38,6 @@ SubaccountsResource, ) -# Required settlement-advance fields on SubaccountBalance (OpenAPI 3.26.0 content). -_BALANCE_ADVANCE_FIELDS = { - "voluntarily_locked": False, - "settlement_advance": "0.0000", -} - -_TEST_ADVANCE_STATE = "550e8400-e29b-41d4-a716-446655440099" - @pytest.fixture def config() -> KalshiConfig: @@ -96,44 +85,11 @@ def test_subaccount_balance_parses_dollar_decimal(self) -> None: "exchange_index": 0, "balance": "12.3400", "updated_ts": 1_700_000_000, - **_BALANCE_ADVANCE_FIELDS, } ) assert bal.subaccount_number == 1 assert bal.balance == Decimal("12.3400") assert bal.updated_ts == 1_700_000_000 - assert bal.voluntarily_locked is False - assert bal.settlement_advance == Decimal("0.0000") - assert bal.settlement_advance_state is None - - def test_subaccount_balance_settlement_advance_fields(self) -> None: - state = "550e8400-e29b-41d4-a716-446655440099" - bal = SubaccountBalance.model_validate( - { - "subaccount_number": 2, - "exchange_index": 0, - "balance": "1.00", - "updated_ts": 1, - "voluntarily_locked": True, - "settlement_advance": "3.5000", - "settlement_advance_state": state, - } - ) - assert bal.voluntarily_locked is True - assert bal.settlement_advance == Decimal("3.5000") - assert str(bal.settlement_advance_state) == state - - def test_subaccount_balance_requires_settlement_advance_fields(self) -> None: - with pytest.raises(ValidationError): - SubaccountBalance.model_validate( - { - "subaccount_number": 0, - "exchange_index": 0, - "balance": "1.00", - "updated_ts": 1, - # voluntarily_locked / settlement_advance intentionally omitted - } - ) def test_subaccount_transfer_parses(self) -> None: # Spec sync (2026-07-20/21): GET transfers is cash-only; transfer_type @@ -211,7 +167,6 @@ def test_get_balances_response_wraps_list(self) -> None: "exchange_index": 0, "balance": "100.00", "updated_ts": 1, - **_BALANCE_ADVANCE_FIELDS, }, ], }, @@ -404,45 +359,6 @@ def test_position_transfer_request_rejects_bad_price(self, bad_price: Decimal) - price=bad_price, ) - # ── Settlement-advance lock / unlock request models (#486) ── - def test_lock_settlement_advance_request_serializes(self) -> None: - req = LockSubaccountForSettlementAdvanceRequest(subaccount_number=1) - body = req.model_dump(exclude_none=True, by_alias=True, mode="json") - assert body == {"subaccount_number": 1} - - def test_lock_settlement_advance_request_with_exchange_index(self) -> None: - req = LockSubaccountForSettlementAdvanceRequest( - subaccount_number=0, exchange_index=0, - ) - body = req.model_dump(exclude_none=True, by_alias=True, mode="json") - assert body == {"subaccount_number": 0, "exchange_index": 0} - - def test_lock_settlement_advance_request_forbids_extra(self) -> None: - with pytest.raises(ValidationError): - LockSubaccountForSettlementAdvanceRequest( # type: ignore[call-arg] - subaccount_number=0, phantom=1, - ) - - def test_unlock_settlement_advance_request_serializes(self) -> None: - req = UnlockSubaccountForSettlementAdvanceRequest( - subaccount_number=2, exchange_index=0, - ) - body = req.model_dump(exclude_none=True, by_alias=True, mode="json") - assert body == {"subaccount_number": 2, "exchange_index": 0} - - def test_unlock_settlement_advance_request_forbids_extra(self) -> None: - with pytest.raises(ValidationError): - UnlockSubaccountForSettlementAdvanceRequest( # type: ignore[call-arg] - subaccount_number=0, phantom=1, - ) - - def test_lock_settlement_advance_response_parses_uuid(self) -> None: - resp = LockSubaccountForSettlementAdvanceResponse.model_validate( - {"settlement_advance_state": _TEST_ADVANCE_STATE}, - ) - assert str(resp.settlement_advance_state) == _TEST_ADVANCE_STATE - - class TestSubaccountsCreate: @respx.mock def test_create_sends_empty_json_body( @@ -646,14 +562,12 @@ def test_returns_balances(self, subaccounts: SubaccountsResource) -> None: "exchange_index": 0, "balance": "10.00", "updated_ts": 1, - **_BALANCE_ADVANCE_FIELDS, }, { "subaccount_number": 1, "exchange_index": 0, "balance": "5.00", "updated_ts": 2, - **_BALANCE_ADVANCE_FIELDS, }, ], }, @@ -663,7 +577,6 @@ def test_returns_balances(self, subaccounts: SubaccountsResource) -> None: assert isinstance(resp, GetSubaccountBalancesResponse) assert len(resp.subaccount_balances) == 2 assert resp.subaccount_balances[0].balance == Decimal("10.00") - assert resp.subaccount_balances[0].voluntarily_locked is False @respx.mock def test_empty_list(self, subaccounts: SubaccountsResource) -> None: @@ -875,7 +788,6 @@ async def test_list_balances( "exchange_index": 0, "balance": "1.00", "updated_ts": 1, - **_BALANCE_ADVANCE_FIELDS, }, ], }, @@ -953,126 +865,6 @@ async def test_get_netting( resp = await async_subaccounts.get_netting() assert resp.netting_configs == [] - async def test_lock_settlement_advance( - self, - async_subaccounts: AsyncSubaccountsResource, - respx_mock: respx.MockRouter, - ) -> None: - route = respx_mock.put( - "https://test.kalshi.com/trade-api/v2/portfolio/subaccounts/" - "settlement-advance-lock", - ).mock( - return_value=httpx.Response( - 200, json={"settlement_advance_state": _TEST_ADVANCE_STATE}, - ), - ) - resp = await async_subaccounts.lock_settlement_advance(subaccount_number=1) - assert str(resp.settlement_advance_state) == _TEST_ADVANCE_STATE - assert json.loads(route.calls[0].request.content) == {"subaccount_number": 1} - - async def test_unlock_settlement_advance( - self, - async_subaccounts: AsyncSubaccountsResource, - respx_mock: respx.MockRouter, - ) -> None: - route = respx_mock.delete( - "https://test.kalshi.com/trade-api/v2/portfolio/subaccounts/" - "settlement-advance-lock", - ).mock(return_value=httpx.Response(200, json={})) - result = await async_subaccounts.unlock_settlement_advance(subaccount_number=1) - assert result is None - assert json.loads(route.calls[0].request.content) == {"subaccount_number": 1} - - -class TestSubaccountsSettlementAdvance: - @respx.mock - def test_lock_settlement_advance_kwargs( - self, subaccounts: SubaccountsResource, - ) -> None: - route = respx.put( - "https://test.kalshi.com/trade-api/v2/portfolio/subaccounts/" - "settlement-advance-lock", - ).mock( - return_value=httpx.Response( - 200, json={"settlement_advance_state": _TEST_ADVANCE_STATE}, - ), - ) - resp = subaccounts.lock_settlement_advance( - subaccount_number=1, exchange_index=0, - ) - assert isinstance(resp, LockSubaccountForSettlementAdvanceResponse) - assert str(resp.settlement_advance_state) == _TEST_ADVANCE_STATE - assert json.loads(route.calls[0].request.content) == { - "subaccount_number": 1, - "exchange_index": 0, - } - - @respx.mock - def test_lock_settlement_advance_request_model( - self, subaccounts: SubaccountsResource, - ) -> None: - route = respx.put( - "https://test.kalshi.com/trade-api/v2/portfolio/subaccounts/" - "settlement-advance-lock", - ).mock( - return_value=httpx.Response( - 200, json={"settlement_advance_state": _TEST_ADVANCE_STATE}, - ), - ) - req = LockSubaccountForSettlementAdvanceRequest(subaccount_number=0) - resp = subaccounts.lock_settlement_advance(request=req) - assert str(resp.settlement_advance_state) == _TEST_ADVANCE_STATE - assert json.loads(route.calls[0].request.content) == {"subaccount_number": 0} - - def test_lock_settlement_advance_requires_subaccount( - self, subaccounts: SubaccountsResource, - ) -> None: - with pytest.raises(TypeError, match="subaccount_number"): - subaccounts.lock_settlement_advance() - - def test_lock_settlement_advance_rejects_mixed_args( - self, subaccounts: SubaccountsResource, - ) -> None: - req = LockSubaccountForSettlementAdvanceRequest(subaccount_number=0) - with pytest.raises(TypeError, match="either `request="): - subaccounts.lock_settlement_advance(request=req, subaccount_number=1) - - @respx.mock - def test_unlock_settlement_advance_kwargs( - self, subaccounts: SubaccountsResource, - ) -> None: - route = respx.delete( - "https://test.kalshi.com/trade-api/v2/portfolio/subaccounts/" - "settlement-advance-lock", - ).mock(return_value=httpx.Response(200, json={})) - result = subaccounts.unlock_settlement_advance(subaccount_number=2) - assert result is None - assert json.loads(route.calls[0].request.content) == {"subaccount_number": 2} - - @respx.mock - def test_unlock_settlement_advance_request_model( - self, subaccounts: SubaccountsResource, - ) -> None: - route = respx.delete( - "https://test.kalshi.com/trade-api/v2/portfolio/subaccounts/" - "settlement-advance-lock", - ).mock(return_value=httpx.Response(200, json={})) - req = UnlockSubaccountForSettlementAdvanceRequest( - subaccount_number=3, exchange_index=0, - ) - result = subaccounts.unlock_settlement_advance(request=req) - assert result is None - assert json.loads(route.calls[0].request.content) == { - "subaccount_number": 3, - "exchange_index": 0, - } - - def test_unlock_settlement_advance_requires_subaccount( - self, subaccounts: SubaccountsResource, - ) -> None: - with pytest.raises(TypeError, match="subaccount_number"): - subaccounts.unlock_settlement_advance() - class TestSubaccountsAuthGuard: def test_create_requires_auth( @@ -1124,19 +916,6 @@ def test_get_netting_requires_auth( with pytest.raises(AuthRequiredError): unauth_subaccounts.get_netting() - def test_lock_settlement_advance_requires_auth( - self, unauth_subaccounts: SubaccountsResource, - ) -> None: - with pytest.raises(AuthRequiredError): - unauth_subaccounts.lock_settlement_advance(subaccount_number=0) - - def test_unlock_settlement_advance_requires_auth( - self, unauth_subaccounts: SubaccountsResource, - ) -> None: - with pytest.raises(AuthRequiredError): - unauth_subaccounts.unlock_settlement_advance(subaccount_number=0) - - class TestClientWiring: def test_sync_client_exposes_subaccounts( self, client: KalshiClient,