Skip to content

Commit 38e5fad

Browse files
committed
feat: add missing USDⓈ-M futures WebSocket streams
Adds all streams from Binance's endpoint mapping that were not previously implemented: Public: - futuresBookTicker, futuresAllBookTickers Market: - futuresMarkPrice (individual symbol, supports 1s update speed) - futuresContinuousCandles (pair + contractType klines) - futuresCompositeIndex (index composition data) - futuresContractInfo (contract listing/status changes) - futuresAssetIndex, futuresAllAssetIndex (multi-assets mode)
1 parent a0c291d commit 38e5fad

2 files changed

Lines changed: 303 additions & 0 deletions

File tree

src/websocket.js

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,223 @@ const futuresAllLiquidations = (cb, transform = true) => {
631631
return options => w.close(1000, 'Close handle was called', { keepClosed: true, ...options })
632632
}
633633

634+
const futuresBookTicker = (payload, cb, transform = true) => {
635+
const cache = (Array.isArray(payload) ? payload : [payload]).map(symbol => {
636+
const w = openWebSocket(
637+
`${endpoints.futuresPublic}/${symbol.toLowerCase()}@bookTicker`,
638+
)
639+
640+
w.onmessage = msg => {
641+
const obj = JSONbig.parse(msg.data)
642+
cb(transform ? bookTickerTransform(obj) : obj)
643+
}
644+
645+
return w
646+
})
647+
648+
return options =>
649+
cache.forEach(w =>
650+
w.close(1000, 'Close handle was called', { keepClosed: true, ...options }),
651+
)
652+
}
653+
654+
const futuresAllBookTickers = (cb, transform = true) => {
655+
const w = openWebSocket(`${endpoints.futuresPublic}/!bookTicker`)
656+
657+
w.onmessage = msg => {
658+
const obj = JSONbig.parse(msg.data)
659+
cb(transform ? bookTickerTransform(obj) : obj)
660+
}
661+
662+
return options => w.close(1000, 'Close handle was called', { keepClosed: true, ...options })
663+
}
664+
665+
const futuresMarkPriceTransform = m => ({
666+
eventType: m.e,
667+
eventTime: m.E,
668+
symbol: m.s,
669+
markPrice: m.p,
670+
indexPrice: m.i,
671+
settlePrice: m.P,
672+
fundingRate: m.r,
673+
nextFundingRate: m.T,
674+
})
675+
676+
const futuresMarkPrice = (payload, cb, transform = true) => {
677+
const cache = (Array.isArray(payload) ? payload : [payload]).map(input => {
678+
const symbol = typeof input === 'object' ? input.symbol : input
679+
const updateSpeed = typeof input === 'object' ? input.updateSpeed : undefined
680+
const stream = updateSpeed === '1s'
681+
? `${symbol.toLowerCase()}@markPrice@1s`
682+
: `${symbol.toLowerCase()}@markPrice`
683+
684+
const w = openWebSocket(`${endpoints.futuresMarket}/${stream}`)
685+
686+
w.onmessage = msg => {
687+
const obj = JSONbig.parse(msg.data)
688+
cb(transform ? futuresMarkPriceTransform(obj) : obj)
689+
}
690+
691+
return w
692+
})
693+
694+
return options =>
695+
cache.forEach(w =>
696+
w.close(1000, 'Close handle was called', { keepClosed: true, ...options }),
697+
)
698+
}
699+
700+
const futuresContinuousCandles = (payload, interval, cb, transform = true) => {
701+
if (!interval || !cb) {
702+
throw new Error('Please pass a pair, contractType, interval and callback.')
703+
}
704+
705+
const pair = payload.pair.toLowerCase()
706+
const contractType = payload.contractType.toLowerCase()
707+
708+
const w = openWebSocket(
709+
`${endpoints.futuresMarket}/${pair}_${contractType}@continuousKline_${interval}`,
710+
)
711+
712+
w.onmessage = msg => {
713+
const obj = JSONbig.parse(msg.data)
714+
const { e: eventType, E: eventTime, ps: pairSymbol, ct: contType, k: tick } = obj
715+
716+
cb(
717+
transform
718+
? {
719+
eventType,
720+
eventTime,
721+
pair: pairSymbol,
722+
contractType: contType,
723+
...candleTransform(tick),
724+
}
725+
: obj,
726+
)
727+
}
728+
729+
return options => w.close(1000, 'Close handle was called', { keepClosed: true, ...options })
730+
}
731+
732+
const futuresCompositeIndex = (payload, cb, transform = true) => {
733+
const cache = (Array.isArray(payload) ? payload : [payload]).map(symbol => {
734+
const w = openWebSocket(
735+
`${endpoints.futuresMarket}/${symbol.toLowerCase()}@compositeIndex`,
736+
)
737+
738+
w.onmessage = msg => {
739+
const obj = JSONbig.parse(msg.data)
740+
cb(
741+
transform
742+
? {
743+
eventType: obj.e,
744+
eventTime: obj.E,
745+
symbol: obj.s,
746+
price: obj.p,
747+
composition: obj.c
748+
? obj.c.map(c => ({
749+
baseAsset: c.b,
750+
quoteAsset: c.q,
751+
weightInQuantity: c.w,
752+
weightInPercentage: c.W,
753+
indexPrice: c.i,
754+
}))
755+
: [],
756+
}
757+
: obj,
758+
)
759+
}
760+
761+
return w
762+
})
763+
764+
return options =>
765+
cache.forEach(w =>
766+
w.close(1000, 'Close handle was called', { keepClosed: true, ...options }),
767+
)
768+
}
769+
770+
const futuresContractInfo = (cb, transform = true) => {
771+
const w = openWebSocket(`${endpoints.futuresMarket}/!contractInfo`)
772+
773+
w.onmessage = msg => {
774+
const obj = JSONbig.parse(msg.data)
775+
cb(
776+
transform
777+
? {
778+
eventType: obj.e,
779+
eventTime: obj.E,
780+
symbol: obj.s,
781+
pair: obj.ps,
782+
contractType: obj.ct,
783+
deliveryDate: obj.dt,
784+
onboardDate: obj.ot,
785+
contractStatus: obj.cs,
786+
brackets: obj.bks
787+
? obj.bks.map(b => ({
788+
notionalBracket: b.bs,
789+
floorNotional: b.bnf,
790+
capNotional: b.bnc,
791+
maintenanceRatio: b.mmr,
792+
auxiliaryNumber: b.cf,
793+
minLeverage: b.mi,
794+
maxLeverage: b.ma,
795+
}))
796+
: [],
797+
}
798+
: obj,
799+
)
800+
}
801+
802+
return options => w.close(1000, 'Close handle was called', { keepClosed: true, ...options })
803+
}
804+
805+
const futuresAssetIndexTransform = m => ({
806+
eventType: m.e,
807+
eventTime: m.E,
808+
symbol: m.s,
809+
index: m.i,
810+
bidBuffer: m.b,
811+
askBuffer: m.a,
812+
bidRate: m.B,
813+
askRate: m.A,
814+
autoExchangeBidBuffer: m.q,
815+
autoExchangeAskBuffer: m.Q,
816+
autoExchangeBidRate: m.g,
817+
autoExchangeAskRate: m.G,
818+
})
819+
820+
const futuresAssetIndex = (payload, cb, transform = true) => {
821+
const cache = (Array.isArray(payload) ? payload : [payload]).map(symbol => {
822+
const w = openWebSocket(
823+
`${endpoints.futuresMarket}/${symbol.toLowerCase()}@assetIndex`,
824+
)
825+
826+
w.onmessage = msg => {
827+
const obj = JSONbig.parse(msg.data)
828+
cb(transform ? futuresAssetIndexTransform(obj) : obj)
829+
}
830+
831+
return w
832+
})
833+
834+
return options =>
835+
cache.forEach(w =>
836+
w.close(1000, 'Close handle was called', { keepClosed: true, ...options }),
837+
)
838+
}
839+
840+
const futuresAllAssetIndex = (cb, transform = true) => {
841+
const w = openWebSocket(`${endpoints.futuresMarket}/!assetIndex@arr`)
842+
843+
w.onmessage = msg => {
844+
const arr = JSONbig.parse(msg.data)
845+
cb(transform ? arr.map(futuresAssetIndexTransform) : arr)
846+
}
847+
848+
return options => w.close(1000, 'Close handle was called', { keepClosed: true, ...options })
849+
}
850+
634851
const tradesTransform = m => ({
635852
eventType: m.e,
636853
eventTime: m.E,
@@ -1363,6 +1580,14 @@ export default opts => {
13631580
aggTrades(payload, cb, transform, 'delivery'),
13641581
futuresLiquidations,
13651582
futuresAllLiquidations,
1583+
futuresBookTicker,
1584+
futuresAllBookTickers,
1585+
futuresMarkPrice,
1586+
futuresContinuousCandles,
1587+
futuresCompositeIndex,
1588+
futuresContractInfo,
1589+
futuresAssetIndex,
1590+
futuresAllAssetIndex,
13661591
futuresUser: user(opts, 'futures'),
13671592
deliveryUser: user(opts, 'delivery'),
13681593
futuresCustomSubStream: (payload, cb) => customSubStream(payload, cb, 'futures'),

types/websocket.d.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,76 @@ export interface FuturesAllMarkPricesPayload {
298298
updateSpeed?: '1s' | '3s';
299299
}
300300

301+
// Futures mark price payload (individual symbol)
302+
export interface FuturesMarkPricePayload {
303+
symbol: string;
304+
updateSpeed?: '1s';
305+
}
306+
307+
// Futures continuous candles payload
308+
export interface FuturesContinuousCandlesPayload {
309+
pair: string;
310+
contractType: string;
311+
}
312+
313+
// Futures continuous candle event
314+
export interface FuturesContinuousCandleEvent extends CandleEvent {
315+
pair: string;
316+
contractType: string;
317+
}
318+
319+
// Futures composite index event
320+
export interface FuturesCompositeIndexEvent {
321+
eventType: string;
322+
eventTime: number;
323+
symbol: string;
324+
price: string;
325+
composition: {
326+
baseAsset: string;
327+
quoteAsset: string;
328+
weightInQuantity: string;
329+
weightInPercentage: string;
330+
indexPrice: string;
331+
}[];
332+
}
333+
334+
// Futures contract info event
335+
export interface FuturesContractInfoEvent {
336+
eventType: string;
337+
eventTime: number;
338+
symbol: string;
339+
pair: string;
340+
contractType: string;
341+
deliveryDate: number;
342+
onboardDate: number;
343+
contractStatus: string;
344+
brackets: {
345+
notionalBracket: number;
346+
floorNotional: number;
347+
capNotional: number;
348+
maintenanceRatio: string;
349+
auxiliaryNumber: number;
350+
minLeverage: number;
351+
maxLeverage: number;
352+
}[];
353+
}
354+
355+
// Futures asset index event
356+
export interface FuturesAssetIndexEvent {
357+
eventType: string;
358+
eventTime: number;
359+
symbol: string;
360+
index: string;
361+
bidBuffer: string;
362+
askBuffer: string;
363+
bidRate: string;
364+
askRate: string;
365+
autoExchangeBidBuffer: string;
366+
autoExchangeAskBuffer: string;
367+
autoExchangeBidRate: string;
368+
autoExchangeAskRate: string;
369+
}
370+
301371
export interface BinanceWebSocket {
302372
// Spot
303373
depth(payload: string | string[], cb: (data: DepthEvent) => void, transform?: boolean): CleanupFn;
@@ -326,6 +396,14 @@ export interface BinanceWebSocket {
326396
futuresAggTrades(payload: string | string[], cb: (data: FuturesAggTradeEvent) => void, transform?: boolean): CleanupFn;
327397
futuresLiquidations(payload: string | string[], cb: (data: FuturesLiquidationEvent) => void, transform?: boolean): CleanupFn;
328398
futuresAllLiquidations(cb: (data: FuturesLiquidationEvent) => void, transform?: boolean): CleanupFn;
399+
futuresBookTicker(payload: string | string[], cb: (data: BookTickerEvent) => void, transform?: boolean): CleanupFn;
400+
futuresAllBookTickers(cb: (data: BookTickerEvent) => void, transform?: boolean): CleanupFn;
401+
futuresMarkPrice(payload: string | string[] | FuturesMarkPricePayload | FuturesMarkPricePayload[], cb: (data: FuturesMarkPriceEvent) => void, transform?: boolean): CleanupFn;
402+
futuresContinuousCandles(payload: FuturesContinuousCandlesPayload, interval: string, cb: (data: FuturesContinuousCandleEvent) => void, transform?: boolean): CleanupFn;
403+
futuresCompositeIndex(payload: string | string[], cb: (data: FuturesCompositeIndexEvent) => void, transform?: boolean): CleanupFn;
404+
futuresContractInfo(cb: (data: FuturesContractInfoEvent) => void, transform?: boolean): CleanupFn;
405+
futuresAssetIndex(payload: string | string[], cb: (data: FuturesAssetIndexEvent) => void, transform?: boolean): CleanupFn;
406+
futuresAllAssetIndex(cb: (data: FuturesAssetIndexEvent[]) => void, transform?: boolean): CleanupFn;
329407
futuresUser(cb: (data: any) => void, transform?: boolean): Promise<CleanupFn>;
330408
futuresCustomSubStream(payload: string | string[], cb: (data: any) => void): CleanupFn;
331409
futuresAllMarkPrices(payload: FuturesAllMarkPricesPayload, cb: (data: FuturesMarkPriceEvent[]) => void): CleanupFn;

0 commit comments

Comments
 (0)