thetadatadx 8.0.26 → 8.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +26 -20
  2. package/index.d.ts +40 -15
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -36,14 +36,19 @@ async function main() {
36
36
  // With timeout
37
37
  const snap = tdx.stockSnapshotQuote(['AAPL', 'MSFT'], null, null, 5000);
38
38
 
39
- // Streaming — `nextEvent` is async; `await` it or you'll get a
40
- // `Promise` object back and `event.kind` will be `undefined`.
41
- tdx.startStreaming();
39
+ // Streaming — register a callback. napi-rs `ThreadsafeFunction`
40
+ // routes every event through libuv's `uv_async_t` queue onto the
41
+ // Node main thread; the callback runs there, decoupled from the
42
+ // FPSS reader thread. A slow callback fills the SSOT dispatcher's
43
+ // bounded queue and overflow events are dropped (observable via
44
+ // `tdx.droppedEventCount()`); the FPSS TLS reader is never blocked.
45
+ tdx.startStreaming((event) => {
46
+ if (event.kind === 'quote') {
47
+ console.log(event.quote.bid, event.quote.ask);
48
+ }
49
+ });
42
50
  tdx.subscribeQuotes('AAPL');
43
- const event = await tdx.nextEvent(1000); // poll with 1s timeout
44
- if (event && event.kind === 'quote') {
45
- console.log(event.quote.bid, event.quote.ask);
46
- }
51
+ // ...do other work; the callback fires on incoming events...
47
52
  tdx.stopStreaming();
48
53
  }
49
54
 
@@ -60,20 +65,21 @@ the Rust side, so the full typed surface lives in `index.d.ts`
60
65
  import type { OhlcTick, GreeksTick, Quote, Trade, FpssEvent } from 'thetadatadx';
61
66
  ```
62
67
 
63
- Historical endpoints return `Tick[]`; `nextEvent()` is async and resolves
64
- to a discriminated `FpssEvent | null` union, narrowed on `event.kind`:
68
+ Historical endpoints return `Tick[]`. Streaming events arrive through the
69
+ `startStreaming(callback)` registration; the callback receives a
70
+ discriminated `FpssEvent`, narrowed on `event.kind`:
65
71
 
66
72
  ```ts
