Add symbol_meta reader for per-symbol geometry sidecars

Implements #3: DataServer::symbol_meta(symbol) -> Option<InstrumentGeometry>
loads a <SYMBOL>.meta.json sidecar from the owned data directory and returns
neutral, broker-agnostic price geometry (digits, pip_size, tick_size,
lot_size, base, quote). A consumer can now obtain a symbol's bars and its
price-interpretation geometry from one server.

Design (forks logged on #3):
- Neutral output is the struct's shape/semantics, not currency-code
  normalization: base/quote pass through verbatim. The live sidecars carry
  wildly heterogeneous base codes (ISO, index codes, descriptive names, stock
  tickers) with no definable neutral target; the downstream consumer
  cross-checks them against its own vetted table.
- Format quirks are absorbed in a pure parser (meta::from_sidecar_bytes):
  scientific notation parses natively; a null / non-finite / missing core
  field or an unsupported schemaVersion yields None, never a partial struct.
- A missing sidecar is a normal None (silent); a present-but-unusable one
  warns to stderr, matching the existing loader's degrade-and-warn style.
- serde_json (Value extraction, no derive) is the new direct dependency,
  chosen over a hand-rolled parser for robust number/escape handling; the
  README dependency statement is updated to match.
- No caching and no Arc<Self>: geometry files are tiny and read rarely, and
  the read needs no prefetch. Lookup is not gated on bar-index membership.

Verified: cargo build and clippy clean (0 warnings); full suite green
(7 parser unit tests + 5 symbol_meta integration tests pin each absorbed
quirk and the index-independent lookup). Cargo.lock stays untracked per the
library convention.

closes #3
This commit is contained in:
2026-06-25 14:42:04 +02:00
parent a1ce14ccc7
commit be2489ac95
4 changed files with 287 additions and 1 deletions
+2 -1
View File
@@ -5,7 +5,7 @@ High-performance, thread-safe loader and cache for binary market data files
one `.bin` entry of tightly packed records; it is read and parsed exactly once,
then shared lock-free across many readers via `Arc<[T]>` chunks.
Standalone leaf crate — depends only on `chrono`, `regex`, `zip`.
Leaf crate — depends only on `chrono`, `regex`, `serde_json`, `zip`.
## Add as dependency
@@ -32,6 +32,7 @@ data-server = { git = "http://192.168.178.103:3000/Brummel/data-server.git", bra
| `has_symbol(symbol) -> bool` | Whether the symbol has any files. |
| `symbols() -> Vec<Arc<str>>` | All known symbols, sorted. |
| `file_count(symbol, DataFormat) -> Option<usize>` | Number of files for that symbol/format. |
| `symbol_meta(symbol) -> Option<meta::InstrumentGeometry>` | Neutral price geometry from the symbol's `<SYMBOL>.meta.json` sidecar; `None` if no usable sidecar exists. |
| `stream_m1(symbol)` / `stream_tick(symbol)` | `Option<SymbolChunkIter<_>>` over all data. |
| `stream_m1_windowed(symbol, from_ms, to_ms)` / `stream_tick_windowed(...)` | Same, restricted to an inclusive `[from_ms, to_ms]` Unix-millisecond window (`Option<i64>` bounds; files outside are skipped without I/O). |