Skip to content

Add symbol resolution helpers (instrument_id → raw_symbol join)#38

Merged
tbeason merged 2 commits into
mainfrom
symbol-join
Jun 22, 2026
Merged

Add symbol resolution helpers (instrument_id → raw_symbol join)#38
tbeason merged 2 commits into
mainfrom
symbol-join

Conversation

@tbeason

@tbeason tbeason commented Jun 17, 2026

Copy link
Copy Markdown
Owner

Summary

Records carry only the opaque numeric hd.instrument_id. The human-readable symbol lives in Metadata.mappings as interval-keyed (raw_symbol, mapped_symbol, start_date, end_date) tuples. When a query is resolved with stype_out = INSTRUMENT_ID (the historical default), mapped_symbol is the decimal instrument-id string — so the table is really an interval-keyed instrument_id → raw_symbol map. This PR adds helpers to invert it and join the symbol back onto records.

New API

  • symbol_map(metadata) — build the instrument_id → [(start_date, end_date, raw_symbol)] lookup once for reuse in a hot loop.
  • symbol_for(map_or_metadata, instrument_id, ts_event) — resolve the raw_symbol valid at a record's hd.ts_event (half-open [start, end) intervals; nothing if unknown/out of range).
  • add_symbol_column!(df, metadata; column=:symbol) — join a symbol column onto a records DataFrame in place. Keys on the frame's instrument_id/ts_event, so it also covers the row-expanded MBP-10 frame; unmatched rows get missing.
  • records_to_dataframe(records, metadata; symbols=true) — convert + join in one call.

Notes

  • Non-INSTRUMENT_ID stype_out yields an empty map (single warning, missing column), since records can't be keyed back to the mapping.
  • Date math is pure integer (ns → YYYYMMDD), no float round-trip.
  • New test file test/test_symbols.jl (20 assertions) wired into runtests.jl; covers the map, lookup edge cases (inclusive start / exclusive end / id rolls / degenerate single-day interval), the DataFrame join, custom column name, the non-INSTRUMENT_ID warning path, and the empty-frame no-op.

🤖 Generated with Claude Code

Records carry only the opaque numeric hd.instrument_id; the human-readable
symbol lives in Metadata.mappings as interval-keyed
(raw_symbol, mapped_symbol, start_date, end_date) tuples. When a query is
resolved with stype_out = INSTRUMENT_ID (the historical default) the mapped
symbol is the decimal instrument-id string, making the table an interval-keyed
instrument_id -> raw_symbol map.

New helpers invert it and join the symbol back:
- symbol_map(metadata): build the id -> intervals lookup once for reuse
- symbol_for(map_or_metadata, instrument_id, ts_event): resolve symbol valid
  at a record's timestamp (half-open [start, end) intervals)
- add_symbol_column!(df, metadata; column=:symbol): join in place, keying on
  the frame's instrument_id/ts_event so it also covers the row-expanded MBP-10
  frame; unmatched rows get missing
- records_to_dataframe(records, metadata; symbols=true): convert + join

Non-INSTRUMENT_ID stype_out yields an empty map (single warning, missing
column) since records can't be keyed back to the mapping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The new symbol_map / symbol_for / add_symbol_column! docstrings cross-ref each
other and records_to_dataframe with [`...`](@ref); Documenter's cross_references
check fails unless the targets are spliced into a docs page. Add a "Symbol
Resolution" @docs block to the Conversion API reference.

Bump the package version to 0.1.4 so the symbol-resolution helpers can be
released (downstream DatabentoAPI.jl pins this as its minimum).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@tbeason tbeason merged commit d6ee3a4 into main Jun 22, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant