tardis-dev
Version:
Convenient access to tick-level historical and real-time cryptocurrency market data via Node.js
218 lines • 8.66 kB
JavaScript
import { asNonZeroNumberOrUndefined, asNumberOrUndefined } from "../handy.js";
import { PendingTickerInfoHelper } from "./mapper.js";
export class BullishTradesMapper {
canHandle(message) {
return message.dataType === 'V1TAAnonymousTradeUpdate' && message.type === 'update';
}
getFilters(symbols) {
return [
{
channel: 'V1TAAnonymousTradeUpdate',
symbols
}
];
}
*map(message, localTimestamp) {
for (const trade of message.data.trades) {
yield {
type: 'trade',
symbol: trade.symbol,
exchange: 'bullish',
id: trade.tradeId,
price: Number(trade.price),
amount: Number(trade.quantity),
side: this.mapBullishTradeSide(trade.side, trade.isTaker),
timestamp: new Date(trade.createdAtDatetime),
localTimestamp
};
}
}
mapBullishTradeSide(side, isTaker) {
if (isTaker) {
// Bullish side already represents the taker/aggressor side.
return side === 'BUY' ? 'buy' : 'sell';
}
// Bullish side represents the maker/resting order, so the taker was on the opposite side.
return side === 'BUY' ? 'sell' : 'buy';
}
}
export class BullishBookChangeMapper {
canHandle(message) {
return message.dataType === 'V1TALevel2';
}
getFilters(symbols) {
return [
{
channel: 'V1TALevel2',
symbols
}
];
}
*map(message, localTimestamp) {
yield {
type: 'book_change',
symbol: message.data.symbol,
exchange: 'bullish',
isSnapshot: message.type === 'snapshot',
bids: this.mapLevels(message.data.bids),
asks: this.mapLevels(message.data.asks),
timestamp: new Date(message.data.datetime),
localTimestamp
};
}
mapLevels(levels) {
const result = new Array(levels.length / 2);
for (let index = 0, resultIndex = 0; index < levels.length; index += 2, resultIndex++) {
result[resultIndex] = {
price: Number(levels[index]),
amount: Number(levels[index + 1])
};
}
return result;
}
}
export class BullishBookTickerMapper {
canHandle(message) {
return message.dataType === 'V1TALevel1' && (message.type === 'snapshot' || message.type === 'update');
}
getFilters(symbols) {
return [
{
channel: 'V1TALevel1',
symbols
}
];
}
*map(message, localTimestamp) {
yield {
type: 'book_ticker',
symbol: message.data.symbol,
exchange: 'bullish',
bidPrice: asNonZeroNumberOrUndefined(message.data.bid[0]),
bidAmount: asNonZeroNumberOrUndefined(message.data.bid[1]),
askPrice: asNonZeroNumberOrUndefined(message.data.ask[0]),
askAmount: asNonZeroNumberOrUndefined(message.data.ask[1]),
timestamp: new Date(message.data.datetime),
localTimestamp
};
}
}
export class BullishDerivativeTickerMapper {
pendingTickerInfoHelper = new PendingTickerInfoHelper();
indexPrices = new Map();
canHandle(message) {
if (message.dataType === 'V1TAIndexPrice' && (message.type === 'snapshot' || message.type === 'update')) {
return true;
}
if (message.dataType === 'V1TATickerResponse' && (message.type === 'snapshot' || message.type === 'update')) {
const tickerMessage = message;
return tickerMessage.data.symbol.endsWith('-PERP') || /-\d{8}$/.test(tickerMessage.data.symbol);
}
return false;
}
getFilters(symbols) {
return [
{
channel: 'V1TATickerResponse',
symbols
},
{
channel: 'V1TAIndexPrice',
symbols: symbols === undefined ? undefined : [...new Set(symbols.map((symbol) => symbol.split('-')[0]))]
}
];
}
*map(message, localTimestamp) {
if (message.dataType === 'V1TAIndexPrice') {
const price = asNonZeroNumberOrUndefined(message.data.price);
if (price !== undefined) {
this.indexPrices.set(message.data.assetSymbol, {
price,
timestamp: new Date(message.data.updatedAtDatetime)
});
}
return;
}
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(message.data.symbol, 'bullish');
const indexAsset = message.data.symbol.split('-')[0];
const indexPrice = this.indexPrices.get(indexAsset);
pendingTickerInfo.updateLastPrice(asNonZeroNumberOrUndefined(message.data.last));
pendingTickerInfo.updateMarkPrice(asNonZeroNumberOrUndefined(message.data.markPrice));
pendingTickerInfo.updateFundingRate(asNumberOrUndefined(message.data.fundingRate));
pendingTickerInfo.updateOpenInterest(asNumberOrUndefined(message.data.openInterest));
pendingTickerInfo.updateIndexPrice(indexPrice?.price);
if (pendingTickerInfo.hasChanged()) {
pendingTickerInfo.updateTimestamp(new Date(message.data.createdAtDatetime));
yield pendingTickerInfo.getSnapshot(localTimestamp);
}
}
}
export class BullishOptionSummaryMapper {
indexPrices = new Map();
canHandle(message) {
if (message.dataType === 'V1TAIndexPrice' && (message.type === 'snapshot' || message.type === 'update')) {
return true;
}
if (message.dataType === 'V1TATickerResponse' && (message.type === 'snapshot' || message.type === 'update')) {
const tickerMessage = message;
return tickerMessage.data.symbol.endsWith('-C') || tickerMessage.data.symbol.endsWith('-P');
}
return false;
}
getFilters(symbols) {
return [
{
channel: 'V1TATickerResponse',
symbols
},
{
channel: 'V1TAIndexPrice',
symbols: symbols === undefined ? undefined : [...new Set(symbols.map((symbol) => symbol.split('-')[0]))]
}
];
}
*map(message, localTimestamp) {
if (message.dataType === 'V1TAIndexPrice') {
const price = asNonZeroNumberOrUndefined(message.data.price);
if (price !== undefined) {
this.indexPrices.set(message.data.assetSymbol, {
price,
timestamp: new Date(message.data.updatedAtDatetime)
});
}
return;
}
const [indexAsset, , dateText, strikePriceText, optionType] = message.data.symbol.split('-');
const indexPrice = this.indexPrices.get(indexAsset);
const expirationDate = new Date(`${dateText.slice(0, 4)}-${dateText.slice(4, 6)}-${dateText.slice(6, 8)}Z`);
expirationDate.setUTCHours(8);
yield {
type: 'option_summary',
symbol: message.data.symbol,
exchange: 'bullish',
optionType: optionType === 'P' ? 'put' : 'call',
strikePrice: Number(strikePriceText),
expirationDate,
bestBidPrice: asNonZeroNumberOrUndefined(message.data.bestBid),
bestBidAmount: asNonZeroNumberOrUndefined(message.data.bidVolume),
bestBidIV: undefined,
bestAskPrice: asNonZeroNumberOrUndefined(message.data.bestAsk),
bestAskAmount: asNonZeroNumberOrUndefined(message.data.askVolume),
bestAskIV: undefined,
lastPrice: asNonZeroNumberOrUndefined(message.data.last),
openInterest: asNumberOrUndefined(message.data.openInterest),
markPrice: asNumberOrUndefined(message.data.markPrice),
markIV: asNonZeroNumberOrUndefined(message.data.impliedVolatility),
delta: asNumberOrUndefined(message.data.delta),
gamma: asNumberOrUndefined(message.data.gamma),
vega: asNumberOrUndefined(message.data.vega),
theta: asNumberOrUndefined(message.data.theta),
rho: undefined,
underlyingPrice: indexPrice?.price,
underlyingIndex: indexAsset,
timestamp: new Date(message.data.createdAtDatetime),
localTimestamp
};
}
}
//# sourceMappingURL=bullish.js.map