@solncebro/market-data-feeder-lib 0.1.0
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.
- package/CHANGELOG.md +10 -0
- package/README.md +60 -0
- package/dist/client/dataStaleness.d.ts +18 -0
- package/dist/client/dataStaleness.d.ts.map +1 -0
- package/dist/client/dataStaleness.js +23 -0
- package/dist/client/dataStaleness.js.map +1 -0
- package/dist/client/marketDataClient.d.ts +47 -0
- package/dist/client/marketDataClient.d.ts.map +1 -0
- package/dist/client/marketDataClient.js +262 -0
- package/dist/client/marketDataClient.js.map +1 -0
- package/dist/client/marketDataClient.types.d.ts +15 -0
- package/dist/client/marketDataClient.types.d.ts.map +1 -0
- package/dist/client/marketDataClient.types.js +2 -0
- package/dist/client/marketDataClient.types.js.map +1 -0
- package/dist/client/marketDataSource.types.d.ts +27 -0
- package/dist/client/marketDataSource.types.d.ts.map +1 -0
- package/dist/client/marketDataSource.types.js +2 -0
- package/dist/client/marketDataSource.types.js.map +1 -0
- package/dist/client/mirrorStore.d.ts +29 -0
- package/dist/client/mirrorStore.d.ts.map +1 -0
- package/dist/client/mirrorStore.js +119 -0
- package/dist/client/mirrorStore.js.map +1 -0
- package/dist/client/mirrorStore.types.d.ts +20 -0
- package/dist/client/mirrorStore.types.d.ts.map +1 -0
- package/dist/client/mirrorStore.types.js +2 -0
- package/dist/client/mirrorStore.types.js.map +1 -0
- package/dist/domain/constants.d.ts +12 -0
- package/dist/domain/constants.d.ts.map +1 -0
- package/dist/domain/constants.js +47 -0
- package/dist/domain/constants.js.map +1 -0
- package/dist/domain/events.types.d.ts +14 -0
- package/dist/domain/events.types.d.ts.map +1 -0
- package/dist/domain/events.types.js +2 -0
- package/dist/domain/events.types.js.map +1 -0
- package/dist/domain/feederSource.types.d.ts +44 -0
- package/dist/domain/feederSource.types.d.ts.map +1 -0
- package/dist/domain/feederSource.types.js +2 -0
- package/dist/domain/feederSource.types.js.map +1 -0
- package/dist/domain/managedSource.types.d.ts +13 -0
- package/dist/domain/managedSource.types.d.ts.map +1 -0
- package/dist/domain/managedSource.types.js +2 -0
- package/dist/domain/managedSource.types.js.map +1 -0
- package/dist/domain/marketData.types.d.ts +29 -0
- package/dist/domain/marketData.types.d.ts.map +1 -0
- package/dist/domain/marketData.types.js +2 -0
- package/dist/domain/marketData.types.js.map +1 -0
- package/dist/domain/snapshot.types.d.ts +10 -0
- package/dist/domain/snapshot.types.d.ts.map +1 -0
- package/dist/domain/snapshot.types.js +2 -0
- package/dist/domain/snapshot.types.js.map +1 -0
- package/dist/domain/subscription.types.d.ts +11 -0
- package/dist/domain/subscription.types.d.ts.map +1 -0
- package/dist/domain/subscription.types.js +2 -0
- package/dist/domain/subscription.types.js.map +1 -0
- package/dist/embedded/embeddedMarketDataSource.d.ts +29 -0
- package/dist/embedded/embeddedMarketDataSource.d.ts.map +1 -0
- package/dist/embedded/embeddedMarketDataSource.js +121 -0
- package/dist/embedded/embeddedMarketDataSource.js.map +1 -0
- package/dist/embedded/embeddedMarketDataSource.types.d.ts +17 -0
- package/dist/embedded/embeddedMarketDataSource.types.d.ts.map +1 -0
- package/dist/embedded/embeddedMarketDataSource.types.js +2 -0
- package/dist/embedded/embeddedMarketDataSource.types.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol/clientMessageValidation.d.ts +3 -0
- package/dist/protocol/clientMessageValidation.d.ts.map +1 -0
- package/dist/protocol/clientMessageValidation.js +41 -0
- package/dist/protocol/clientMessageValidation.js.map +1 -0
- package/dist/protocol/codec.d.ts +5 -0
- package/dist/protocol/codec.d.ts.map +1 -0
- package/dist/protocol/codec.js +40 -0
- package/dist/protocol/codec.js.map +1 -0
- package/dist/protocol/messages.types.d.ts +65 -0
- package/dist/protocol/messages.types.d.ts.map +1 -0
- package/dist/protocol/messages.types.js +2 -0
- package/dist/protocol/messages.types.js.map +1 -0
- package/dist/source/gapRepair.d.ts +15 -0
- package/dist/source/gapRepair.d.ts.map +1 -0
- package/dist/source/gapRepair.js +40 -0
- package/dist/source/gapRepair.js.map +1 -0
- package/dist/source/indicators.d.ts +5 -0
- package/dist/source/indicators.d.ts.map +1 -0
- package/dist/source/indicators.js +21 -0
- package/dist/source/indicators.js.map +1 -0
- package/dist/source/marketDataManager.d.ts +94 -0
- package/dist/source/marketDataManager.d.ts.map +1 -0
- package/dist/source/marketDataManager.js +930 -0
- package/dist/source/marketDataManager.js.map +1 -0
- package/dist/source/massStale.d.ts +10 -0
- package/dist/source/massStale.d.ts.map +1 -0
- package/dist/source/massStale.js +8 -0
- package/dist/source/massStale.js.map +1 -0
- package/dist/source/symbolListDelta.d.ts +4 -0
- package/dist/source/symbolListDelta.d.ts.map +1 -0
- package/dist/source/symbolListDelta.js +9 -0
- package/dist/source/symbolListDelta.js.map +1 -0
- package/dist/source/symbolListDelta.types.d.ts +10 -0
- package/dist/source/symbolListDelta.types.d.ts.map +1 -0
- package/dist/source/symbolListDelta.types.js +2 -0
- package/dist/source/symbolListDelta.types.js.map +1 -0
- package/dist/source/symbolRemovalGuard.d.ts +14 -0
- package/dist/source/symbolRemovalGuard.d.ts.map +1 -0
- package/dist/source/symbolRemovalGuard.js +19 -0
- package/dist/source/symbolRemovalGuard.js.map +1 -0
- package/dist/utils/intervalScheduler.d.ts +16 -0
- package/dist/utils/intervalScheduler.d.ts.map +1 -0
- package/dist/utils/intervalScheduler.js +42 -0
- package/dist/utils/intervalScheduler.js.map +1 -0
- package/dist/utils/timeout.d.ts +3 -0
- package/dist/utils/timeout.d.ts.map +1 -0
- package/dist/utils/timeout.js +18 -0
- package/dist/utils/timeout.js.map +1 -0
- package/package.json +37 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
- Initial release: library half of `market-data-feeder` extracted into its own package —
|
|
6
|
+
`domain/` (types, constants, `FeederSource`/`StreamLiveness`/`ManagedSource`/`SymbolLoadOutcome`
|
|
7
|
+
contracts), `protocol/` (codec, message types, client message validation), `source/` (kline
|
|
8
|
+
collection core), `client/` (`MarketDataClient`, mirror, staleness), `embedded/` (in-process
|
|
9
|
+
source), `utils/` (`startIntervalScheduler`, `withTimeout`).
|
|
10
|
+
- The feeder server keeps its own repository (`market-data-feeder`) and depends on this package.
|
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# @solncebro/market-data-feeder-lib
|
|
2
|
+
|
|
3
|
+
Market-data feeder library: the kline collection core (`MarketDataManager`), the embedded
|
|
4
|
+
in-process source (`createEmbeddedMarketDataSource`), the WebSocket client (`MarketDataClient`)
|
|
5
|
+
and the shared wire protocol (codec, message types, client message validation).
|
|
6
|
+
|
|
7
|
+
The standalone feeder **server** lives in the `market-data-feeder` repository and builds on this
|
|
8
|
+
package. Consumers embed this library into their own process, so the shared engines
|
|
9
|
+
(`@solncebro/trade-engine`, `@solncebro/websocket-engine`) are peer dependencies — the host
|
|
10
|
+
process owns the single installed copy.
|
|
11
|
+
|
|
12
|
+
Peer floors (`trade-engine >=3.16.0`, `websocket-engine >=0.3.0`) cover every real consumer tree.
|
|
13
|
+
The client path is verified down to those floors (volume-breaker / ma-chaser); the collection
|
|
14
|
+
core and the embedded source are developed and exercised against `trade-engine ^3.21` /
|
|
15
|
+
`websocket-engine 0.6` (feeder server, rubber) — on older engines the undergrown-backfill anchor
|
|
16
|
+
(`launchTimestamp`) may be absent and that self-heal quietly stands down (guarded, not a crash).
|
|
17
|
+
|
|
18
|
+
## Use from a strategy app
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { MarketDataClient } from '@solncebro/market-data-feeder-lib';
|
|
22
|
+
import type { MarketDataSource } from '@solncebro/market-data-feeder-lib';
|
|
23
|
+
|
|
24
|
+
const client = new MarketDataClient({
|
|
25
|
+
url: 'ws://127.0.0.1:7070',
|
|
26
|
+
interval: '30m',
|
|
27
|
+
scope: { kind: 'all' },
|
|
28
|
+
events: ['klineClosed', 'klineUpdated', 'klineUpdatedTick'],
|
|
29
|
+
wantMa: true,
|
|
30
|
+
logger,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
await client.waitUntilReady();
|
|
34
|
+
// client.getKlineList / getMaValues / getVolume24h ... + client.on('klineClosed', ...)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Create one `MarketDataClient` per interval the app needs (e.g. the chaser app: 30m + 5m + 4h; the breaker and rubber: 30m only).
|
|
38
|
+
|
|
39
|
+
## Embed in a single-consumer app
|
|
40
|
+
|
|
41
|
+
When an app is the **only** market-data consumer on its machine, a separate feeder process just doubles the RAM (server buffer + client mirror hold the same klines). `createEmbeddedMarketDataSource` runs the feeder core in-process instead: same `MarketDataSource` read API + events served straight from the single kline store — no WS hop, no mirror, no second Node process, no Telegram/health-monitor stack.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { createEmbeddedMarketDataSource } from '@solncebro/market-data-feeder-lib';
|
|
45
|
+
|
|
46
|
+
const source = await createEmbeddedMarketDataSource({
|
|
47
|
+
exchangeName: 'bybit',
|
|
48
|
+
exchangeApiKey,
|
|
49
|
+
exchangeSecret,
|
|
50
|
+
interval: '30m',
|
|
51
|
+
onNotify: (message) => notifier.sendMessage(message),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
await source.waitUntilReady(180_000);
|
|
55
|
+
// source.getKlineList / getVolume24h ... + source.on('klineClosed', ...)
|
|
56
|
+
// on teardown: await source.shutdown() (stops watchdogs, unsubscribes, closes its own connector)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The factory creates its **own** `ExchangeConnector` (kline watchdog tuned like the standalone feeder) so market-data traffic never shares a connector with the host's order path. Exchange-stream silence maps to `connectionLost`/`connectionRestored`, `isStale()` flips after 45s of silence, and the hourly listing/delisting sync runs inside the adapter. The standalone server topology is untouched — pick per machine: shared feeder process for many consumers, embedded core for one.
|
|
60
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { FeedEventName } from '../domain/subscription.types.js';
|
|
2
|
+
interface DataStalenessArgs {
|
|
3
|
+
isSnapshotComplete: boolean;
|
|
4
|
+
lastDataMessageMs: number;
|
|
5
|
+
nowMs: number;
|
|
6
|
+
thresholdMs: number;
|
|
7
|
+
}
|
|
8
|
+
interface ResolveDataStaleThresholdArgs {
|
|
9
|
+
intervalMs: number;
|
|
10
|
+
events: FeedEventName[];
|
|
11
|
+
baseThresholdMs: number;
|
|
12
|
+
}
|
|
13
|
+
declare function isDataStale(args: DataStalenessArgs): boolean;
|
|
14
|
+
declare function isDataFreshnessMessage(messageType: string): boolean;
|
|
15
|
+
declare function resolveDataStaleThresholdMs(args: ResolveDataStaleThresholdArgs): number;
|
|
16
|
+
export { isDataFreshnessMessage, isDataStale, resolveDataStaleThresholdMs };
|
|
17
|
+
export type { DataStalenessArgs, ResolveDataStaleThresholdArgs };
|
|
18
|
+
//# sourceMappingURL=dataStaleness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataStaleness.d.ts","sourceRoot":"","sources":["../../src/client/dataStaleness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAErE,UAAU,iBAAiB;IACzB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,UAAU,6BAA6B;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,iBAAS,WAAW,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAMrD;AAED,iBAAS,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE5D;AAOD,iBAAS,2BAA2B,CAAC,IAAI,EAAE,6BAA6B,GAAG,MAAM,CAQhF;AAED,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;AAC5E,YAAY,EAAE,iBAAiB,EAAE,6BAA6B,EAAE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
function isDataStale(args) {
|
|
2
|
+
if (!args.isSnapshotComplete) {
|
|
3
|
+
return true;
|
|
4
|
+
}
|
|
5
|
+
return args.nowMs - args.lastDataMessageMs > args.thresholdMs;
|
|
6
|
+
}
|
|
7
|
+
function isDataFreshnessMessage(messageType) {
|
|
8
|
+
return messageType !== 'heartbeat';
|
|
9
|
+
}
|
|
10
|
+
// The staleness window must match how often this subscription actually receives data. A subscription
|
|
11
|
+
// with a high-frequency event (klineUpdated/klineUpdatedTick) gets messages within seconds, so the base
|
|
12
|
+
// threshold is right. A closed-only subscription gets a message just once per interval — one full
|
|
13
|
+
// interval can legitimately pass between klines — so the threshold must exceed an interval (plus base
|
|
14
|
+
// grace); otherwise the channel reads STALE for most of every interval even while the feeder is healthy.
|
|
15
|
+
function resolveDataStaleThresholdMs(args) {
|
|
16
|
+
const hasHighFrequencyEvent = args.events.some((event) => event === 'klineUpdated' || event === 'klineUpdatedTick');
|
|
17
|
+
if (hasHighFrequencyEvent) {
|
|
18
|
+
return args.baseThresholdMs;
|
|
19
|
+
}
|
|
20
|
+
return args.intervalMs + args.baseThresholdMs;
|
|
21
|
+
}
|
|
22
|
+
export { isDataFreshnessMessage, isDataStale, resolveDataStaleThresholdMs };
|
|
23
|
+
//# sourceMappingURL=dataStaleness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dataStaleness.js","sourceRoot":"","sources":["../../src/client/dataStaleness.ts"],"names":[],"mappings":"AAeA,SAAS,WAAW,CAAC,IAAuB;IAC1C,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,WAAW,CAAC;AAChE,CAAC;AAED,SAAS,sBAAsB,CAAC,WAAmB;IACjD,OAAO,WAAW,KAAK,WAAW,CAAC;AACrC,CAAC;AAED,qGAAqG;AACrG,wGAAwG;AACxG,kGAAkG;AAClG,sGAAsG;AACtG,yGAAyG;AACzG,SAAS,2BAA2B,CAAC,IAAmC;IACtE,MAAM,qBAAqB,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,cAAc,IAAI,KAAK,KAAK,kBAAkB,CAAC,CAAC;IAEpH,IAAI,qBAAqB,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED,OAAO,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,eAAe,CAAC;AAChD,CAAC;AAED,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import type { Kline, KlineInterval, MaValues, StaleSymbolInfo } from '../domain/marketData.types.js';
|
|
3
|
+
import type { MarketDataSource } from './marketDataSource.types.js';
|
|
4
|
+
import type { MarketDataClientArgs } from './marketDataClient.types.js';
|
|
5
|
+
declare class MarketDataClient extends EventEmitter implements MarketDataSource {
|
|
6
|
+
private readonly url;
|
|
7
|
+
private readonly logger;
|
|
8
|
+
private readonly interval;
|
|
9
|
+
private readonly intervalMs;
|
|
10
|
+
private readonly dataStaleThresholdMs;
|
|
11
|
+
private readonly forceReconnectStaleMs;
|
|
12
|
+
private readonly subscribeMessage;
|
|
13
|
+
private readonly mirror;
|
|
14
|
+
private readonly lastUpdateMsBySymbol;
|
|
15
|
+
private socket;
|
|
16
|
+
private staleCheckTimer;
|
|
17
|
+
private staleSinceMs;
|
|
18
|
+
private snapshotSymbolSet;
|
|
19
|
+
private isSnapshotComplete;
|
|
20
|
+
private isConnectionLost;
|
|
21
|
+
private isClosed;
|
|
22
|
+
private lastDataMessageMs;
|
|
23
|
+
private resolveReady;
|
|
24
|
+
constructor(args: MarketDataClientArgs);
|
|
25
|
+
private createSocket;
|
|
26
|
+
private markConnectionLost;
|
|
27
|
+
private startStaleSelfHealCheck;
|
|
28
|
+
private evaluateStaleSelfHeal;
|
|
29
|
+
waitUntilReady(timeoutMs?: number): Promise<void>;
|
|
30
|
+
close(): void;
|
|
31
|
+
shutdown(): Promise<void>;
|
|
32
|
+
getInterval(): KlineInterval;
|
|
33
|
+
getIntervalMs(): number;
|
|
34
|
+
getMaValues(symbol: string): MaValues;
|
|
35
|
+
getKlineList(symbol: string): Kline[];
|
|
36
|
+
getCurrentKline(symbol: string): Kline | undefined;
|
|
37
|
+
getSymbolList(): string[];
|
|
38
|
+
getLastKlineOpenTimestamp(symbol: string): number | undefined;
|
|
39
|
+
getLastUpdateTimestamp(symbol: string): number | undefined;
|
|
40
|
+
getVolume24h(symbol: string): number;
|
|
41
|
+
isStale(): boolean;
|
|
42
|
+
getStaleSymbolList(): StaleSymbolInfo[];
|
|
43
|
+
private handleMessage;
|
|
44
|
+
private markReady;
|
|
45
|
+
}
|
|
46
|
+
export { MarketDataClient };
|
|
47
|
+
//# sourceMappingURL=marketDataClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketDataClient.d.ts","sourceRoot":"","sources":["../../src/client/marketDataClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAMrG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAgBxE,cAAM,gBAAiB,SAAQ,YAAa,YAAW,gBAAgB;IACrE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAS;IAC/C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAkC;IACvE,OAAO,CAAC,MAAM,CAA0C;IACxD,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,iBAAiB,CAA0B;IACnD,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,iBAAiB,CAAa;IACtC,OAAO,CAAC,YAAY,CAA6B;gBAErC,IAAI,EAAE,oBAAoB;IActC,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,kBAAkB;IAS1B,OAAO,CAAC,uBAAuB;IAO/B,OAAO,CAAC,qBAAqB;IAkCvB,cAAc,CAAC,SAAS,GAAE,MAAqC,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBrF,KAAK,IAAI,IAAI;IAWP,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B,WAAW,IAAI,aAAa;IAI5B,aAAa,IAAI,MAAM;IAIvB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAIrC,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE;IAIrC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIlD,aAAa,IAAI,MAAM,EAAE;IAIzB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI7D,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI1D,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIpC,OAAO,IAAI,OAAO;IASlB,kBAAkB,IAAI,eAAe,EAAE;IA0BvC,OAAO,CAAC,aAAa;IA6ErB,OAAO,CAAC,SAAS;CAclB;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { ReliableWebSocket } from '@solncebro/websocket-engine';
|
|
3
|
+
import { KLINE_BUFFER_SIZE, STALENESS_THRESHOLD_MULTIPLIER, resolveIntervalMs } from '../domain/constants.js';
|
|
4
|
+
import { decodeMessage, encodeMessage } from '../protocol/codec.js';
|
|
5
|
+
import { MirrorStore } from './mirrorStore.js';
|
|
6
|
+
import { isDataFreshnessMessage, isDataStale, resolveDataStaleThresholdMs } from './dataStaleness.js';
|
|
7
|
+
const DEFAULT_SUBSCRIBE_TIMEOUT_MS = 30_000;
|
|
8
|
+
const CLIENT_STALE_THRESHOLD_MS = 45_000;
|
|
9
|
+
const CLIENT_STALE_CHECK_INTERVAL_MS = 15_000;
|
|
10
|
+
// Self-healing: data staleness persisting past this multiple of the stale threshold means the
|
|
11
|
+
// subscription is silently gone (the socket may still be OPEN receiving heartbeats) — recreate the
|
|
12
|
+
// transport and re-subscribe. Recreation also resurrects a transport that exhausted its retry
|
|
13
|
+
// budget and parked itself in a terminal FAILED state during a long feeder outage.
|
|
14
|
+
const CLIENT_FORCE_RECONNECT_STALE_MULTIPLIER = 2;
|
|
15
|
+
// Before the FIRST final snapshot the mirror is legitimately stale for as long as the feeder's
|
|
16
|
+
// bulk backfill takes (a Binance cold start pushes ~1600 requests through a 16 req/s pacer —
|
|
17
|
+
// minutes, not seconds), so the pre-ready self-heal uses this much larger floor. A genuinely
|
|
18
|
+
// failed subscribe is covered separately: the server closes the socket with code 4001.
|
|
19
|
+
const CLIENT_PRE_READY_FORCE_RECONNECT_MS = 300_000;
|
|
20
|
+
class MarketDataClient extends EventEmitter {
|
|
21
|
+
url;
|
|
22
|
+
logger;
|
|
23
|
+
interval;
|
|
24
|
+
intervalMs;
|
|
25
|
+
dataStaleThresholdMs;
|
|
26
|
+
forceReconnectStaleMs;
|
|
27
|
+
subscribeMessage;
|
|
28
|
+
mirror;
|
|
29
|
+
lastUpdateMsBySymbol = new Map();
|
|
30
|
+
socket;
|
|
31
|
+
staleCheckTimer = null;
|
|
32
|
+
staleSinceMs = null;
|
|
33
|
+
snapshotSymbolSet = new Set();
|
|
34
|
+
isSnapshotComplete = false;
|
|
35
|
+
isConnectionLost = false;
|
|
36
|
+
isClosed = false;
|
|
37
|
+
lastDataMessageMs = 0;
|
|
38
|
+
resolveReady = null;
|
|
39
|
+
constructor(args) {
|
|
40
|
+
super();
|
|
41
|
+
this.url = args.url;
|
|
42
|
+
this.logger = args.logger;
|
|
43
|
+
this.interval = args.interval;
|
|
44
|
+
this.intervalMs = resolveIntervalMs(args.interval);
|
|
45
|
+
this.dataStaleThresholdMs = resolveDataStaleThresholdMs({ intervalMs: this.intervalMs, events: args.events, baseThresholdMs: args.staleThresholdMs ?? CLIENT_STALE_THRESHOLD_MS });
|
|
46
|
+
this.forceReconnectStaleMs = this.dataStaleThresholdMs * CLIENT_FORCE_RECONNECT_STALE_MULTIPLIER;
|
|
47
|
+
this.subscribeMessage = { type: 'subscribe', interval: args.interval, scope: args.scope, events: args.events, wantMa: args.wantMa };
|
|
48
|
+
this.mirror = new MirrorStore(KLINE_BUFFER_SIZE);
|
|
49
|
+
this.socket = this.createSocket();
|
|
50
|
+
this.startStaleSelfHealCheck(args.staleCheckIntervalMs ?? CLIENT_STALE_CHECK_INTERVAL_MS);
|
|
51
|
+
}
|
|
52
|
+
createSocket() {
|
|
53
|
+
return new ReliableWebSocket({
|
|
54
|
+
url: this.url,
|
|
55
|
+
label: `market-data-${this.interval}`,
|
|
56
|
+
logger: this.logger,
|
|
57
|
+
parseMessage: (rawData) => decodeMessage(rawData.toString()),
|
|
58
|
+
onMessage: (message) => {
|
|
59
|
+
this.handleMessage(message);
|
|
60
|
+
},
|
|
61
|
+
onOpen: async (context) => {
|
|
62
|
+
this.isSnapshotComplete = false;
|
|
63
|
+
this.snapshotSymbolSet = new Set();
|
|
64
|
+
this.staleSinceMs = null;
|
|
65
|
+
context.send(encodeMessage(this.subscribeMessage));
|
|
66
|
+
},
|
|
67
|
+
onNotify: (reason) => {
|
|
68
|
+
this.markConnectionLost(reason);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
markConnectionLost(reason) {
|
|
73
|
+
if (this.isConnectionLost) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.isConnectionLost = true;
|
|
77
|
+
this.emit('connectionLost', reason);
|
|
78
|
+
}
|
|
79
|
+
startStaleSelfHealCheck(checkIntervalMs) {
|
|
80
|
+
this.staleCheckTimer = setInterval(() => {
|
|
81
|
+
this.evaluateStaleSelfHeal();
|
|
82
|
+
}, checkIntervalMs);
|
|
83
|
+
this.staleCheckTimer.unref();
|
|
84
|
+
}
|
|
85
|
+
evaluateStaleSelfHeal() {
|
|
86
|
+
if (this.isClosed) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!this.isStale()) {
|
|
90
|
+
this.staleSinceMs = null;
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const nowMs = Date.now();
|
|
94
|
+
if (this.staleSinceMs === null) {
|
|
95
|
+
this.staleSinceMs = nowMs;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const forceReconnectMs = this.isSnapshotComplete
|
|
99
|
+
? this.forceReconnectStaleMs
|
|
100
|
+
: Math.max(this.forceReconnectStaleMs, CLIENT_PRE_READY_FORCE_RECONNECT_MS);
|
|
101
|
+
if (nowMs - this.staleSinceMs < forceReconnectMs) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
this.staleSinceMs = null;
|
|
105
|
+
this.logger.warn(`[market-data-${this.interval}] data stale for over ${Math.round(this.forceReconnectStaleMs / 1000)}s — forcing a reconnect to re-subscribe`);
|
|
106
|
+
this.markConnectionLost('stale data — forcing reconnect');
|
|
107
|
+
this.socket.close();
|
|
108
|
+
this.socket = this.createSocket();
|
|
109
|
+
}
|
|
110
|
+
async waitUntilReady(timeoutMs = DEFAULT_SUBSCRIBE_TIMEOUT_MS) {
|
|
111
|
+
if (this.isSnapshotComplete) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
await new Promise((resolve, reject) => {
|
|
115
|
+
const timeoutHandle = setTimeout(() => {
|
|
116
|
+
this.resolveReady = null;
|
|
117
|
+
reject(new Error(`Snapshot not received within ${timeoutMs}ms for ${this.interval}`));
|
|
118
|
+
}, timeoutMs);
|
|
119
|
+
this.resolveReady = () => {
|
|
120
|
+
clearTimeout(timeoutHandle);
|
|
121
|
+
resolve();
|
|
122
|
+
};
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
close() {
|
|
126
|
+
this.isClosed = true;
|
|
127
|
+
if (this.staleCheckTimer !== null) {
|
|
128
|
+
clearInterval(this.staleCheckTimer);
|
|
129
|
+
this.staleCheckTimer = null;
|
|
130
|
+
}
|
|
131
|
+
this.socket.close();
|
|
132
|
+
}
|
|
133
|
+
async shutdown() {
|
|
134
|
+
this.close();
|
|
135
|
+
}
|
|
136
|
+
getInterval() {
|
|
137
|
+
return this.interval;
|
|
138
|
+
}
|
|
139
|
+
getIntervalMs() {
|
|
140
|
+
return this.intervalMs;
|
|
141
|
+
}
|
|
142
|
+
getMaValues(symbol) {
|
|
143
|
+
return this.mirror.getMaValues(symbol);
|
|
144
|
+
}
|
|
145
|
+
getKlineList(symbol) {
|
|
146
|
+
return this.mirror.getKlineList(symbol);
|
|
147
|
+
}
|
|
148
|
+
getCurrentKline(symbol) {
|
|
149
|
+
return this.mirror.getCurrentKline(symbol);
|
|
150
|
+
}
|
|
151
|
+
getSymbolList() {
|
|
152
|
+
return this.mirror.getSymbolList();
|
|
153
|
+
}
|
|
154
|
+
getLastKlineOpenTimestamp(symbol) {
|
|
155
|
+
return this.mirror.getLastKlineOpenTimestamp(symbol);
|
|
156
|
+
}
|
|
157
|
+
getLastUpdateTimestamp(symbol) {
|
|
158
|
+
return this.lastUpdateMsBySymbol.get(symbol);
|
|
159
|
+
}
|
|
160
|
+
getVolume24h(symbol) {
|
|
161
|
+
return this.mirror.getVolume24h(symbol);
|
|
162
|
+
}
|
|
163
|
+
isStale() {
|
|
164
|
+
return isDataStale({
|
|
165
|
+
isSnapshotComplete: this.isSnapshotComplete,
|
|
166
|
+
lastDataMessageMs: this.lastDataMessageMs,
|
|
167
|
+
nowMs: Date.now(),
|
|
168
|
+
thresholdMs: this.dataStaleThresholdMs,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
getStaleSymbolList() {
|
|
172
|
+
const thresholdMs = STALENESS_THRESHOLD_MULTIPLIER * this.intervalMs;
|
|
173
|
+
const nowMs = Date.now();
|
|
174
|
+
const staleSymbolList = [];
|
|
175
|
+
for (const symbol of this.mirror.getSymbolList()) {
|
|
176
|
+
const klineList = this.mirror.getKlineList(symbol);
|
|
177
|
+
if (klineList.length === 0) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const lastKline = klineList[klineList.length - 1];
|
|
181
|
+
const referenceTimestamp = lastKline.closeTimestamp > 0 ? lastKline.closeTimestamp : lastKline.openTimestamp + this.intervalMs;
|
|
182
|
+
const ageMs = nowMs - referenceTimestamp;
|
|
183
|
+
if (ageMs > thresholdMs) {
|
|
184
|
+
staleSymbolList.push({ symbol, ageMs });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
staleSymbolList.sort((first, second) => second.ageMs - first.ageMs);
|
|
188
|
+
return staleSymbolList;
|
|
189
|
+
}
|
|
190
|
+
handleMessage(message) {
|
|
191
|
+
if (message === null) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (isDataFreshnessMessage(message.type)) {
|
|
195
|
+
this.lastDataMessageMs = Date.now();
|
|
196
|
+
}
|
|
197
|
+
if (message.type === 'snapshot') {
|
|
198
|
+
this.mirror.applySnapshot({ entryList: message.entryList });
|
|
199
|
+
for (const entry of message.entryList) {
|
|
200
|
+
this.snapshotSymbolSet.add(entry.symbol);
|
|
201
|
+
}
|
|
202
|
+
if (message.isFinal) {
|
|
203
|
+
this.mirror.retainSymbols(this.snapshotSymbolSet);
|
|
204
|
+
for (const symbol of this.lastUpdateMsBySymbol.keys()) {
|
|
205
|
+
if (!this.snapshotSymbolSet.has(symbol)) {
|
|
206
|
+
this.lastUpdateMsBySymbol.delete(symbol);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.snapshotSymbolSet = new Set();
|
|
210
|
+
this.markReady();
|
|
211
|
+
}
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (message.type === 'klineClosed') {
|
|
215
|
+
this.mirror.applyKlineClosed({ symbol: message.symbol, kline: message.kline, maValues: message.maValues });
|
|
216
|
+
this.lastUpdateMsBySymbol.set(message.symbol, Date.now());
|
|
217
|
+
this.emit('klineClosed', message.symbol, message.kline, message.maValues);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (message.type === 'klineUpdated') {
|
|
221
|
+
this.mirror.applyKlineUpdated({ symbol: message.symbol, kline: message.kline, maValues: message.maValues });
|
|
222
|
+
this.lastUpdateMsBySymbol.set(message.symbol, Date.now());
|
|
223
|
+
this.emit('klineUpdated', message.symbol, message.kline, message.maValues);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (message.type === 'klineUpdatedTick') {
|
|
227
|
+
this.mirror.applyKlineTick({ symbol: message.symbol, kline: message.kline });
|
|
228
|
+
this.lastUpdateMsBySymbol.set(message.symbol, Date.now());
|
|
229
|
+
this.emit('klineUpdatedTick', message.symbol, message.kline);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (message.type === 'symbolAdded') {
|
|
233
|
+
this.mirror.applySymbolAdded(message.entry);
|
|
234
|
+
this.lastUpdateMsBySymbol.set(message.entry.symbol, Date.now());
|
|
235
|
+
this.emit('symbolAdded', message.entry.symbol);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (message.type === 'symbolRemoved') {
|
|
239
|
+
this.mirror.applySymbolRemoved(message.symbol);
|
|
240
|
+
this.lastUpdateMsBySymbol.delete(message.symbol);
|
|
241
|
+
this.emit('symbolRemoved', message.symbol);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (message.type === 'volume24h') {
|
|
245
|
+
this.mirror.applyVolume24h({ symbol: message.symbol, volume24hUsdt: message.volume24hUsdt });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
markReady() {
|
|
249
|
+
this.isSnapshotComplete = true;
|
|
250
|
+
if (this.isConnectionLost) {
|
|
251
|
+
this.isConnectionLost = false;
|
|
252
|
+
this.emit('connectionRestored');
|
|
253
|
+
}
|
|
254
|
+
if (this.resolveReady !== null) {
|
|
255
|
+
const resolve = this.resolveReady;
|
|
256
|
+
this.resolveReady = null;
|
|
257
|
+
resolve();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
export { MarketDataClient };
|
|
262
|
+
//# sourceMappingURL=marketDataClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketDataClient.js","sourceRoot":"","sources":["../../src/client/marketDataClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WebSocketLogger } from '@solncebro/websocket-engine';
|
|
2
|
+
import type { KlineInterval } from '../domain/marketData.types.js';
|
|
3
|
+
import type { FeedEventName, SubscriptionScope } from '../domain/subscription.types.js';
|
|
4
|
+
interface MarketDataClientArgs {
|
|
5
|
+
url: string;
|
|
6
|
+
interval: KlineInterval;
|
|
7
|
+
scope: SubscriptionScope;
|
|
8
|
+
events: FeedEventName[];
|
|
9
|
+
wantMa: boolean;
|
|
10
|
+
logger: WebSocketLogger;
|
|
11
|
+
staleThresholdMs?: number;
|
|
12
|
+
staleCheckIntervalMs?: number;
|
|
13
|
+
}
|
|
14
|
+
export type { MarketDataClientArgs };
|
|
15
|
+
//# sourceMappingURL=marketDataClient.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketDataClient.types.d.ts","sourceRoot":"","sources":["../../src/client/marketDataClient.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAExF,UAAU,oBAAoB;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,iBAAiB,CAAC;IACzB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,eAAe,CAAC;IAExB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,YAAY,EAAE,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketDataClient.types.js","sourceRoot":"","sources":["../../src/client/marketDataClient.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Kline, KlineInterval, MaValues, StaleSymbolInfo } from '../domain/marketData.types.js';
|
|
2
|
+
import type { ConnectionLostListener, ConnectionRestoredListener, KlineTickListener, KlineWithMaListener, SymbolNameListener } from '../domain/events.types.js';
|
|
3
|
+
interface MarketDataSource {
|
|
4
|
+
getInterval: () => KlineInterval;
|
|
5
|
+
getIntervalMs: () => number;
|
|
6
|
+
getMaValues: (symbol: string) => MaValues;
|
|
7
|
+
getKlineList: (symbol: string) => Kline[];
|
|
8
|
+
getCurrentKline: (symbol: string) => Kline | undefined;
|
|
9
|
+
getSymbolList: () => string[];
|
|
10
|
+
getLastKlineOpenTimestamp: (symbol: string) => number | undefined;
|
|
11
|
+
getLastUpdateTimestamp: (symbol: string) => number | undefined;
|
|
12
|
+
getVolume24h: (symbol: string) => number;
|
|
13
|
+
isStale: () => boolean;
|
|
14
|
+
getStaleSymbolList: () => StaleSymbolInfo[];
|
|
15
|
+
on(eventName: 'klineClosed' | 'klineUpdated', listener: KlineWithMaListener): this;
|
|
16
|
+
on(eventName: 'klineUpdatedTick', listener: KlineTickListener): this;
|
|
17
|
+
on(eventName: 'symbolAdded' | 'symbolRemoved', listener: SymbolNameListener): this;
|
|
18
|
+
on(eventName: 'connectionLost', listener: ConnectionLostListener): this;
|
|
19
|
+
on(eventName: 'connectionRestored', listener: ConnectionRestoredListener): this;
|
|
20
|
+
off(eventName: 'klineClosed' | 'klineUpdated', listener: KlineWithMaListener): this;
|
|
21
|
+
off(eventName: 'klineUpdatedTick', listener: KlineTickListener): this;
|
|
22
|
+
off(eventName: 'symbolAdded' | 'symbolRemoved', listener: SymbolNameListener): this;
|
|
23
|
+
off(eventName: 'connectionLost', listener: ConnectionLostListener): this;
|
|
24
|
+
off(eventName: 'connectionRestored', listener: ConnectionRestoredListener): this;
|
|
25
|
+
}
|
|
26
|
+
export type { MarketDataSource };
|
|
27
|
+
//# sourceMappingURL=marketDataSource.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketDataSource.types.d.ts","sourceRoot":"","sources":["../../src/client/marketDataSource.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AACrG,OAAO,KAAK,EAAE,sBAAsB,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEhK,UAAU,gBAAgB;IACxB,WAAW,EAAE,MAAM,aAAa,CAAC;IACjC,aAAa,EAAE,MAAM,MAAM,CAAC;IAC5B,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,QAAQ,CAAC;IAC1C,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,EAAE,CAAC;IAC1C,eAAe,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,GAAG,SAAS,CAAC;IACvD,aAAa,EAAE,MAAM,MAAM,EAAE,CAAC;IAC9B,yBAAyB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAClE,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IAC/D,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,CAAC;IACzC,OAAO,EAAE,MAAM,OAAO,CAAC;IACvB,kBAAkB,EAAE,MAAM,eAAe,EAAE,CAAC;IAC5C,EAAE,CAAC,SAAS,EAAE,aAAa,GAAG,cAAc,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACnF,EAAE,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACrE,EAAE,CAAC,SAAS,EAAE,aAAa,GAAG,eAAe,EAAE,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACnF,EAAE,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACxE,EAAE,CAAC,SAAS,EAAE,oBAAoB,EAAE,QAAQ,EAAE,0BAA0B,GAAG,IAAI,CAAC;IAChF,GAAG,CAAC,SAAS,EAAE,aAAa,GAAG,cAAc,EAAE,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACpF,GAAG,CAAC,SAAS,EAAE,kBAAkB,EAAE,QAAQ,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtE,GAAG,CAAC,SAAS,EAAE,aAAa,GAAG,eAAe,EAAE,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpF,GAAG,CAAC,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACzE,GAAG,CAAC,SAAS,EAAE,oBAAoB,EAAE,QAAQ,EAAE,0BAA0B,GAAG,IAAI,CAAC;CAClF;AAED,YAAY,EAAE,gBAAgB,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marketDataSource.types.js","sourceRoot":"","sources":["../../src/client/marketDataSource.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Kline, MaValues } from '../domain/marketData.types.js';
|
|
2
|
+
import type { MarketDataSnapshotEntry } from '../domain/snapshot.types.js';
|
|
3
|
+
import type { ApplyKlineArgs, ApplyKlineWithMaArgs, ApplySnapshotArgs, ApplyVolume24hArgs } from './mirrorStore.types.js';
|
|
4
|
+
declare class MirrorStore {
|
|
5
|
+
private readonly maxBufferSize;
|
|
6
|
+
private readonly klineListBySymbol;
|
|
7
|
+
private readonly maValuesBySymbol;
|
|
8
|
+
private readonly currentKlineBySymbol;
|
|
9
|
+
private readonly volume24hBySymbol;
|
|
10
|
+
constructor(maxBufferSize: number);
|
|
11
|
+
applySnapshot(args: ApplySnapshotArgs): void;
|
|
12
|
+
applySymbolAdded(entry: MarketDataSnapshotEntry): void;
|
|
13
|
+
applySymbolRemoved(symbol: string): void;
|
|
14
|
+
retainSymbols(symbolSet: Set<string>): void;
|
|
15
|
+
applyKlineClosed(args: ApplyKlineWithMaArgs): void;
|
|
16
|
+
applyKlineUpdated(args: ApplyKlineWithMaArgs): void;
|
|
17
|
+
applyKlineTick(args: ApplyKlineArgs): void;
|
|
18
|
+
applyVolume24h(args: ApplyVolume24hArgs): void;
|
|
19
|
+
getKlineList(symbol: string): Kline[];
|
|
20
|
+
getMaValues(symbol: string): MaValues;
|
|
21
|
+
getCurrentKline(symbol: string): Kline | undefined;
|
|
22
|
+
getSymbolList(): string[];
|
|
23
|
+
getLastKlineOpenTimestamp(symbol: string): number | undefined;
|
|
24
|
+
getVolume24h(symbol: string): number;
|
|
25
|
+
private seedSymbol;
|
|
26
|
+
private applyKlineToBuffer;
|
|
27
|
+
}
|
|
28
|
+
export { MirrorStore };
|
|
29
|
+
//# sourceMappingURL=mirrorStore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mirrorStore.d.ts","sourceRoot":"","sources":["../../src/client/mirrorStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AAC3E,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,wBAAwB,CAAC;AAIhC,cAAM,WAAW;IACf,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmC;IACrE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAoC;IACrE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAiC;IACtE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAkC;gBAExD,aAAa,EAAE,MAAM;IAIjC,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI;IAM5C,gBAAgB,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI;IAItD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAOxC,aAAa,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAQ3C,gBAAgB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;IAWlD,iBAAiB,CAAC,IAAI,EAAE,oBAAoB,GAAG,IAAI;IAWnD,cAAc,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAU1C,cAAc,CAAC,IAAI,EAAE,kBAAkB,GAAG,IAAI;IAI9C,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE;IAIrC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAIrC,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIlD,aAAa,IAAI,MAAM,EAAE;IAIzB,yBAAyB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAU7D,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAIpC,OAAO,CAAC,UAAU;IAelB,OAAO,CAAC,kBAAkB;CAkC3B;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
|