diff --git a/cli/README.md b/cli/README.md index d450c0a..cd554ec 100644 --- a/cli/README.md +++ b/cli/README.md @@ -26,5 +26,4 @@ broker schema quote.snapshot - `--help` is available on all command groups - output is machine-first JSON in a stable envelope (`ok/data/error/meta`) -- `--strict` enables stricter empty-result validation where supported (`history`, `chain`) - when daemon is down, run `broker daemon status` and `broker daemon start` diff --git a/cli/src/_common.py b/cli/src/_common.py index fbf6cad..7432353 100644 --- a/cli/src/_common.py +++ b/cli/src/_common.py @@ -101,8 +101,6 @@ def build_meta( "request_id": request_id or str(uuid.uuid4()), "timestamp": datetime.now(UTC).isoformat(), } - if strict is not None: - meta["strict"] = strict return meta diff --git a/cli/src/main.py b/cli/src/main.py index 611029e..6c8d085 100644 --- a/cli/src/main.py +++ b/cli/src/main.py @@ -42,14 +42,9 @@ @app.callback() def root( ctx: typer.Context, - strict: bool = typer.Option( - False, - "--strict/--no-strict", - help="Enable strict mode for commands that can treat empty market payloads as errors.", - ), ) -> None: cfg = load_config() - ctx.obj = CLIState(config=cfg, json_output=True, strict=strict) + ctx.obj = CLIState(config=cfg, json_output=True, strict=False) def run() -> None: diff --git a/cli/src/market.py b/cli/src/market.py index 2a108ef..6257078 100644 --- a/cli/src/market.py +++ b/cli/src/market.py @@ -180,20 +180,13 @@ def chain( "--fields", help="Comma-separated entry fields to include. Defaults to all.", ), - strict: bool | None = typer.Option( - None, - "--strict/--no-strict", - help="Treat empty chain results as errors.", - ), ) -> None: state = get_state(ctx) command = "market.chain" - strict_mode = state.strict if strict is None else strict params: dict[str, object] = { "symbol": symbol, "limit": limit, "offset": offset, - "strict": strict_mode, } if expiry: params["expiry"] = expiry @@ -212,10 +205,10 @@ def chain( json_output=state.json_output, command=command, request_id=result.request_id, - strict=strict_mode, + strict=state.strict, ) except BrokerError as exc: - handle_error(exc, json_output=state.json_output, command=command, strict=strict_mode) + handle_error(exc, json_output=state.json_output, command=command, strict=state.strict) @app.command("history", help="Fetch historical bars for a symbol.") @@ -225,15 +218,9 @@ def history( period: HistoryPeriod = typer.Option(..., "--period", case_sensitive=False, help="1d, 5d, 30d, 90d, 1y"), bar: BarSize = typer.Option(..., "--bar", case_sensitive=False, help="1m, 5m, 15m, 1h, 1d"), rth_only: bool = typer.Option(False, "--rth-only", help="Restrict to regular trading hours."), - strict: bool | None = typer.Option( - None, - "--strict/--no-strict", - help="Treat empty history responses as errors.", - ), ) -> None: state = get_state(ctx) command = "market.history" - strict_mode = state.strict if strict is None else strict try: result = run_async( daemon_request( @@ -244,7 +231,6 @@ def history( "period": period.value, "bar": bar.value, "rth_only": rth_only, - "strict": strict_mode, }, ) ) @@ -253,10 +239,10 @@ def history( json_output=state.json_output, command=command, request_id=result.request_id, - strict=strict_mode, + strict=state.strict, ) except BrokerError as exc: - handle_error(exc, json_output=state.json_output, command=command, strict=strict_mode) + handle_error(exc, json_output=state.json_output, command=command, strict=state.strict) @app.command("capabilities", help="Show detected market-data capabilities for the connected provider.") diff --git a/daemon/src/broker_daemon/daemon/server.py b/daemon/src/broker_daemon/daemon/server.py index 85ac80c..ca60044 100644 --- a/daemon/src/broker_daemon/daemon/server.py +++ b/daemon/src/broker_daemon/daemon/server.py @@ -345,13 +345,6 @@ async def _dispatch(self, request: Request) -> dict[str, Any]: bar=bar, rth_only=bool(p.get("rth_only", False)), ) - if bool(p.get("strict", False)) and not bars: - raise BrokerError( - ErrorCode.INVALID_SYMBOL, - f"no historical bars returned for symbol '{symbol}'", - details={"symbol": symbol, "period": period, "bar": bar}, - suggestion="Use a valid symbol or disable strict mode with --no-strict.", - ) return {"bars": [b.model_dump(mode="json") for b in bars]} if cmd == "market.chain": @@ -383,19 +376,6 @@ async def _dispatch(self, request: Request) -> dict[str, Any]: if selected_fields: all_entries = [{field: entry.get(field) for field in selected_fields} for entry in all_entries] entries = all_entries[offset : offset + limit] - if bool(p.get("strict", False)) and not entries: - raise BrokerError( - ErrorCode.INVALID_SYMBOL, - f"no option contracts matched filters for '{symbol}'", - details={ - "symbol": symbol, - "expiry": p.get("expiry"), - "strike_range": raw_strike_range, - "offset": offset, - "limit": limit, - }, - suggestion="Relax filters, increase --limit, or disable strict mode with --no-strict.", - ) payload["entries"] = entries payload["pagination"] = { "total_entries": len(all_entries), @@ -982,7 +962,6 @@ def _cli_envelope_schema() -> dict[str, Any]: "command": {"type": "string"}, "request_id": {"type": "string"}, "timestamp": {"type": "string", "format": "date-time"}, - "strict": {"type": "boolean"}, }, "required": ["schema_version", "command", "request_id", "timestamp"], }, @@ -1055,7 +1034,6 @@ def _command_schema_registry() -> dict[str, dict[str, Any]]: "period": {"enum": ["1d", "5d", "30d", "90d", "1y"]}, "bar": {"enum": ["1m", "5m", "15m", "1h", "1d"]}, "rth_only": {"type": "boolean"}, - "strict": {"type": "boolean"}, }, "required": ["symbol"], }, @@ -1079,7 +1057,6 @@ def _command_schema_registry() -> dict[str, dict[str, Any]]: "limit": {"type": "integer", "minimum": 1}, "offset": {"type": "integer", "minimum": 0}, "fields": {"type": "array", "items": {"enum": sorted(OPTION_CHAIN_FIELDS)}}, - "strict": {"type": "boolean"}, }, "required": ["symbol"], }, diff --git a/daemon/tests/test_daemon/test_dispatch_validation.py b/daemon/tests/test_daemon/test_dispatch_validation.py index bc462eb..36fb72a 100644 --- a/daemon/tests/test_daemon/test_dispatch_validation.py +++ b/daemon/tests/test_daemon/test_dispatch_validation.py @@ -86,26 +86,6 @@ async def test_dispatch_market_capabilities_returns_payload(tmp_path) -> None: assert "cache_age_ms" in data["cache"] -@pytest.mark.asyncio -async def test_dispatch_history_strict_raises_on_empty(monkeypatch: pytest.MonkeyPatch, tmp_path) -> None: - server = DaemonServer(_test_config(tmp_path)) - server._provider.capabilities["history"] = True # noqa: SLF001 - - async def fake_history(**_: object) -> list[object]: - return [] - - monkeypatch.setattr(server._provider, "history", fake_history) # noqa: SLF001 - - req = Request( - command="market.history", - params={"symbol": "INVALID", "period": "5d", "bar": "1d", "strict": True}, - ) - - with pytest.raises(BrokerError) as exc: - await server._dispatch(req) # noqa: SLF001 - - assert exc.value.code == ErrorCode.INVALID_SYMBOL - @pytest.mark.asyncio async def test_dispatch_chain_applies_limit_offset_and_fields(monkeypatch: pytest.MonkeyPatch, tmp_path) -> None: diff --git a/sdk/python/src/broker_sdk/client.py b/sdk/python/src/broker_sdk/client.py index 71c4a12..66c5080 100644 --- a/sdk/python/src/broker_sdk/client.py +++ b/sdk/python/src/broker_sdk/client.py @@ -173,12 +173,10 @@ async def history( period: HistoryPeriod, bar: BarSize, rth_only: bool = False, - *, - strict: bool = False, ) -> list[dict[str, Any]]: data = await self._request( "market.history", - {"symbol": symbol, "period": period, "bar": bar, "rth_only": rth_only, "strict": strict}, + {"symbol": symbol, "period": period, "bar": bar, "rth_only": rth_only}, ) return data.get("bars", []) @@ -192,9 +190,8 @@ async def chain( limit: int = 200, offset: int = 0, fields: list[ChainField] | None = None, - strict: bool = False, ) -> dict[str, Any]: - params: dict[str, Any] = {"symbol": symbol, "limit": limit, "offset": offset, "strict": strict} + params: dict[str, Any] = {"symbol": symbol, "limit": limit, "offset": offset} if expiry: params["expiry"] = expiry if strike_range: diff --git a/sdk/typescript/src/client.ts b/sdk/typescript/src/client.ts index 463bb2f..3fe20b9 100644 --- a/sdk/typescript/src/client.ts +++ b/sdk/typescript/src/client.ts @@ -175,14 +175,12 @@ export class Client { period: HistoryPeriod, bar: BarSize, rthOnly = false, - strict = false ): Promise { return this.request("market.history", { symbol, period, bar, rth_only: rthOnly, - strict }); } @@ -191,7 +189,7 @@ export class Client { expiry?: string, strikeRange?: string, optionType?: OptionType, - options: { limit?: number; offset?: number; fields?: ChainField[]; strict?: boolean } = {} + options: { limit?: number; offset?: number; fields?: ChainField[] } = {} ): Promise { const params: CommandParams<"market.chain"> = { symbol }; if (expiry) { @@ -212,9 +210,6 @@ export class Client { if (options.fields) { params.fields = options.fields; } - if (options.strict !== undefined) { - params.strict = options.strict; - } return this.request("market.chain", params); } diff --git a/sdk/typescript/src/commands.ts b/sdk/typescript/src/commands.ts index 42db551..c81c98f 100644 --- a/sdk/typescript/src/commands.ts +++ b/sdk/typescript/src/commands.ts @@ -60,7 +60,6 @@ export interface CommandMap { period: HistoryPeriod; bar: BarSize; rth_only?: boolean; - strict?: boolean; }, MarketHistoryResponse >; @@ -73,7 +72,6 @@ export interface CommandMap { limit?: number; offset?: number; fields?: ChainField[]; - strict?: boolean; }, OptionChainResponse >; diff --git a/website/app/reference/page.tsx b/website/app/reference/page.tsx index e954a9e..80cb336 100644 --- a/website/app/reference/page.tsx +++ b/website/app/reference/page.tsx @@ -139,8 +139,7 @@ export default function ReferencePage() { Complete reference for every broker-cli command. Every response uses a stable JSON envelope: {`{ok,data,error,meta}`} with request IDs for tracing and audit correlation. - Use global --strict (or command-level strict flags where available) - when agents should treat empty market payloads as errors. + Use supported flags where available and note command-specific behavior in each section.