67
- const event = await tdx.nextEvent(1000);
68
- if (!event) return; // timeout
69
- switch (event.kind) {
70
- case 'quote': /* event.quote is Quote */ break;
71
- case 'trade': /* event.trade is Trade */ break;
72
- case 'ohlcvc': /* event.ohlcvc is Ohlcvc */ break;
73
- case 'open_interest': /* event.openInterest is OpenInterest */ break;
74
- case 'simple': /* event.simple is FpssSimplePayload */ break;
75
- case 'raw_data': /* event.rawData is FpssRawDataPayload */ break;
76
- }
73
+ tdx.startStreaming((event: FpssEvent) => {
74
+ switch (event.kind) {
75
+ case 'quote': /* event.quote is Quote */ break;
76
+ case 'trade': /* event.trade is Trade */ break;
77
+ case 'ohlcvc': /* event.ohlcvc is Ohlcvc */ break;
78
+ case 'open_interest': /* event.openInterest is OpenInterest */ break;
79
+ case 'simple': /* event.simple is FpssSimplePayload */ break;
80
+ case 'raw_data': /* event.rawData is FpssRawDataPayload */ break;
81
+ }
82
+ });
77
83
  ```
78
84
 
79
85
  The `kind` field is typed as the string-literal union
@@ -87,7 +93,7 @@ including Vite, esbuild, ts-jest, and Next.js.
87
93
 
88
94
  Anywhere a Rust `u64` or `i64` crosses the napi boundary it surfaces as
89
95
  JavaScript `bigint` (not `number`): `volume` and `count` on every
90
- OHLC / EOD tick, `droppedEvents()` on the streaming client, and
96
+ OHLC / EOD tick, `droppedEventCount()` on the streaming client, and
91
97
  `received_at_ns` on every FPSS event. Use `bigint` literal syntax
92
98
  (`42n`) for comparisons or widen to `Number(x)` at the point of
93
99
  display (watch for loss of precision beyond 2^53).
package/index.d.ts CHANGED
@@ -9,18 +9,19 @@ export declare class ThetaDataDx {
9
9
  /** Connect with a credentials file (line 1 = email, line 2 = password). */
10
10
  static connectFromFile(path: string): ThetaDataDx
11
11
  /**
12
- * Cumulative count of FPSS events dropped because the JS polling
13
- * side disconnected before the FPSS callback could hand them off.
12
+ * Cumulative count of FPSS events dropped because the SSOT
13
+ * `StreamingDispatcher`'s bounded queue overflowed before the
14
+ * drain thread could hand the event off to the JS callback.
14
15
  *
15
- * Counter lives on the client instance (not inside the
16
- * `start_streaming` / `reconnect` closures), so the value survives
17
- * reconnect and is observable at any point before streaming,
18
- * during, or after `shutdown()`.
16
+ * Forwards to `thetadatadx::ThetaDataDx::dropped_event_count` so
17
+ * the value matches every other binding (C ABI, Python, future
18
+ * C++) and survives reconnect the dispatcher carries the count
19
+ * across `start_streaming` / `reconnect` cycles.
19
20
  *
20
21
  * Returned as `bigint` so it can represent the full `u64` range
21
22
  * (Number would top out at 2^53).
22
23
  */
23
- droppedEvents(): bigint
24
+ droppedEventCount(): bigint
24
25
  /**
25
26
  * List all available stock ticker symbols.
26
27
  *
@@ -760,8 +761,27 @@ export declare class ThetaDataDx {
760
761
  * - `venue`: `"nqb"`
761
762
  */
762
763
  stockHistoryOHLCRange(symbol: string, startDate: string | Date, endDate: string | Date, interval?: string | undefined | null, startTime?: string | Date | undefined | null, endTime?: string | Date | undefined | null, venue?: string | undefined | null, timeoutMs?: number | undefined | null): Array<OhlcTick>
763
- /** Start FPSS streaming. Events are buffered; poll with next_event(). */
764
- startStreaming(): void
764
+ /**
765
+ * Start FPSS streaming and register a JS callback for incoming events.
766
+ *
767
+ * The dispatcher's drain thread routes every typed FPSS event through
768
+ * napi-rs `ThreadsafeFunction` to the Node main thread, where the user's
769
+ * `callback(event)` runs. The FPSS reader thread itself never touches V8:
770
+ * events cross the bounded `crossbeam_channel(8192)` queue inside the
771
+ * SSOT `StreamingDispatcher` first.
772
+ *
773
+ * Node's libuv requires JS callbacks on the main thread, so
774
+ * `ThreadsafeFunction` (with its internal `uv_async_t` queue) is the only
775
+ * safe path. This binding deliberately does NOT expose a
776
+ * `start_streaming_inline` opt-in: calling into V8 from any thread other
777
+ * than the main loop is undefined behavior.
778
+ *
779
+ * Backpressure: a slow callback fills the dispatcher queue and overflow
780
+ * events are dropped, observable via `droppedEventCount()`. The FPSS TLS
781
+ * reader is never blocked — vendor disconnects on slow consumers cannot
782
+ * happen on this path.
783
+ */
784
+ startStreaming(callback: (event: FpssEvent) => void): void
765
785
  /** Whether the streaming connection is active. */
766
786
  isStreaming(): boolean
767
787
  /** Subscribe to real-time quote data for a stock symbol. */
@@ -802,9 +822,14 @@ export declare class ThetaDataDx {
802
822
  contractLookup(id: number): string | null
803
823
  /** Get a snapshot of currently active subscriptions. */
804
824
  activeSubscriptions(): any
805
- /** Poll for the next FPSS event. */
806
- nextEvent(timeoutMs: number): Promise<({ kind: 'ohlcvc'; ohlcvc: Ohlcvc } | { kind: 'open_interest'; openInterest: OpenInterest } | { kind: 'quote'; quote: Quote } | { kind: 'trade'; trade: Trade } | { kind: 'simple'; simple: FpssSimplePayload } | { kind: 'raw_data'; rawData: FpssRawDataPayload }) | null>
807
- /** Reconnect streaming and re-subscribe all previous subscriptions. */
825
+ /**
826
+ * Reconnect FPSS streaming and re-register the previously installed callback.
827
+ *
828
+ * Requires a prior `startStreaming(callback)`; throws if no callback is
829
+ * registered. All active subscriptions are restored on the new connection
830
+ * — see `thetadatadx::ThetaDataDx::reconnect_streaming` for partial-failure
831
+ * semantics.
832
+ */
808
833
  reconnect(): void
809
834
  /** Stop streaming while keeping the historical client usable. */
810
835
  stopStreaming(): void
@@ -826,9 +851,9 @@ export interface CalendarDay {
826
851
  * event as `event.quote.contract` / `event.trade.contract` / etc.
827
852
  */
828
853
  export interface Contract {
829
- root: string
854
+ symbol: string
830
855
  secType: number
831
- expDate?: number
856
+ expiration?: number
832
857
  isCall?: boolean
833
858
  strike?: number
834
859
  }
@@ -1096,7 +1121,7 @@ export interface OpenInterestTick {
1096
1121
 
1097
1122
  /** Option contract. Contract specification. */
1098
1123
  export interface OptionContract {
1099
- root: string
1124
+ symbol: string
1100
1125
  expiration: number
1101
1126
  strike: number
1102
1127
  right: string
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "thetadatadx",
3
- "version": "8.0.26",
3
+ "version": "8.0.30",
4
4
  "description": "Native ThetaData SDK for Node.js — powered by Rust via napi-rs",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -30,9 +30,9 @@
30
30
  "@napi-rs/cli": "^3.6.2"
31
31
  },
32
32
  "optionalDependencies": {
33
- "thetadatadx-linux-x64-gnu": "8.0.26",
34
- "thetadatadx-darwin-arm64": "8.0.26",
35
- "thetadatadx-win32-x64-msvc": "8.0.26"
33
+ "thetadatadx-linux-x64-gnu": "8.0.30",
34
+ "thetadatadx-darwin-arm64": "8.0.30",
35
+ "thetadatadx-win32-x64-msvc": "8.0.30"
36
36
  },
37
37
  "engines": {
38
38
  "node": ">= 20"