You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/api-reference.md
+69-6Lines changed: 69 additions & 6 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -589,9 +589,54 @@ let table = client.raw_query(|mut stub| {
589
589
}).await?;
590
590
```
591
591
592
+
### Streaming `_stream` Endpoint Variants
593
+
594
+
These variants process gRPC response chunks via callback without materializing the full response in memory. Ideal for endpoints returning millions of rows.
DirectClient exposes **61 typed methods** covering all 60 gRPC RPCs in `BetaThetaTerminal` plus 1 convenience range-query variant (`stock_history_ohlc_range`). All 61 methods are generated by the `define_endpoint!` macro in `direct.rs`.
@@ -726,12 +771,19 @@ All subscription methods return the request ID. The server confirms via a `ReqRe
726
771
727
772
### FpssEvent
728
773
729
-
Events received through the channel:
774
+
Events received through the ring buffer. `FpssEvent` is a 3-variant wrapper around `FpssData` (market data), `FpssControl` (lifecycle), and `RawData` (unparsed frames):
730
775
731
776
```rust
732
777
pubenumFpssEvent {
733
-
LoginSuccess { permissions:String },
734
-
ContractAssigned { id:i32, contract:Contract },
778
+
/// Market data events — quote, trade, open interest, OHLCVC.
**Migration from v1.1.x**: Replace `FpssEvent::Quote { .. }` with `FpssEvent::Data(FpssData::Quote { .. })`, and `FpssEvent::MarketOpen` with `FpssEvent::Control(FpssControl::MarketOpen)`, etc. The `RawData` variant remains unchanged.
813
+
814
+
### OhlcvcAccumulator
815
+
816
+
OHLCVC bars are derived from trade ticks via the internal `OhlcvcAccumulator`. The accumulator is per-contract and only begins emitting `FpssData::Ohlcvc` events after receiving a server-seeded initial OHLCVC bar. Subsequent trades update the bar's open/high/low/close/volume/count fields incrementally. This matches the Java terminal's behavior.
Copy file name to clipboardExpand all lines: docs/architecture.md
+28-2Lines changed: 28 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -147,9 +147,10 @@ flowchart TD
147
147
148
148
If the `compression_description.algo` field contains an unrecognized algorithm, `decompress_response` returns `Error::Decompress` rather than silently treating the data as uncompressed.
149
149
150
-
Two response processing modes are available:
151
-
-**`collect_stream`** (default): materializes all chunks into a single merged `DataTable`. Uses `original_size` from the compression description as a pre-allocation hint for the decompression buffer.
150
+
Three response processing modes are available:
151
+
-**`collect_stream`** (default): materializes all chunks into a single merged `DataTable`. Uses `original_size` from the compression description as a pre-allocation hint for the decompression buffer. The decompressor uses a slab-recycled thread-local `(Decompressor, Vec<u8>)` pair — the internal buffer retains its capacity across calls, avoiding allocator pressure for repeated decompressions.
152
152
-**`for_each_chunk`**: streaming callback that processes each chunk individually without accumulating the full response in memory.
153
+
-**`_stream` endpoint variants**: `stock_history_trade_stream`, `stock_history_quote_stream`, `option_history_trade_stream`, `option_history_quote_stream` — these combine the gRPC call with `for_each_chunk` processing in a single method call, ideal for endpoints returning millions of rows.
153
154
154
155
## FPSS Protocol (Real-Time Streaming)
155
156
@@ -285,6 +286,31 @@ After successful authentication, the client waits 2000ms before sending the firs
285
286
286
287
FPSS event dispatch uses a lock-free disruptor ring buffer (`disruptor-rs` v4), matching Java's LMAX Disruptor pattern. This eliminates channel overhead on the hot path and provides bounded-latency event delivery. The FPSS I/O thread is fully synchronous -- no tokio in the streaming hot path.
287
288
289
+
Events delivered through the ring buffer use a split enum:
This split enables callers to `match` on data events without touching lifecycle logic, and vice versa.
295
+
296
+
### OHLCVC-from-Trade Derivation
297
+
298
+
The `OhlcvcAccumulator` derives OHLCVC bars from trade ticks in real time. Behavior:
299
+
1. The accumulator is **not active** until the server sends an initial OHLCVC bar (server-seeded).
300
+
2. After initialization, each incoming trade updates open/high/low/close/volume/count.
301
+
3. Derived OHLCVC events are emitted as `FpssEvent::Data(FpssData::Ohlcvc { .. })` alongside the trade event.
302
+
4. One accumulator per contract, stored in a `HashMap<i32, OhlcvcAccumulator>`.
303
+
304
+
This matches the Java terminal's behavior: OHLCVC bars are never emitted purely from trades without a server-provided seed.
305
+
306
+
### SIMD FIT Decoding
307
+
308
+
On x86_64 with SSE2, the FIT decoder uses SIMD-accelerated bulk nibble extraction:
309
+
-`chunk_has_special_nibbles()` — scans 16 bytes for field/row separators and negative markers
310
+
-`extract_nibbles_simd()` — unpacks high/low nibbles from 16 bytes in parallel
311
+
312
+
The SIMD pre-scan amortizes branch misprediction cost in the scalar decoder. Results are bit-identical to the scalar path. Non-x86_64 platforms fall back to scalar.
313
+
288
314
FPSS streaming is available in all SDKs:
289
315
-**Rust**: `FpssClient::connect()` returns a disruptor-backed event receiver
290
316
-**Python**: `FpssClient` class with `subscribe()`, `next_event()`, `shutdown()`
0 commit comments