@@ -261,7 +260,6 @@ export default function ReferencePage() { { flag: "--limit INT", description: "Max entries returned after filtering", default: "200" }, { flag: "--offset INT", description: "Offset into filtered entries", default: "0" }, { flag: "--fields LIST", description: "Comma-separated entry fields (e.g. strike,expiry,bid,ask)" }, - { flag: "--strict / --no-strict", description: "Error if no entries match filters" }, ]} example={`$ broker chain AAPL --type call --strike-range 0.95:1.05 --limit 5 --fields strike,expiry,bid,ask\n{"ok":true,"data":{"symbol":"AAPL","underlying_price":263.3,"entries":[{"strike":252.5,"expiry":"2026-02-20","bid":null,"ask":null}],"pagination":{"total_entries":80,"offset":0,"limit":5,"returned_entries":5},"fields":["strike","expiry","bid","ask"]},"error":null,"meta":{"schema_version":"v1","command":"market.chain","request_id":"...","timestamp":"..."}}`} /> @@ -273,7 +271,6 @@ export default function ReferencePage() { { flag: "--period 1d|5d|30d|90d|1y", description: "Lookback period" }, { flag: "--bar 1m|5m|15m|1h|1d", description: "Bar size" }, { flag: "--rth-only", description: "Restrict to regular trading hours" }, - { flag: "--strict / --no-strict", description: "Error when no bars are returned" }, ]} example={`$ broker history AAPL --period 5d --bar 1h\n{"ok":true,"data":[{"symbol":"AAPL","time":"2026-02-18T00:00:00","open":265.1,"close":263.29}],"error":null,"meta":{"schema_version":"v1","command":"market.history","request_id":"...","timestamp":"..."}}`} notes="Available on Interactive Brokers only."