Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:**
Expand Down
2 changes: 1 addition & 1 deletion src/marketdata/input_types/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 27 additions & 0 deletions src/tests/test_options_chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"
Loading