@solncebro/market-data-feeder-lib
v0.1.0
Published
Market-data feeder library: kline collection core, embedded in-process source, WebSocket client and the shared wire protocol. The standalone feeder server lives in market-data-feeder and builds on this package
Readme
@solncebro/market-data-feeder-lib
Market-data feeder library: the kline collection core (MarketDataManager), the embedded
in-process source (createEmbeddedMarketDataSource), the WebSocket client (MarketDataClient)
and the shared wire protocol (codec, message types, client message validation).
The standalone feeder server lives in the market-data-feeder repository and builds on this
package. Consumers embed this library into their own process, so the shared engines
(@solncebro/trade-engine, @solncebro/websocket-engine) are peer dependencies — the host
process owns the single installed copy.
Peer floors (trade-engine >=3.16.0, websocket-engine >=0.3.0) cover every real consumer tree.
The client path is verified down to those floors (volume-breaker / ma-chaser); the collection
core and the embedded source are developed and exercised against trade-engine ^3.21 /
websocket-engine 0.6 (feeder server, rubber) — on older engines the undergrown-backfill anchor
(launchTimestamp) may be absent and that self-heal quietly stands down (guarded, not a crash).
Use from a strategy app
import { MarketDataClient } from '@solncebro/market-data-feeder-lib';
import type { MarketDataSource } from '@solncebro/market-data-feeder-lib';
const client = new MarketDataClient({
url: 'ws://127.0.0.1:7070',
interval: '30m',
scope: { kind: 'all' },
events: ['klineClosed', 'klineUpdated', 'klineUpdatedTick'],
wantMa: true,
logger,
});
await client.waitUntilReady();
// client.getKlineList / getMaValues / getVolume24h ... + client.on('klineClosed', ...)Create one MarketDataClient per interval the app needs (e.g. the chaser app: 30m + 5m + 4h; the breaker and rubber: 30m only).
Embed in a single-consumer app
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.
import { createEmbeddedMarketDataSource } from '@solncebro/market-data-feeder-lib';
const source = await createEmbeddedMarketDataSource({
exchangeName: 'bybit',
exchangeApiKey,
exchangeSecret,
interval: '30m',
onNotify: (message) => notifier.sendMessage(message),
});
await source.waitUntilReady(180_000);
// source.getKlineList / getVolume24h ... + source.on('klineClosed', ...)
// on teardown: await source.shutdown() (stops watchdogs, unsubscribes, closes its own connector)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.
