tardis-dev
Version:
Convenient access to tick-level historical and real-time cryptocurrency market data via Node.js
181 lines • 6.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BinanceOptionSummaryMapper = exports.BinanceOptionsBookChangeMapper = exports.BinanceOptionsTradesMapper = void 0;
const handy_1 = require("../handy");
// https://github.com/binance-exchange/binance-official-api-docs/blob/master/web-socket-streams.md
class BinanceOptionsTradesMapper {
constructor() {
this._lastTradeId = new Map();
}
canHandle(message) {
if (message.stream === undefined) {
return false;
}
return message.stream.endsWith('@TRADE');
}
getFilters(symbols) {
symbols = (0, handy_1.upperCaseSymbols)(symbols);
return [
{
channel: 'TRADE',
symbols
}
];
}
*map(binanceTradeResponse, localTimestamp) {
const symbol = binanceTradeResponse.data.s;
for (const optionsTrade of binanceTradeResponse.data.t) {
// binance options does not only return real-time trade as it happens but just snapshot of last 'x' trades always
// so we need to decide which are real-time trades and which are stale/already processed
const timestamp = new Date(optionsTrade.T);
const tradeIdNumeric = Number(optionsTrade.t);
const lastProcessedTradeId = this._lastTradeId.get(symbol);
const isAlreadyProcessed = lastProcessedTradeId !== undefined && lastProcessedTradeId >= tradeIdNumeric;
const isStaleTrade = localTimestamp.valueOf() - timestamp.valueOf() > 10000;
if (isAlreadyProcessed || isStaleTrade) {
continue;
}
this._lastTradeId.set(symbol, Number(optionsTrade.t));
const trade = {
type: 'trade',
symbol,
exchange: 'binance-options',
id: optionsTrade.t,
price: Number(optionsTrade.p),
amount: Number(optionsTrade.q),
side: optionsTrade.s === '-1' ? 'sell' : 'buy',
timestamp,
localTimestamp: localTimestamp
};
yield trade;
}
}
}
exports.BinanceOptionsTradesMapper = BinanceOptionsTradesMapper;
class BinanceOptionsBookChangeMapper {
canHandle(message) {
if (message.stream === undefined) {
return false;
}
return message.stream.endsWith('@DEPTH100');
}
getFilters(symbols) {
symbols = (0, handy_1.upperCaseSymbols)(symbols);
return [
{
channel: 'DEPTH100',
symbols
}
];
}
*map(message, localTimestamp) {
const bookChange = {
type: 'book_change',
symbol: message.data.s,
exchange: 'binance-options',
isSnapshot: true,
bids: message.data.b.map(this.mapBookLevel),
asks: message.data.a.map(this.mapBookLevel),
timestamp: new Date(message.data.E),
localTimestamp
};
yield bookChange;
}
mapBookLevel(level) {
const price = Number(level[0]);
const amount = Number(level[1]);
return { price, amount };
}
}
exports.BinanceOptionsBookChangeMapper = BinanceOptionsBookChangeMapper;
class BinanceOptionSummaryMapper {
constructor() {
this._indexPrices = new Map();
}
canHandle(message) {
if (message.stream === undefined) {
return false;
}
return message.stream.endsWith('@TICKER') || message.stream.endsWith('@INDEX');
}
getFilters(symbols) {
symbols = (0, handy_1.upperCaseSymbols)(symbols);
const indexes = symbols !== undefined
? symbols.map((s) => {
const symbolParts = s.split('-');
return `${symbolParts[0]}USDT`;
})
: undefined;
return [
{
channel: 'TICKER',
symbols
},
{
channel: 'INDEX',
symbols: indexes
}
];
}
*map(message, localTimestamp) {
if (message.stream.endsWith('@INDEX')) {
const lastIndexPrice = Number(message.data.p);
if (lastIndexPrice > 0) {
this._indexPrices.set(message.data.s, lastIndexPrice);
}
return;
}
const optionInfo = message.data;
const [base, expiryPart, strikePrice, optionType] = optionInfo.s.split('-');
const expirationDate = new Date(`20${expiryPart.slice(0, 2)}-${expiryPart.slice(2, 4)}-${expiryPart.slice(4, 6)}Z`);
expirationDate.setUTCHours(8);
const isPut = optionType === 'P';
const underlyingIndex = `${base}USDT`;
let bestBidPrice = (0, handy_1.asNumberIfValid)(optionInfo.bo);
if (bestBidPrice === 0) {
bestBidPrice = undefined;
}
let bestAskPrice = (0, handy_1.asNumberIfValid)(optionInfo.ao);
if (bestAskPrice === 0) {
bestAskPrice = undefined;
}
let bestBidIV = bestBidPrice !== undefined ? (0, handy_1.asNumberIfValid)(optionInfo.b) : undefined;
if (bestBidIV === -1) {
bestBidIV = undefined;
}
let bestAskIV = bestAskPrice !== undefined ? (0, handy_1.asNumberIfValid)(optionInfo.a) : undefined;
if (bestAskIV === -1) {
bestAskIV = undefined;
}
const optionSummary = {
type: 'option_summary',
symbol: optionInfo.s,
exchange: 'binance-options',
optionType: isPut ? 'put' : 'call',
strikePrice: Number(strikePrice),
expirationDate,
bestBidPrice,
bestBidAmount: undefined,
bestBidIV,
bestAskPrice,
bestAskAmount: undefined,
bestAskIV,
lastPrice: (0, handy_1.asNumberIfValid)(optionInfo.c),
openInterest: undefined,
markPrice: (0, handy_1.asNumberIfValid)(optionInfo.mp),
markIV: undefined,
delta: (0, handy_1.asNumberIfValid)(optionInfo.d),
gamma: (0, handy_1.asNumberIfValid)(optionInfo.g),
vega: (0, handy_1.asNumberIfValid)(optionInfo.v),
theta: (0, handy_1.asNumberIfValid)(optionInfo.t),
rho: undefined,
underlyingPrice: this._indexPrices.get(underlyingIndex),
underlyingIndex,
timestamp: new Date(optionInfo.E),
localTimestamp: localTimestamp
};
yield optionSummary;
}
}
exports.BinanceOptionSummaryMapper = BinanceOptionSummaryMapper;
//# sourceMappingURL=binanceoptions.js.map