diff --git a/options_scraper.py b/options_scraper.py index c0bfe38..3db8b59 100644 --- a/options_scraper.py +++ b/options_scraper.py @@ -30,6 +30,16 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: " no --expiration is provided)." ), ) + parser.add_argument( + "--exp-start", + type=int, + help="Start index (0-based) into the available expirations list.", + ) + parser.add_argument( + "--exp-end", + type=int, + help="End index (0-based, exclusive) into the available expirations list.", + ) parser.add_argument( "--calls-only", action="store_true", @@ -44,6 +54,14 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: if args.calls_only and args.puts_only: parser.error("Use only one of --calls-only or --puts-only.") + if args.expiration and (args.exp_start is not None or args.exp_end is not None): + parser.error("Use either --expiration or the exp-start/exp-end range, not both.") + if args.all_expirations and (args.exp_start is not None or args.exp_end is not None): + parser.error("Use either --all-expirations or the exp-start/exp-end range, not both.") + if args.exp_start is not None and args.exp_start < 0: + parser.error("--exp-start must be non-negative.") + if args.exp_end is not None and args.exp_end < 0: + parser.error("--exp-end must be non-negative.") return args @@ -53,6 +71,8 @@ def pick_expirations( requested: str | None, include_all: bool, default_limit: int | None, + range_start: int | None, + range_end: int | None, ) -> tuple[list[str], list[str]]: available = list(ticker.options or []) if not available: @@ -64,6 +84,17 @@ def pick_expirations( f"Expiration {requested!r} not in available dates: {', '.join(available)}" ) targets = [requested] + elif range_start is not None or range_end is not None: + start = range_start or 0 + end = range_end if range_end is not None else len(available) + if start >= len(available): + raise ValueError( + f"--exp-start {start} is beyond available expirations (max index {len(available) - 1})." + ) + end = min(end, len(available)) + if start >= end: + raise ValueError("--exp-start must be less than --exp-end.") + targets = available[start:end] elif include_all: targets = available else: @@ -113,12 +144,19 @@ def main(argv: list[str] | None = None) -> int: default_limit = ( DEFAULT_EXPIRATION_LIMIT if args.expiration is None and not args.all_expirations else None ) + range_start = args.exp_start + range_end = args.exp_end ticker = yf.Ticker(args.symbol) try: target_expirations, available_expirations = pick_expirations( - ticker, args.expiration, include_all_expirations, default_limit + ticker, + args.expiration, + include_all_expirations, + default_limit, + range_start, + range_end, ) except (ValueError, RuntimeError) as exc: print(f"error: {exc}", file=sys.stderr)