diff --git a/docs/options.md b/docs/options.md index 5528908..9b35a8e 100644 --- a/docs/options.md +++ b/docs/options.md @@ -198,7 +198,7 @@ Fetches the options chain for a given symbol with extensive filtering options. T - `strike` (str, optional): Filter by strike price (e.g., "150", "ATM", "ITM", "OTM") - `delta` (float, optional): Filter by delta value -- `strike_limit` (float, optional): Limit the number of strikes +- `strike_limit` (int, optional): Limit the number of strikes - `range` (str, optional): Strike range filter **Price / Liquidity Filters:** diff --git a/src/marketdata/input_types/options.py b/src/marketdata/input_types/options.py index b3587a6..7da03ee 100644 --- a/src/marketdata/input_types/options.py +++ b/src/marketdata/input_types/options.py @@ -64,7 +64,7 @@ class OptionsChainInput(BaseInputType): description="The strike price to filter by", default=None ) delta: float | None = Field(description="The delta to filter by", default=None) - strike_limit: float | None = Field( + strike_limit: int | None = Field( description="The strike limit to filter by", alias="strikeLimit", default=None ) range: str | None = Field(description="The range to filter by", default=None) diff --git a/src/tests/test_options_chain.py b/src/tests/test_options_chain.py index acf464f..a8477e0 100644 --- a/src/tests/test_options_chain.py +++ b/src/tests/test_options_chain.py @@ -5,6 +5,7 @@ import pytz from marketdata.input_types.base import OutputFormat +from marketdata.input_types.options import OptionsChainInput from marketdata.output_types.options_chain import ( OptionsChain, OptionsChainHumanReadable, @@ -307,3 +308,29 @@ def test_options_chain_input_date_range_aliases_on_wire(load_json, respx_mock, c assert params.get("to") == "2026-04-18" assert params.get("from_date") is None assert params.get("to_date") is None + + +def test_options_chain_input_strike_limit_typed_as_int(): + """Issue #24: `strike_limit` is a count of strikes, so an integer input + must be kept as an int instead of being coerced to a float. + """ + input_params = OptionsChainInput(strike_limit=10) + assert input_params.strike_limit == 10 + assert type(input_params.strike_limit) is int + + +def test_options_chain_strike_limit_is_int_on_wire(load_json, respx_mock, client): + """Issue #24: `strike_limit=10` must be sent as `strikeLimit=10`, not as the + float `strikeLimit=10.0` that the API rejects. + """ + mock_data = load_json("options_chain_response_200") + respx_mock.get("https://api.marketdata.app/v1/options/chain/AAPL/").respond( + json=mock_data, status_code=200 + ) + + client.options.chain( + "AAPL", strike_limit=10, output_format=OutputFormat.INTERNAL + ) + + params = respx_mock.calls.last.request.url.params + assert params.get("strikeLimit") == "10"