diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c9fbcc..9ab462a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,15 @@ Core OpenAPI remains 3.34.0. ### Added +- **`events.get(..., exclude_markets=)`** (sync + async) — optional + boolean query param on `GET /events/{event_ticker}`. When true, + returns event metadata without loading child markets. Use + `GET /markets` with `event_ticker`, `limit`, and `cursor` for + bounded market pages. Cannot be combined with + `with_nested_markets=true` (API returns 400). Default `None` does + not emit the param; explicit `False` serializes as `false`. + (Closes #542). + - Perps **`markets.bulk_orderbooks(*, tickers)`** (sync + async) — `GET /margin/markets/orderbooks`. Fetches up to 100 margin orderbooks in one call. `tickers` is required (1–100) and serializes as a diff --git a/docs/resources/events.md b/docs/resources/events.md index c9c540e..c2a2b86 100644 --- a/docs/resources/events.md +++ b/docs/resources/events.md @@ -11,7 +11,7 @@ more markets that share a resolution. | `list_all(...)` | walks `list` | no | | `list_multivariate(...)` | `GET /events/multivariate` | no | | `list_all_multivariate(...)` | walks `list_multivariate` | no | -| `get(event_ticker, *, with_nested_markets=False)` | `GET /events/{event_ticker}` | no | +| `get(event_ticker, *, with_nested_markets=False, exclude_markets=False)` | `GET /events/{event_ticker}` | no | | `metadata(event_ticker)` | `GET /events/{event_ticker}/metadata` | no | | `fee_changes(...)` | `GET /events/fee_changes` | no | | `fee_changes_all(...)` | walks `fee_changes` | no | @@ -59,6 +59,11 @@ for market in event.markets: `with_nested_markets` defaults to `False` — you'll get the event metadata only unless you opt in. +`exclude_markets=True` returns event metadata without loading child markets +(use `client.markets.list(event_ticker=..., limit=..., cursor=...)` for +bounded market pages). It cannot be combined with `with_nested_markets=True` +(the API returns 400). Default `None` omits the query param. + ## Event metadata ```python diff --git a/kalshi/resources/events.py b/kalshi/resources/events.py index cbef28a..b16141e 100644 --- a/kalshi/resources/events.py +++ b/kalshi/resources/events.py @@ -198,10 +198,12 @@ def get( event_ticker: str, *, with_nested_markets: bool | None = None, + exclude_markets: bool | None = None, extra_headers: dict[str, str] | None = None, ) -> Event: params = _params( with_nested_markets=_bool_param(with_nested_markets), + exclude_markets=_bool_param(exclude_markets), ) data = self._get( f"/events/{_seg(event_ticker, name='event_ticker')}", @@ -384,10 +386,12 @@ async def get( event_ticker: str, *, with_nested_markets: bool | None = None, + exclude_markets: bool | None = None, extra_headers: dict[str, str] | None = None, ) -> Event: params = _params( with_nested_markets=_bool_param(with_nested_markets), + exclude_markets=_bool_param(exclude_markets), ) data = await self._get( f"/events/{_seg(event_ticker, name='event_ticker')}", diff --git a/specs/openapi.yaml b/specs/openapi.yaml index a18e65a..3ba64fa 100644 --- a/specs/openapi.yaml +++ b/specs/openapi.yaml @@ -754,6 +754,13 @@ paths: description: Event ticker schema: type: string + - name: exclude_markets + in: query + description: Return event metadata without loading child markets. Use GET /markets with event_ticker, limit and cursor for bounded market pages. Cannot be combined with with_nested_markets=true. + required: false + schema: + type: boolean + default: false - name: with_nested_markets in: query required: false diff --git a/tests/test_events.py b/tests/test_events.py index 248b951..3adf6c4 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -182,6 +182,45 @@ def test_get_with_explicit_false_still_serializes(self, events: EventsResource) events.get("EVT-1", with_nested_markets=False) assert route.calls[0].request.url.params["with_nested_markets"] == "false" + @respx.mock + def test_get_exclude_markets_true(self, events: EventsResource) -> None: + route = respx.get("https://test.kalshi.com/trade-api/v2/events/EVT-1").mock( + return_value=httpx.Response( + 200, + json={"event": event_dict(event_ticker="EVT-1", title="T", series_ticker="S")}, + ) + ) + events.get("EVT-1", exclude_markets=True) + assert route.calls[0].request.url.params["exclude_markets"] == "true" + + @respx.mock + def test_get_exclude_markets_default_does_not_send_param( + self, events: EventsResource + ) -> None: + """Default `exclude_markets=None` MUST NOT emit the query param (#542).""" + route = respx.get("https://test.kalshi.com/trade-api/v2/events/EVT-1").mock( + return_value=httpx.Response( + 200, + json={"event": event_dict(event_ticker="EVT-1", title="T", series_ticker="S")}, + ) + ) + events.get("EVT-1") + assert "exclude_markets" not in route.calls[0].request.url.params + + @respx.mock + def test_get_exclude_markets_explicit_false_still_serializes( + self, events: EventsResource + ) -> None: + """Explicit `exclude_markets=False` MUST still emit `?exclude_markets=false`.""" + route = respx.get("https://test.kalshi.com/trade-api/v2/events/EVT-1").mock( + return_value=httpx.Response( + 200, + json={"event": event_dict(event_ticker="EVT-1", title="T", series_ticker="S")}, + ) + ) + events.get("EVT-1", exclude_markets=False) + assert route.calls[0].request.url.params["exclude_markets"] == "false" + @respx.mock def test_not_found(self, events: EventsResource) -> None: respx.get("https://test.kalshi.com/trade-api/v2/events/FAKE").mock(