fix: align endpoint docs with upstream operations + interval normaliser#527
Merged
Conversation
Mirror the upstream operation spec at docs.thetadata.us/operations/ option_history_quote.html. The previous doc claimed `interval="0"` returned every quote change tick-by-tick; that value is not in the upstream enum and the SDK silently normalises it to `100ms`. Replace with the documented presets (tick / 10ms / .../ 1h) and default 1s. Mark `strike` and `right` optional (default `*` and `both`); they are optional at the wire level and the SDK builder treats them the same way. Correct `start_time` / `end_time` to HH:MM:SS.SSS wall-clock with the upstream defaults (09:30:00 / 16:00:00). Add `start_date` / `end_date` for multi-day requests and document the one-month / must- specify-expiration constraints called out by the upstream spec. Refs ThetaData v3 spec for /v3/option/history/quote.
Mirror the upstream operation specs at docs.thetadata.us/operations/
for the option_history_{trade, ohlc, eod, open_interest, trade_quote}
endpoints.
Common fixes across the family:
- strike and right are optional with default `*` and `both` (the SDK
was already constructing the wire wildcards through wire_strike_opt
/ wire_right_opt; only the doc badge was wrong).
- start_time / end_time take HH:MM:SS.SSS wall-clock with defaults
09:30:00 / 16:00:00, not 'milliseconds from midnight'.
- expiration accepts YYYY-MM-DD as well as YYYYMMDD, plus `*` for
all expirations.
- Add start_date / end_date as builder optionals; document the
single-`date` override semantics from upstream.
- Call out the upstream one-month / must-specify-expiration ceiling
on multi-day requests.
ohlc additionally pulls the new `tick` and `10ms` presets into the
interval enum and marks interval optional with default `1s`.
trade_quote additionally documents the `exclusive` flag with its
upstream `true` default.
Apply the same parity sweep to the 11 greeks endpoints:
option_history_greeks_{all, eod, implied_volatility, first_order,
second_order, third_order} and
option_history_trade_greeks_{all, implied_volatility, first_order,
second_order, third_order}.
For each:
- strike / right marked optional with upstream defaults (`*` / `both`)
- start_time / end_time documented as HH:MM:SS.SSS with the upstream
09:30:00 / 16:00:00 defaults
- expiration accepts YYYY-MM-DD and YYYYMMDD plus `*`
- interval (where applicable) marked optional, default `1s`, enum
extended to include `tick` and `10ms`
- Greeks inputs (annual_dividend, rate_type with full Treasury enum,
rate_value, version) documented with their upstream defaults and
allowed values
- start_date / end_date listed as builder optionals on the intraday
greeks endpoints; greeks_eod keeps start_date / end_date required
per upstream
- underlyer_use_nbbo (greeks_eod only) documents its `false` default
Multi-day one-month / must-specify-expiration ceiling called out where
upstream documents it.
Same parity sweep as the option/history family — strike and right are optional with default `*` and `both`; min_time on snapshot endpoints is HH:MM:SS.SSS, not milliseconds; expiration accepts YYYY-MM-DD and wildcard `*`; Greeks-input defaults documented. option_list_dates and option_list_contracts: request_type lower-case trade/quote is the upstream enum; SDK still accepts the historical TRADE/QUOTE casing. option_list_strikes already mirrored upstream exactly — no change needed.
Apply the same parity sweep to the stock and index history / snapshot / at_time pages. interval is optional with a `1s` default and the upstream enum extended to `tick` and `10ms`. start_time / end_time are documented as HH:MM:SS.SSS ET wall-clock with the upstream 09:30:00 / 16:00:00 defaults instead of 'milliseconds from midnight'. The `Use "0"` claim is removed across the board — the SDK does not have a tick-by-tick sentinel that maps to a real upstream value, and the doc was implying behaviour the wire does not expose. venue (stock-only) is documented with the upstream `nqb` / `utp_cta` enum and `nqb` default. min_time on stock snapshots takes the same HH:MM:SS.SSS form. stock_history_trade_quote: exclusive flag documented with the `true` upstream default.
normalize_interval now maps `"0"` to `"tick"` instead of `"100ms"`. The historical mapping contradicted the previously-documented every-event semantics — the upstream enum spells that as `tick`, and the SDK silently downgraded user requests to a 100ms sample without warning. Mapping `0` to `tick` makes the behaviour match the doc without breaking callers that picked an interval explicitly. The small-ms snap range now also exposes `10ms`, which is the upstream preset between `tick` and `100ms` that the SDK previously skipped. validate_interval (CLI / MCP entry point) now enforces the upstream enum verbatim plus the SDK's millisecond shorthand. Garbage strings like `"twosec"` are rejected up front with a typed error listing the accepted values, instead of being passed through to the gRPC layer where they used to surface as opaque server-side rejections. Mirrors the upstream operation specs at `docs.thetadata.us/operations/option_history_quote.html` (and the other 14 endpoints that carry an `interval` parameter).
…ntinel The earlier rewrite left a stale copy of the pre-alignment param list at the bottom of greeks_eod.md, which broke the VitePress build. Remove the duplicate and rewrite the option_history_eod multi-strike note to use the upstream `strike="*"` wildcard vocabulary instead of the SDK-only `"0"` sentinel that contradicted the rest of the alignment sweep.
21f9bc1 to
f8df8c2
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Audit the 60 hand-maintained
docs-site/docs/historical/**/*.mddoc pages against the upstream operation specs atdocs.thetadata.us/operations/*.html, fix every doc-parity issue surfaced by the audit, and harden the SDK'sintervalhandling so the runtime behaviour matches the doc.Triggered by a user report:
tdx.option_history_quote("QQQ", "*", "20260507").strike("*").right("both").interval("0")hung indefinitely. Two root causes were uncovered:docs-site/docs/historical/option/history/quote.mdclaimedinterval="0"returned every quote tick-by-tick. That value is not in the upstream enum (tick,10ms,100ms, ...,1h). The SDK silently mapped"0"to"100ms", so the user's intent (every quote) was downgraded to a 100ms sample without warning.expiration="*"on a liquid symbol the upstream MDDS server can take a long time to start emitting data. The TLS handshake completes, the gRPC stream opens, but no DATA frames arrive in the SDK's observation window. Root cause analysis in/tmp/wildcard-hang-rootcause.md: server-side query compilation latency (hypothesis H4). Out of scope for a hot fix in v10.0.0 — PR feat(grpc): in-house gRPC transport replacing tonic #524's in-house gRPC transport with per-call deadlines is the recommended landing place; the doc + validator changes here close the surface the user can hit immediately.Doc changes (47 markdown files)
Universal alignment
Every option doc that documents
strike/rightnow marks them optional with the upstream defaults (*/both). The SDK builder was already building the wire-side wildcards viawire_strike_opt/wire_right_opt; only the badge was wrong.start_time/end_timeare documented asHH:MM:SS.SSSET wall-clock with the upstream defaults (09:30:00/16:00:00), not as "milliseconds from midnight".expirationnow documents the upstream wildcard (*) and the alternateYYYY-MM-DDform.start_date/end_dateare added as builder optionals on every endpoint upstream documents them on. The one-month / must-specify-expiration multi-day ceiling is called out where upstream documents it.Interval enum
Every page with an
intervalparameter now lists the full upstream enum (tick,10ms,100ms,500ms,1s,5s,10s,15s,30s,1m,5m,10m,15m,30m,1h) and marksintervaloptional with the upstream1sdefault. The historical "Use\"0\"to get every quote change" claim is removed across the board.Greeks inputs
The history/greeks and history/trade_greeks pages now document
annual_dividend,rate_type(with the full Treasury enum andsofrdefault),rate_value,version(latest/1), andunderlyer_use_nbbo/use_market_valuewith their upstream defaults. The snapshot/greeks pages addstock_price,min_time, and the same overrides.Misc
option_list_dates/option_list_contracts:request_typenow points to the upstream lower-casetrade/quoteenum (SDK keeps the historical upper-case casing for back-compat).option_list_strikes: upstream surface only hassymbol+expiration; the SDK doc already matched — no change.stock_history_*:venuedocumented with thenqb/utp_ctaenum andnqbdefault.index_history_*,index_snapshot_*,index_at_time_*: same alignment sweep applied.Code changes
crates/thetadatadx/src/mdds/endpoints.rs::normalize_interval:"0"now snaps to"tick"(every-event) instead of"100ms". The historical mapping contradicted the previously-documented every-event semantics.0..=100ms snap range now exposes the10msupstream preset (1..=10→10ms,11..=100→100ms) instead of skipping it.crates/thetadatadx/src/mdds/validate.rs::validate_interval:"twosec"or"1minute"up front with a typedInvalidParamserror that lists the accepted values.Unit tests cover both the preset and ms-shorthand paths.
Wildcard-hang investigation
Hypothesis H4 (server-side query compilation latency for full-chain wildcard requests) remains the working theory. Methodology and full hypothesis chain documented in
/tmp/wildcard-hang-rootcause.md(kept out of the repo because it references the in-flight PR #524 transport work). The doc + validator changes here close the user-visible surface: callers no longer get the silent"0"→ 100ms downgrade and the doc no longer promises behaviour the wire doesn't expose.Test plan
cargo fmt --all -- --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspace(411 lib tests + doc-tests pass; 6 new tests added)python3 scripts/check_docs_consistency.py(api-reference, openapi, tier badges all ok)cd docs-site && npm run build(15.69s, clean)Files changed
crates/thetadatadx/src/mdds/{endpoints.rs, validate.rs}(code, +tests) and 45 markdown files underdocs-site/docs/historical/.