|
2 | 2 |
|
3 | 3 | All notable changes to kalshi-sdk will be documented in this file. |
4 | 4 |
|
| 5 | +## 1.1.0 — 2026-05-16 |
| 6 | + |
| 7 | +Post-1.0 enhancements and polish. 17 issues closed across four parallel waves of |
| 8 | +work. No breaking changes to runtime behavior; two mypy-level type-system |
| 9 | +tightenings are called out below. |
| 10 | + |
| 11 | +### Added |
| 12 | + |
| 13 | +- **Model-first request API.** Every POST/PUT/DELETE-with-body resource method |
| 14 | + now accepts a pre-built request model as an alternative to individual kwargs. |
| 15 | + Backward-compatible — the existing kwarg form continues to work unchanged |
| 16 | + (#56). |
| 17 | + |
| 18 | + ```python |
| 19 | + client.orders.amend(request=AmendOrderRequest(order_id=..., yes_price=...)) |
| 20 | + client.orders.amend(order_id=..., yes_price=...) # also works |
| 21 | + ``` |
| 22 | + |
| 23 | + Each method has typed `@overload` stubs (32 methods × 2 = 64 stubs) so mypy |
| 24 | + catches misuse at type-check time, not runtime. |
| 25 | + |
| 26 | +- **DataFrame integration.** `Page[T]` gained `.to_dataframe()` and |
| 27 | + `.to_polars()` methods with optional dependency extras (#12): |
| 28 | + |
| 29 | + ```bash |
| 30 | + pip install 'kalshi-sdk[pandas]' # or [polars] or [all] |
| 31 | + ``` |
| 32 | + |
| 33 | + ```python |
| 34 | + page = client.markets.list(limit=100) |
| 35 | + df = page.to_dataframe() |
| 36 | + ``` |
| 37 | + |
| 38 | + Lazy imports; `Decimal` and `datetime` preserved as native types via |
| 39 | + `model_dump(mode="python")`. |
| 40 | + |
| 41 | +- **Record / replay mock transport** (`kalshi.testing`) for offline integration |
| 42 | + testing (#13). `RecordingTransport` proxies real calls and saves |
| 43 | + request/response pairs as JSON; `ReplayTransport` serves the fixtures with |
| 44 | + no network. Sync and async transports both supported; signature/timestamp |
| 45 | + headers are excluded from fingerprinting so signatures can drift between |
| 46 | + record and replay. |
| 47 | + |
| 48 | + ```python |
| 49 | + with KalshiClient.from_env(transport=RecordingTransport("fixtures")) as c: |
| 50 | + c.exchange.status() # records once |
| 51 | + |
| 52 | + with KalshiClient(transport=ReplayTransport("fixtures")) as c: |
| 53 | + c.exchange.status() # offline replay |
| 54 | + ``` |
| 55 | + |
| 56 | +- **Typed `Literal` aliases for fixed-enum kwargs** (#50). 13 new aliases |
| 57 | + exported from `kalshi` and `kalshi.models`: `SideLiteral`, `ActionLiteral`, |
| 58 | + `TimeInForceLiteral`, `SelfTradePreventionTypeLiteral`, `OrderStatusLiteral`, |
| 59 | + `EventStatusLiteral`, `MarketStatusLiteral`, `MveFilterLiteral`, |
| 60 | + `MveHistoricalFilterLiteral`, `MultivariateCollectionStatusLiteral`, |
| 61 | + `IncentiveProgramStatusLiteral`, `IncentiveProgramTypeLiteral`, |
| 62 | + `SettlementStatusLiteral`. mypy now catches typos in resource kwargs at |
| 63 | + authoring time. |
| 64 | + |
| 65 | +- **MkDocs documentation site** (#14, #57). Material theme + mkdocstrings; |
| 66 | + Getting Started, Authentication, WebSockets, Resources, Errors, Migration |
| 67 | + guides plus auto-generated API reference. GitHub Pages deploy workflow at |
| 68 | + `.github/workflows/docs.yml`. |
| 69 | + |
| 70 | +- **Constructor-variant integration tests** (#54). Exercises every supported |
| 71 | + `KalshiClient` construction path against the demo API (`from_env`, |
| 72 | + `key_id + private_key_path`, in-memory PEM string, pre-built `KalshiAuth`, |
| 73 | + `demo=True`). Includes an async sibling test to catch signing-path drift. |
| 74 | + |
| 75 | +- **Per-method auth guards on `markets.orderbook`** (#49). Spec walk confirmed |
| 76 | + this was the only public-resource GET endpoint missing `_require_auth()`; |
| 77 | + unauthenticated callers now get a clear `AuthRequiredError` instead of a |
| 78 | + confusing 401 from Kalshi. |
| 79 | + |
| 80 | +### Changed |
| 81 | + |
| 82 | +- **Sync/async dedup refactor** (#46). Extracted shared body-builder, |
| 83 | + query-param-builder, and response-parser helpers across 13 resource modules. |
| 84 | + Dispatcher logic and request-model construction now exist once per |
| 85 | + method-pair instead of twice. Sync/async signatures, `@overload` stubs, and |
| 86 | + the `async for item in client.markets.list_all():` ergonomic are all |
| 87 | + preserved. |
| 88 | + |
| 89 | +- **Async `OrdersResource.batch_cancel` routed through shared |
| 90 | + `_delete_with_body` helper** (#47). Previously called the transport directly, |
| 91 | + bypassing the sync path's helper; any future retry / error-mapping change to |
| 92 | + the helper now applies to both transports symmetrically. |
| 93 | + |
| 94 | +- **Sync `test_list_all` iteration idiom standardized** (#48). Sync tests now |
| 95 | + use the same manual-counter loop as their async siblings; cosmetic only. |
| 96 | + |
| 97 | +### Fixed |
| 98 | + |
| 99 | +- **Async `multivariate.lookup_tickers` 204 spec-drift guard** (#72). Sync had |
| 100 | + a clear `RuntimeError("spec drift: ...")` on an unexpected 204; async would |
| 101 | + surface a confusing `TypeError` from `model_validate(None)`. Extracted a |
| 102 | + shared `_parse_lookup_tickers_response` helper so both paths share the |
| 103 | + guard. |
| 104 | + |
| 105 | +### Test infrastructure |
| 106 | + |
| 107 | +- **Typed `ExclusionKind`** discriminator on contract drift exclusions (#51). |
| 108 | + Replaces the free-text `reason` substring matching in |
| 109 | + `test_exclusion_map_is_current` with explicit |
| 110 | + `Literal["body_param", "spec_deprecated", "paginator_handled", |
| 111 | + "wire_normalization", "kwarg_rename"]` classification. All 47 existing |
| 112 | + exclusions reclassified. |
| 113 | + |
| 114 | +- **Nested-model body-drift detection** (#52). The drift test now recurses |
| 115 | + into nested `BaseModel` fields (e.g. `TickerPair` inside |
| 116 | + `CreateMarketInMultivariateEventCollectionRequest.selected_markets`). |
| 117 | + `TickerPair.extra="allow"` intentionally preserved because `LookupPoint` |
| 118 | + responses echo provider keys; the existing pin test documents the carve-out. |
| 119 | + |
| 120 | +- **`kwarg_rename` `ExclusionKind`** split out of `wire_normalization` (#68). |
| 121 | + Python-naming-hygiene renames (`milestone_type`, `target_type`, |
| 122 | + `incentive_type` — spec field `type` shadows the builtin) are now |
| 123 | + classified separately from wire-format normalization. |
| 124 | + |
| 125 | +### Infrastructure |
| 126 | + |
| 127 | +- **Weekly OpenAPI + AsyncAPI spec sync CI** (#16). Cron + manual dispatch |
| 128 | + workflow snapshots both specs, regenerates models, runs ruff / mypy / |
| 129 | + pytest, opens a PR with version + endpoint diff if any changes detected. |
| 130 | + Third-party actions pinned to commit SHAs because the workflow holds |
| 131 | + `contents: write` + `pull-requests: write`. Concurrency-guarded against |
| 132 | + same-branch races. |
| 133 | + |
| 134 | +- **Nightly integration CI** against the demo API (#55). Secret-gated, skips |
| 135 | + cleanly on forks, dedupes failure issues by stable title. |
| 136 | + |
| 137 | +### mypy-only breaking changes |
| 138 | + |
| 139 | +These tighten types without changing runtime behavior. Existing valid calls are |
| 140 | +unaffected; the type system will now reject calls that would have failed at |
| 141 | +runtime anyway (or that were always wrong but mypy couldn't see it). |
| 142 | + |
| 143 | +- `Page[T]` TypeVar tightened from `TypeVar("T")` to |
| 144 | + `TypeVar("T", bound=BaseModel)`. Matches the bound already used inside |
| 145 | + `kalshi/resources/_base.py` and the actual usage pattern across the SDK |
| 146 | + (every concrete `Page[X]` parameterizes with a `BaseModel` subclass). |
| 147 | +- Resource-method kwargs for the 13 enum fields above are now `Literal[...]` |
| 148 | + instead of `str | None`. Callers passing arbitrary strings (typos, in-flight |
| 149 | + variable values) now fail at mypy-check time. |
| 150 | + |
| 151 | +### Coverage at 1.1.0 |
| 152 | + |
| 153 | +- 89/89 REST endpoints implemented (sync + async); auth-guard audit complete |
| 154 | + across public resources. |
| 155 | +- 11 WebSocket channels with sequence-gap detection, configurable backpressure, |
| 156 | + and automatic reconnection. |
| 157 | +- **1407 unit tests passing** (1455 collected, 48 skipped — up from 899 at |
| 158 | + 1.0.0), mypy `--strict` clean (76 source files), ruff clean. |
| 159 | +- Drift tests now detect query/path/body/WS-payload schema drift _and_ nested |
| 160 | + body-model drift. |
| 161 | +- Optional extras: `pandas`, `polars`, `all`, `docs`. |
| 162 | + |
5 | 163 | ## 1.0.0 — 2026-05-10 |
6 | 164 |
|
7 | 165 | First stable release. No behavioral changes from 0.15.0 — this release marks |
|
0 commit comments