Commit 0992c92
feat(ssot)!: TOML render map, generated tdbe ticks, per-endpoint typed Greeks (#475)
* feat(build): TOML-driven render map collapses 19 helper match arms (refs #474)
Every per-language binding name a renderer needs for one tick type --
Rust direct-client return type, generated parser fn, Go struct +
converter, FFI array struct + free fn + output variant + header-return
type, C++ value type, six Python converters (dict, columnar,
pyclass-list, pyclass-list-class, vec-to-pylist, slice-arrow),
TypeScript class + class-vec converter, plus the Python pyclass struct
name -- now lives in `[types.X.render]` blocks in
`crates/thetadatadx/tick_schema.toml`.
The 20 helper functions that previously hardcoded those names with
parallel `match` dispatches collapse into single HashMap lookups
against a `OnceLock`-cached load of the schema:
* `build_support/endpoints/helpers.rs::direct_return_type` /
`direct_parser_name` / `go_result_type` / `go_converter_name` /
`ffi_array_type` / `ffi_array_empty_expr` / `ffi_output_variant` /
`ffi_from_vec_array_type` / `ffi_header_return_type` / `ffi_free_fn`
/ `cpp_value_type` / `cpp_converter_expr` / `python_converter` /
`python_columnar_converter` / `python_pyclass_list_converter` /
`python_pyclass_list_class` / `python_vec_to_pylist_converter` /
`python_slice_arrow_converter` / `ts_class_name` /
`ts_class_vec_converter`
* `build_support/ticks/mod.rs::pyclass_name`
Adding a tick type now requires one TOML row -- no helper edits. The
generated SDK surfaces (sdks/{python,typescript,go,cpp}/...) are
byte-identical against main because the new TOML rows reproduce the
names the helpers previously hardcoded; the `--check` regen pass
shows zero drift.
Sets up the SSOT foundation for the per-endpoint typed Greeks structs
and tdbe tick struct generation tracked in #474; those land in
follow-up PRs to keep this change reviewable.
CI gates locally: cargo fmt, cargo clippy --all-targets -D warnings,
cargo test --workspace, cargo deny check, and `generate_sdk_surfaces
--check` are all clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(build): collapse per-tick match arms onto schema render block
Drive the FFI sizes / layout asserts / Go converter dispatch / Python
list-fn / TS class-vec / CLI raw-header constants from `tick_schema.toml`
[types.X.render] entries instead of hand-coded match arms. Adding a tick
type now requires zero edits in `build_support/ticks/{cpp,go,python_classes,
typescript,cli_headers}.rs`.
* `OpenInterestTick` and `TradeQuoteTick` gained `align = 64` in the
schema -- they were `#[repr(C, align(64))]` in `tdbe::types::tick` but
the schema row was missing the directive, so the Go/C++ FFI size
emitters under-counted (32/144 vs the actual 64/192). The hand-coded
emitters compensated by reading `size_of::<tdbe::T>()` directly; with
the schema as the SSOT the directive must live there.
* `cpp.rs` now reaches into `go::tick_ffi_size_and_align` for the
schema-computed (size, align) pair instead of `size_of::<tdbe::T>()`,
so the C++ static_asserts share one layout calculator with Go.
* Dropped the dead `pub(crate) use ts_tick_class_factory_name`
re-export (no remaining caller outside the typescript emitter).
refs #474
* feat(tdbe): generate tick structs from tick_schema.toml
`crates/tdbe/src/types/tick_generated.rs` is now emitted by
`generate_sdk_surfaces` from the schema. Hand-written `tick.rs`
`include!`s the generated file and keeps only the items the schema
cannot express: `impl_contract_id!` macro applications, `TradeTick`
flag helpers, and `OptionContract` is_call/is_put.
Layout asserts in `types::tick::layout_asserts` pin every struct's
size + alignment to the values the C / Go FFI mirrors and
`tick_layout_asserts.hpp.inc` rely on, so a schema edit that drifts a
layout fails `cargo test -p tdbe` before reaching the FFI side.
refs #474
* feat(greeks)!: per-endpoint typed Greeks structs (closes #474)
Split the union `GreeksTick` into the four shapes the v3 server actually
emits across the `option_*_greeks_*` family. The full union becomes
`GreeksAllTick` (returned by `_greeks_all` and `_greeks_eod`); the
per-order endpoints (`_first_order`, `_second_order`, `_third_order`)
return strict subsets matching the upstream OpenAPI -- no zero-default
columns leak from one subset into another.
`GreeksAllTick` adds `bid`, `ask`, `underlying_ms_of_day`, and
`underlying_price` columns the OpenAPI publishes that the legacy
`GreeksTick` was missing. `decode.rs::HEADER_ALIASES` gains
`underlying_ms_of_day` -> `underlying_timestamp` so the wire
Timestamp -> ms-of-day conversion flows through `row_number` on every
Greeks endpoint.
C ABI surface
- Add `tdx_greeks_all_tick_array_free`,
`tdx_greeks_first_order_tick_array_free`,
`tdx_greeks_second_order_tick_array_free`,
`tdx_greeks_third_order_tick_array_free`. Matching FFI array structs
shipped on every binding.
- Drop `tdx_greeks_tick_array_free`. Callers update to the typed free
fn. No forwarding shim.
Layout safety
- Per-field `offset_of!` asserts in
`crates/tdbe/src/types/tick.rs::layout_asserts` pin every observable
Rust field offset that the C / Go FFI mirrors index into. Catches
the field-order regression class that `size_of` checks miss (e.g.
swapping two same-size fields keeps total size constant).
- `QuoteTick.midpoint` now emits AFTER the `contract_id` triple in
`tick_generated.rs` to match the legacy `tick.rs` order the C header
and Go FFI mirror were already shipping.
- Drop the unused `ffi_array_empty` row from the schema render block
and `ffi_array_empty_expr` helper. The FFI emitter hard-codes
`data: ptr::null()` for every `*const T`-pointer array; the row was
dead and its `null_mut()` literal would have produced a const/mut
mismatch if anyone wired it through.
refs #474
* fix(mcp): map per-endpoint Greeks tick variants
Wire serializers for GreeksAllTick / GreeksFirstOrderTick /
GreeksSecondOrderTick / GreeksThirdOrderTick onto the matching
EndpointOutput variants emitted by the generator. The MCP binary
referenced the deleted GreeksTick / EndpointOutput::GreeksTicks names
and failed to build.
Add explicit cargo check for tools/mcp and tools/server in the
Extended Surfaces job so out-of-workspace binaries can no longer
silently regress on a workspace rename.
* feat(tdbe): generate per-field offset asserts for every tick
Promote the hand-written tdbe layout asserts to a generator-emitted
crates/tdbe/src/types/tick_layout_asserts_generated.rs included from
tick.rs. Coverage now includes size_of / align_of AND offset_of! for
every column on every tick struct in tick_schema.toml -- including
EodTick, OhlcTick, TradeQuoteTick, IvTick, MarketValueTick,
OpenInterestTick, PriceTick, CalendarDay, InterestRateTick, which
previously only had size/align checks.
Extend the C++ layout-assert emitter to mirror the same offset table
into sdks/cpp/include/tick_layout_asserts.hpp.inc as
static_assert(offsetof(...) == ...) lines so a Rust struct field
reorder fails the C++ build at the same point it fails cargo test.
Adding a tick type to tick_schema.toml now picks up Rust + Go + C++
field-offset coverage automatically; no helper edit required.
* fix(go): emit IV uniformly across every Greeks tick struct
The legacy `("GreeksTick", "implied_volatility") => "IV"` special-case
no longer fires after the type rename, so the four new per-order Greeks
structs (`GreeksAllTick` / `GreeksFirstOrderTick` /
`GreeksSecondOrderTick` / `GreeksThirdOrderTick`) fell through to the
default `go_pascal_case` path and exposed `ImpliedVolatility` while the
existing `IVTick` kept emitting `IV`. Replace the per-type arms with a
single `(_, \"implied_volatility\") => \"IV\"` rule so every Greeks
struct AND `IVTick` now expose the same Go field name.
Renaming `IVTick.IV` was rejected as the larger source-breaking
change; `IV` is the historical Go SDK convention since v3.
* test(decode): value-check per-order Greeks parsers
The new `parse_greeks_first_order_ticks`, `parse_greeks_second_order_ticks`,
and `parse_greeks_third_order_ticks` parsers were only exercised by
`is_empty()`-style coverage; the existing decode tests called
`parse_greeks_all_ticks` against per-order column subsets, not the
dedicated parsers.
Add three tests that synthesise the exact wire shape each vendor
endpoint publishes (column lists pinned to
`items_option_snapshot_greeks_*_order` in
`scripts/upstream_openapi.yaml`) and assert every decoded field --
including `bid`, `ask`, the underlying snapshot pair, and `date` --
against the input row's known values. A future regression in any
field on any per-order parser surfaces here.
* test(decode): assert HEADER_ALIASES values in greeks_all fixture
The captured `option_history_greeks_all` fixture exercises two
`HEADER_ALIASES` rewrites -- `implied_vol` -> `implied_volatility` and
`underlying_timestamp` -> `underlying_ms_of_day` -- but the test only
asserted the decoded `delta` and `iv_error` values; either alias could
silently regress to default-zero without any test failing.
Anchor the decoded `implied_volatility`, `underlying_ms_of_day`, and
`underlying_price` (plus `date`) against known first-row values from
the captured payload so an alias-table breakage surfaces here, not at
runtime in production traffic.
* test(frames): assert columns / dtypes / values for per-order Greeks
The new GreeksFirstOrderTick / GreeksSecondOrderTick /
GreeksThirdOrderTick frames coverage in test_frames_arrow.rs and
test_frames_polars.rs was compile-time only -- the
`every_tick_type_has_*_impl` checks proved the trait was implemented
but no test asserted column count, exact column order, dtype per
column, or any decoded value.
Add three Arrow tests + three Polars tests, one per per-order Greeks
struct, that pin:
* total column count,
* exact column order,
* dtype per column (Int32 / Float64 / Utf8 or polars `String`),
* one row's value for every column read back through the typed
Arrow / Polars getters.
A schema reorder, dtype regression, or per-column emitter typo on
build_support/ticks/rust_frames.rs now surfaces here at test time.
* test(decode): pin implied_vol alias decode against non-zero value (refs #474)
Add a synthetic alias-decode test that drives `parse_greeks_all_ticks`
with headers using ONLY the v3 server-side names (`implied_vol`,
`underlying_timestamp`) and non-zero values (IV = 0.42, underlying
ms-of-day = 34_200_000). A broken `implied_vol -> implied_volatility`
alias would silently zero-default via `opt_float(None)` and the
fixture-driven capture test cannot catch it because the recorded
`first_row_implied_volatility` happens to be `0.0`.
* fix(mcp): rename test code GreeksTick to GreeksAllTick
CI gate `cargo test --manifest-path tools/mcp/Cargo.toml --locked` failed
because `cargo check` (run locally) does not compile test code. Test
target still imported the deleted `GreeksTick` and called the renamed
`serialize_greeks_ticks`. Update sample helper to construct
`GreeksAllTick` with the new `bid`/`ask`/`underlying_ms_of_day`/
`underlying_price` fields and rename two call sites.
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent cae1d38 commit 0992c92
55 files changed
Lines changed: 6610 additions & 1683 deletions
File tree
- .github/workflows
- crates
- tdbe/src/types
- thetadatadx
- build_support
- endpoints
- render
- ticks
- src
- mdds
- tests
- fixtures/captures
- docs-site/docs
- ffi/src
- sdks
- cpp
- include
- src
- go
- python/src
- typescript
- src
- tools
- cli/src
- mcp/src
- server/src
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
| 94 | + | |
94 | 95 | | |
95 | 96 | | |
| 97 | + | |
96 | 98 | | |
97 | 99 | | |
98 | 100 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
12 | 91 | | |
13 | 92 | | |
14 | 93 | | |
| |||
30 | 109 | | |
31 | 110 | | |
32 | 111 | | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
33 | 128 | | |
34 | 129 | | |
35 | 130 | | |
| |||
0 commit comments