tardis-dev
Version:
Convenient access to tick-level historical and real-time cryptocurrency market data via Node.js
113 lines • 4.05 kB
JavaScript
import { MultiConnectionRealTimeFeedBase, RealTimeFeedBase } from "./realtimefeed.js";
const BULLISH_SUBSCRIPTION_TARGETS = {
V1TALevel2: {
topic: 'l2Orderbook',
path: '/trading-api/v1/market-data/orderbook',
symbolParam: 'symbol'
},
V1TALevel1: {
topic: 'l1Orderbook',
path: '/trading-api/v1/market-data/orderbook',
symbolParam: 'symbol'
},
V1TAAnonymousTradeUpdate: {
topic: 'anonymousTrades',
path: '/trading-api/v1/market-data/trades',
symbolParam: 'symbol'
},
V1TATickerResponse: {
topic: 'tick',
path: '/trading-api/v1/market-data/tick',
symbolParam: 'symbol'
},
V1TAIndexPrice: {
topic: 'indexPrice',
path: '/trading-api/v1/index-data',
symbolParam: 'assetSymbol'
}
};
function getBullishSubscriptionTarget(channel) {
const target = BULLISH_SUBSCRIPTION_TARGETS[channel];
if (target === undefined) {
throw new Error(`BullishRealTimeFeed unsupported channel ${channel}`);
}
return target;
}
export class BullishRealTimeFeed extends MultiConnectionRealTimeFeedBase {
*_getRealTimeFeeds(exchange, filters, timeoutIntervalMS, onError) {
for (const [path, pathFilters] of this.groupByPath(filters)) {
yield new BullishSingleConnectionRealTimeFeed(exchange, path, pathFilters, timeoutIntervalMS, onError);
}
}
groupByPath(filters) {
const filtersByPath = new Map();
for (const filter of filters) {
const target = getBullishSubscriptionTarget(filter.channel);
const pathFilters = filtersByPath.get(target.path) ?? [];
pathFilters.push(filter);
filtersByPath.set(target.path, pathFilters);
}
return filtersByPath;
}
}
export class BullishSingleConnectionRealTimeFeed extends RealTimeFeedBase {
path;
wssURL = 'wss://api.exchange.bullish.com';
nextMessageId = 1;
constructor(exchange, path, filters, timeoutIntervalMS, onError) {
super(exchange, filters, timeoutIntervalMS, onError);
this.path = path;
}
async getWebSocketUrl() {
const baseURL = await super.getWebSocketUrl();
return `${baseURL.replace(/\/$/, '')}${this.path}`;
}
mapToSubscribeMessages(filters) {
return filters.flatMap((filter) => {
const target = getBullishSubscriptionTarget(filter.channel);
if (target.symbolParam == null) {
return [
{
jsonrpc: '2.0',
type: 'command',
method: 'subscribe',
id: (this.nextMessageId++).toString(),
params: {
topic: target.topic
}
}
];
}
if (!filter.symbols || filter.symbols.length === 0) {
throw new Error('BullishRealTimeFeed requires explicitly specified symbols when subscribing to live feed');
}
return filter.symbols.map((symbol) => {
return {
jsonrpc: '2.0',
type: 'command',
method: 'subscribe',
id: (this.nextMessageId++).toString(),
params: {
topic: target.topic,
[target.symbolParam]: symbol
}
};
});
});
}
messageIsError(message) {
return message.error !== undefined && message.error !== null;
}
sendCustomPing = () => {
this.send({
jsonrpc: '2.0',
type: 'command',
method: 'keepalivePing',
id: (this.nextMessageId++).toString()
});
};
messageIsHeartbeat(message) {
return message.dataType === 'V1TAHeartbeat' || message.result?.message === 'Keep alive pong';
}
}
//# sourceMappingURL=bullish.js.map