Skip to content

Commit 910f2f8

Browse files
TexasCodingclaude
andcommitted
docs: 100% accuracy pass for v4.1.0
Document the 4.1.0 additions and fix a stale verb: - communications: block_trade_proposals sub-resource (quick-ref rows, a worked example section, mkdocstrings directives) + quotes min_ts/max_ts; fix quotes.accept/confirm verb (PUT, not POST) in the quick-ref table - account: volume_progress() (quick-ref row + section) - events: tickers filter (example + prose) - perps: MarginMarket mark-price fields + new TickerPrice model; required MarginPosition.subaccount - reference / request-models: new request models in the curated lists Verified: mkdocs build --strict passes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 46403d0 commit 910f2f8

6 files changed

Lines changed: 115 additions & 2 deletions

File tree

docs/perps.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ Orders create/cancel/decrease/amend are POSTs/DELETEs and are **never retried**.
8989
record). `MarginMarket.leverage_estimates` maps notional position sizes
9090
(`"1000"`, `"10000"`, …) to `MultiplierDecimal` leverage, or `None` when margin
9191
config / price data is unavailable.
92+
- **Mark prices** (since the v3.21.0 spec sync) — `MarginMarket` carries three
93+
optional reference-price objects: `settlement_mark_price`,
94+
`liquidation_mark_price`, and `reference_price`, each a nested `TickerPrice`
95+
(`TickerPrice | None`). `TickerPrice` is a new model with `price`
96+
(`DollarDecimal`, a `FixedPointDollars` USD string) and `ts_ms` (the source
97+
timestamp in epoch **milliseconds**, `int`). All three are absent from the spec
98+
`required` list, so they are `None` when the upstream price is unavailable.
99+
- **Subaccounts** (since the v3.21.0 spec sync) — `MarginPosition` (the
100+
`portfolio.positions()` rows) carries a **required** `subaccount` (`int`)
101+
identifying which subaccount holds the position.
92102

93103
## Funding mechanics
94104

docs/reference.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ every exception class.
5656

5757
::: kalshi.models.communications.AcceptQuoteRequest
5858

59+
::: kalshi.models.communications.ProposeBlockTradeRequest
60+
61+
::: kalshi.models.communications.AcceptBlockTradeProposalRequest
62+
5963
::: kalshi.models.multivariate.CreateMarketInMultivariateEventCollectionRequest
6064

6165
::: kalshi.models.multivariate.LookupTickersForMarketInMultivariateEventCollectionRequest

docs/request-models.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ OpenAPI spec.
7474
| `client.communications.create_rfq` | `CreateRFQRequest` |
7575
| `client.communications.create_quote` | `CreateQuoteRequest` |
7676
| `client.communications.accept_quote` | `AcceptQuoteRequest` |
77+
| `client.communications.block_trade_proposals.create` | `ProposeBlockTradeRequest` |
78+
| `client.communications.block_trade_proposals.accept` | `AcceptBlockTradeProposalRequest` |
7779
| `client.multivariate_collections.create_market` | `CreateMarketInMultivariateEventCollectionRequest` |
7880
| `client.multivariate_collections.lookup_tickers` | `LookupTickersForMarketInMultivariateEventCollectionRequest` |
7981
| `client.order_groups.create` | `CreateOrderGroupRequest` |

docs/resources/account.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Auth required.
1010
|---|---|
1111
| `limits()` | `GET /account/limits` |
1212
| `endpoint_costs()` | `GET /account/endpoint_costs` |
13+
| `volume_progress()` | `GET /account/api_usage_level/volume_progress` |
1314
| `upgrade()` | `POST /account/api_usage_level/upgrade` |
1415

1516
## Read tier limits
@@ -49,6 +50,27 @@ Endpoints not present in `endpoint_costs` use `default_cost`. Batch
4950
endpoints typically appear here with a per-item multiplier (e.g.
5051
`POST /portfolio/orders/batched` costs ~10 tokens per order in the batch).
5152

