tardis-dev
Advanced tools
Comparing version 10.0.10 to 10.0.11
@@ -28,2 +28,3 @@ import { BookChange, DerivativeTicker, FilterForExchange, Trade } from '../types'; | ||
symbol: string; | ||
state?: 'Open' | 'Closed' | 'Unlisted' | 'Settled'; | ||
openInterest?: number | null; | ||
@@ -30,0 +31,0 @@ fundingRate?: number | null; |
@@ -73,24 +73,13 @@ "use strict"; | ||
// https://www.bitmex.com/app/restAPI#OrderBookL2 | ||
let levelMeta = this._idToPriceLevelMap.get(item.id); | ||
// There are cases when bitmex can publish: | ||
// a) update for a given level that has also changed side, for example it was a bid now it's an ask but we've got single message (instead of two: insert to asks and delete from bids) | ||
// b) insert message to add new level but such level already exists but on the other side of the order book, but still there was no delete message for the other side of the book | ||
// We need to detect such cases and in addition to normal processing also remove the level from the opposite side | ||
let levelSwitchedSides = levelMeta !== undefined && levelMeta.side !== item.side; | ||
if (item.price !== undefined || levelSwitchedSides) { | ||
// as long as price or side has changed we need to update our local meta info | ||
const metaToCache = { | ||
price: item.price !== undefined ? item.price : levelMeta.price, | ||
side: item.side | ||
}; | ||
this._idToPriceLevelMap.set(item.id, metaToCache); | ||
levelMeta = metaToCache; | ||
if (item.price !== undefined) { | ||
// store the mapping from id to price level if price is specified | ||
// only partials and inserts have price set | ||
this._idToPriceLevelMap.set(item.id, item.price); | ||
} | ||
// if we still don't have a meta info it means that there was an update before partial message - let's skip it | ||
if (levelMeta === undefined) { | ||
const price = this._idToPriceLevelMap.get(item.id); | ||
const amount = item.size || 0; // delete messages do not have size specified | ||
// if we still don't have a price it means that there was an update before partial message - let's skip it | ||
if (price === undefined) { | ||
continue; | ||
} | ||
const amount = item.size || 0; // delete messages do not contain size field | ||
const { price } = levelMeta; | ||
// construct book change according to provided item side | ||
if (item.side === 'Buy') { | ||
@@ -102,11 +91,2 @@ bids.push({ price, amount }); | ||
} | ||
// as long as item side has changed we need to remove such level from the opposite side | ||
if (levelSwitchedSides) { | ||
if (item.side === 'Buy') { | ||
asks.push({ price, amount: 0 }); | ||
} | ||
else { | ||
bids.push({ price, amount: 0 }); | ||
} | ||
} | ||
// remove meta info for deleted level | ||
@@ -151,16 +131,24 @@ if (bitmexOrderBookL2Message.action === 'delete') { | ||
for (const bitmexInstrument of message.data) { | ||
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(bitmexInstrument.symbol, 'bitmex'); | ||
pendingTickerInfo.updateFundingRate(bitmexInstrument.fundingRate); | ||
pendingTickerInfo.updatePredictedFundingRate(bitmexInstrument.indicativeFundingRate); | ||
pendingTickerInfo.updateFundingTimestamp(bitmexInstrument.fundingTimestamp ? new Date(bitmexInstrument.fundingTimestamp) : undefined); | ||
pendingTickerInfo.updateIndexPrice(bitmexInstrument.indicativeSettlePrice); | ||
pendingTickerInfo.updateMarkPrice(bitmexInstrument.markPrice); | ||
pendingTickerInfo.updateOpenInterest(bitmexInstrument.openInterest); | ||
pendingTickerInfo.updateLastPrice(bitmexInstrument.lastPrice); | ||
if (bitmexInstrument.timestamp !== undefined) { | ||
pendingTickerInfo.updateTimestamp(new Date(bitmexInstrument.timestamp)); | ||
// process instrument messages only if: | ||
// - we already have seen their 'partials' or already have 'pending info' | ||
// - and instruments aren't settled or unlisted already | ||
const isOpen = bitmexInstrument.state === undefined || bitmexInstrument.state === 'Open' || bitmexInstrument.state === 'Closed'; | ||
const isPartial = message.action === 'partial'; | ||
const hasPendingInfo = this.pendingTickerInfoHelper.hasPendingTickerInfo(bitmexInstrument.symbol); | ||
if ((isPartial || hasPendingInfo) && isOpen) { | ||
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(bitmexInstrument.symbol, 'bitmex'); | ||
pendingTickerInfo.updateFundingRate(bitmexInstrument.fundingRate); | ||
pendingTickerInfo.updatePredictedFundingRate(bitmexInstrument.indicativeFundingRate); | ||
pendingTickerInfo.updateFundingTimestamp(bitmexInstrument.fundingTimestamp ? new Date(bitmexInstrument.fundingTimestamp) : undefined); | ||
pendingTickerInfo.updateIndexPrice(bitmexInstrument.indicativeSettlePrice); | ||
pendingTickerInfo.updateMarkPrice(bitmexInstrument.markPrice); | ||
pendingTickerInfo.updateOpenInterest(bitmexInstrument.openInterest); | ||
pendingTickerInfo.updateLastPrice(bitmexInstrument.lastPrice); | ||
if (bitmexInstrument.timestamp !== undefined) { | ||
pendingTickerInfo.updateTimestamp(new Date(bitmexInstrument.timestamp)); | ||
} | ||
if (pendingTickerInfo.hasChanged()) { | ||
yield pendingTickerInfo.getSnapshot(localTimestamp); | ||
} | ||
} | ||
if (pendingTickerInfo.hasChanged()) { | ||
yield pendingTickerInfo.getSnapshot(localTimestamp); | ||
} | ||
} | ||
@@ -167,0 +155,0 @@ } |
@@ -11,2 +11,3 @@ import { DerivativeTicker, Exchange, FilterForExchange, NormalizedData } from '../types'; | ||
getPendingTickerInfo(symbol: string, exchange: Exchange): PendingDerivativeTickerInfo; | ||
hasPendingTickerInfo(symbol: string): boolean; | ||
} | ||
@@ -13,0 +14,0 @@ declare class PendingDerivativeTickerInfo { |
@@ -16,2 +16,5 @@ "use strict"; | ||
} | ||
hasPendingTickerInfo(symbol) { | ||
return this._pendingTickers.has(symbol); | ||
} | ||
} | ||
@@ -18,0 +21,0 @@ exports.PendingTickerInfoHelper = PendingTickerInfoHelper; |
{ | ||
"name": "tardis-dev", | ||
"version": "10.0.10", | ||
"version": "10.0.11", | ||
"engines": { | ||
@@ -5,0 +5,0 @@ "node": ">=12" |
@@ -38,9 +38,3 @@ import { BookChange, BookPriceLevel, DerivativeTicker, FilterForExchange, Trade } from '../types' | ||
export class BitmexBookChangeMapper implements Mapper<'bitmex', BookChange> { | ||
private readonly _idToPriceLevelMap: Map< | ||
number, | ||
{ | ||
price: number | ||
side: 'Buy' | 'Sell' | ||
} | ||
> = new Map() | ||
private readonly _idToPriceLevelMap: Map<number, number> = new Map() | ||
@@ -91,31 +85,14 @@ canHandle(message: BitmexDataMessage) { | ||
// https://www.bitmex.com/app/restAPI#OrderBookL2 | ||
let levelMeta = this._idToPriceLevelMap.get(item.id) | ||
// There are cases when bitmex can publish: | ||
// a) update for a given level that has also changed side, for example it was a bid now it's an ask but we've got single message (instead of two: insert to asks and delete from bids) | ||
// b) insert message to add new level but such level already exists but on the other side of the order book, but still there was no delete message for the other side of the book | ||
// We need to detect such cases and in addition to normal processing also remove the level from the opposite side | ||
let levelSwitchedSides = levelMeta !== undefined && levelMeta.side !== item.side | ||
if (item.price !== undefined || levelSwitchedSides) { | ||
// as long as price or side has changed we need to update our local meta info | ||
const metaToCache = { | ||
price: item.price !== undefined ? item.price : levelMeta!.price, | ||
side: item.side | ||
} | ||
this._idToPriceLevelMap.set(item.id, metaToCache) | ||
levelMeta = metaToCache | ||
if (item.price !== undefined) { | ||
// store the mapping from id to price level if price is specified | ||
// only partials and inserts have price set | ||
this._idToPriceLevelMap.set(item.id, item.price) | ||
} | ||
// if we still don't have a meta info it means that there was an update before partial message - let's skip it | ||
if (levelMeta === undefined) { | ||
const price = this._idToPriceLevelMap.get(item.id) | ||
const amount = item.size || 0 // delete messages do not have size specified | ||
// if we still don't have a price it means that there was an update before partial message - let's skip it | ||
if (price === undefined) { | ||
continue | ||
} | ||
const amount = item.size || 0 // delete messages do not contain size field | ||
const { price } = levelMeta | ||
// construct book change according to provided item side | ||
if (item.side === 'Buy') { | ||
@@ -126,12 +103,2 @@ bids.push({ price, amount }) | ||
} | ||
// as long as item side has changed we need to remove such level from the opposite side | ||
if (levelSwitchedSides) { | ||
if (item.side === 'Buy') { | ||
asks.push({ price, amount: 0 }) | ||
} else { | ||
bids.push({ price, amount: 0 }) | ||
} | ||
} | ||
// remove meta info for deleted level | ||
@@ -179,18 +146,29 @@ if (bitmexOrderBookL2Message.action === 'delete') { | ||
for (const bitmexInstrument of message.data) { | ||
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(bitmexInstrument.symbol, 'bitmex') | ||
// process instrument messages only if: | ||
// - we already have seen their 'partials' or already have 'pending info' | ||
// - and instruments aren't settled or unlisted already | ||
const isOpen = bitmexInstrument.state === undefined || bitmexInstrument.state === 'Open' || bitmexInstrument.state === 'Closed' | ||
const isPartial = message.action === 'partial' | ||
const hasPendingInfo = this.pendingTickerInfoHelper.hasPendingTickerInfo(bitmexInstrument.symbol) | ||
pendingTickerInfo.updateFundingRate(bitmexInstrument.fundingRate) | ||
pendingTickerInfo.updatePredictedFundingRate(bitmexInstrument.indicativeFundingRate) | ||
pendingTickerInfo.updateFundingTimestamp(bitmexInstrument.fundingTimestamp ? new Date(bitmexInstrument.fundingTimestamp) : undefined) | ||
pendingTickerInfo.updateIndexPrice(bitmexInstrument.indicativeSettlePrice) | ||
pendingTickerInfo.updateMarkPrice(bitmexInstrument.markPrice) | ||
pendingTickerInfo.updateOpenInterest(bitmexInstrument.openInterest) | ||
pendingTickerInfo.updateLastPrice(bitmexInstrument.lastPrice) | ||
if ((isPartial || hasPendingInfo) && isOpen) { | ||
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(bitmexInstrument.symbol, 'bitmex') | ||
if (bitmexInstrument.timestamp !== undefined) { | ||
pendingTickerInfo.updateTimestamp(new Date(bitmexInstrument.timestamp)) | ||
} | ||
pendingTickerInfo.updateFundingRate(bitmexInstrument.fundingRate) | ||
pendingTickerInfo.updatePredictedFundingRate(bitmexInstrument.indicativeFundingRate) | ||
pendingTickerInfo.updateFundingTimestamp( | ||
bitmexInstrument.fundingTimestamp ? new Date(bitmexInstrument.fundingTimestamp) : undefined | ||
) | ||
pendingTickerInfo.updateIndexPrice(bitmexInstrument.indicativeSettlePrice) | ||
pendingTickerInfo.updateMarkPrice(bitmexInstrument.markPrice) | ||
pendingTickerInfo.updateOpenInterest(bitmexInstrument.openInterest) | ||
pendingTickerInfo.updateLastPrice(bitmexInstrument.lastPrice) | ||
if (pendingTickerInfo.hasChanged()) { | ||
yield pendingTickerInfo.getSnapshot(localTimestamp) | ||
if (bitmexInstrument.timestamp !== undefined) { | ||
pendingTickerInfo.updateTimestamp(new Date(bitmexInstrument.timestamp)) | ||
} | ||
if (pendingTickerInfo.hasChanged()) { | ||
yield pendingTickerInfo.getSnapshot(localTimestamp) | ||
} | ||
} | ||
@@ -214,2 +192,3 @@ } | ||
symbol: string | ||
state?: 'Open' | 'Closed' | 'Unlisted' | 'Settled' | ||
openInterest?: number | null | ||
@@ -216,0 +195,0 @@ fundingRate?: number | null |
@@ -29,2 +29,5 @@ import { DerivativeTicker, Exchange, FilterForExchange, NormalizedData } from '../types' | ||
} | ||
public hasPendingTickerInfo(symbol: string) { | ||
return this._pendingTickers.has(symbol) | ||
} | ||
} | ||
@@ -31,0 +34,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
659518
11644