53+
## Volume progress
54+
55+
New in v4.1.0. `volume_progress()` (`GET /account/api_usage_level/volume_progress`)
56+
returns the latest cron-computed trading-volume snapshots toward the
57+
volume-based API usage tiers for the predictions (`event_contract`) lane.
58+
59+
```python
60+
progress = client.account.volume_progress()
61+
for snapshot in progress.volume_progress:
62+
print(snapshot.computed_ts, snapshot.trailing_30d_volume)
63+
for goal in snapshot.goals:
64+
# earn = volume needed to earn the level; keep = volume to retain it.
65+
print(goal.level, goal.earn_volume_goal, goal.keep_volume_goal)
66+
```
67+
68+
`AccountVolumeProgress.volume_progress` is a list of
69+
`AccountApiUsageLevelVolumeProgress` snapshots. `computed_ts` is the Unix
70+
second at which the snapshot was computed; `trailing_30d_volume` and each
71+
goal's `earn_volume_goal` / `keep_volume_goal` are fixed-point contract counts
72+
(`Decimal`).
73+
5274
## API usage-level grants
5375

5476
New in v4.0.0. `AccountApiLimits.grants` is a list of `ApiUsageLevelGrant`

docs/resources/communications.md

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ Auth required throughout.
2727
| `quotes.get(quote_id)` | `GET /communications/quotes/{quote_id}` |
2828
| `quotes.create(...)` | `POST /communications/quotes` |
2929
| `quotes.delete(quote_id)` | `DELETE /communications/quotes/{quote_id}` |
30-
| `quotes.accept(quote_id, *, accepted_side)` | `POST /communications/quotes/{quote_id}/accept` |
31-
| `quotes.confirm(quote_id)` | `POST /communications/quotes/{quote_id}/confirm` |
30+
| `quotes.accept(quote_id, *, accepted_side)` | `PUT /communications/quotes/{quote_id}/accept` |
31+
| `quotes.confirm(quote_id)` | `PUT /communications/quotes/{quote_id}/confirm` |
32+
| `block_trade_proposals.list(...)` / `block_trade_proposals.list_all(...)` | `GET /communications/block-trade-proposals` |
33+
| `block_trade_proposals.create(...)` | `POST /communications/block-trade-proposals` |
34+
| `block_trade_proposals.accept(block_trade_proposal_id, *, subtrader_id=None, subaccount=None)` | `POST /communications/block-trade-proposals/{id}/accept` |
3235

3336
`get_id()` returns your `participant_id` — the value you'll pass as
3437
`quote_creator_user_id` / `rfq_creator_user_id` when filtering lists. It stays
@@ -114,6 +117,26 @@ for rfq in client.communications.rfqs.list_all(user_filter="self"):
114117
server-side shorthands like `"organization"` in the future without an SDK
115118
upgrade.
116119

120+
## Filtering quotes by time (v4.1.0)
121+
122+
`quotes.list()` / `quotes.list_all()` accept `min_ts` and `max_ts` (Unix
123+
seconds, `int`) to bound results by the quote's last-updated timestamp. They
124+
compose with the required user-id filter:
125+
126+
```python
127+
import time
128+
129+
# Quotes you made that were updated in the last hour.
130+
for q in client.communications.quotes.list_all(
131+
user_filter="self",
132+
min_ts=int(time.time()) - 3600,
133+
):
134+
print(q.quote_id, q.updated_ts)
135+
```
136+
137+
`min_ts` / `max_ts` are also accepted by the deprecated `list_quotes` /
138+
`list_all_quotes` forwarders.
139+
117140
## Post-only quotes
118141

119142
`quotes.create()` accepts `post_only=True` (added in v2.1.0) to ensure your
@@ -148,6 +171,44 @@ client.communications.quotes.create(
148171
`open`, `accepted`, `confirmed`, `canceled`. Status filtering accepts these
149172
literal strings.
150173

174+
## Block trade proposals (v4.1.0)
175+
176+
`client.communications.block_trade_proposals` backs the
177+
`/communications/block-trade-proposals` API (OpenAPI 3.21.0) — a bilateral
178+
negotiated trade that both the buyer and seller must accept before it settles.
179+
180+
```python
181+
# Propose a block trade. The proposer names both sides explicitly.
182+
resp = client.communications.block_trade_proposals.create(
183+
buyer_user_id="user_abc",
184+
seller_user_id="user_xyz",
185+
market_ticker="KXPRES-24-DJT",
186+
price_centi_cents=5600, # plain int, centi-cents (NOT a _dollars price)
187+
centicount=50_000, # plain int, centicounts (NOT a _fp count)
188+
maker_side="yes",
189+
expiration_ts="2026-07-01T00:00:00Z",
190+
)
191+
proposal_id = resp.block_trade_proposal_id
192+
193+
# List open proposals on a market.
194+
for proposal in client.communications.block_trade_proposals.list_all(
195+
market_ticker="KXPRES-24-DJT", status="open"
196+
):
197+
print(proposal.id, proposal.buyer_accepted, proposal.seller_accepted)
198+
199+
# Accept (the counterparty side). The body is optional — pass subtrader_id
200+
# or subaccount only if you trade through a sub-trader / subaccount.
201+
client.communications.block_trade_proposals.accept(proposal_id)
202+
```
203+
204+
!!! info "Prices are centi-cents, counts are centicounts — plain integers"
205+
Unlike the rest of the SDK, `BlockTradeProposal.price_centi_cents` and
206+
`.centicount` (and the matching `create()` kwargs) are **plain `int`s** in
207+
centi-cents and centicounts respectively — they are *not*
208+
`FixedPointDollars` / `_fp` wire fields, so no `Decimal` conversion or
209+
`_dollars` / `_fp` aliasing applies. `price_centi_cents` and `centicount`
210+
must each be `>= 1`.
211+
151212
## Migrating from v2.x
152213

153214
| v2.x (deprecated) | v3.0.0 (canonical) |
@@ -181,6 +242,10 @@ literal strings.
181242
options:
182243
heading_level: 3
183244

245+
::: kalshi.resources.communications.BlockTradeProposalsResource
246+
options:
247+
heading_level: 3
248+
184249
::: kalshi.resources.communications.AsyncCommunicationsResource
185250
options:
186251
heading_level: 3
@@ -192,3 +257,7 @@ literal strings.
192257
::: kalshi.resources.communications.AsyncQuotesResource
193258
options:
194259
heading_level: 3
260+
261+
::: kalshi.resources.communications.AsyncBlockTradeProposalsResource
262+
options:
263+
heading_level: 3

docs/resources/events.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ more markets that share a resolution.
2222
page = client.events.list(
2323
status="open", # EventStatusLiteral
2424
series_ticker="KXPRES",
25+
tickers=["KXPRES-24", "KXSENATE-24"], # filter to specific event tickers (v4.1.0)
2526
with_nested_markets=False,
2627
with_milestones=False,
2728
min_close_ts=1_700_000_000,
@@ -36,6 +37,11 @@ for event in page:
3637
`EventStatusLiteral` has values `"unopened" | "open" | "closed" | "settled"`.
3738
Unlike [`MarketStatusLiteral`](../types.md), there is no `"paused"`.
3839

40+
`tickers` (added in v4.1.0) restricts the result set to specific event
41+
tickers. Pass a `list[str]` (joined comma-separated on the wire) or a
42+
pre-joined comma-separated string; list elements must be non-empty and must
43+
not themselves contain commas.
44+
3945
## Multivariate events
4046

4147
`list_multivariate(...)` returns only events that participate in a

0 commit comments

Comments
 (0)