From ad58afab9d28bf1ef39939a70d35c0923442a8d4 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Wed, 21 Dec 2022 18:11:19 +0800 Subject: [PATCH 1/6] binance: add watchTickers --- js/pro/binance.js | 141 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 131 insertions(+), 10 deletions(-) diff --git a/js/pro/binance.js b/js/pro/binance.js index 2d4a663a9805..f5779ef3cbc6 100644 --- a/js/pro/binance.js +++ b/js/pro/binance.js @@ -20,7 +20,7 @@ module.exports = class binance extends binanceRest { 'watchOrderBook': true, 'watchOrders': true, 'watchTicker': true, - 'watchTickers': false, // for now + 'watchTickers': true, 'watchTrades': true, }, 'urls': { @@ -64,6 +64,9 @@ module.exports = class binance extends binanceRest { 'watchTicker': { 'name': 'ticker', // ticker = 1000ms L1+OHLCV, bookTicker = real-time L1 }, + 'watchTickers': { + 'name': '!ticker', // !ticker or !miniTicker + }, 'watchBalance': { 'fetchBalanceSnapshot': false, // or true 'awaitBalanceSnapshot': true, // whether to wait for the balance snapshot before providing updates @@ -745,12 +748,47 @@ module.exports = class binance extends binanceRest { return await this.watch (url, messageHash, this.extend (request, params), messageHash, subscribe); } - handleTicker (client, message) { - // - // 24hr rolling window ticker statistics for a single symbol - // These are NOT the statistics of the UTC day, but a 24hr rolling window for the previous 24hrs - // Update Speed 1000ms + async watchTickers (symbols = undefined, params = {}) { + /** + * @method + * @name binance#watchTickers + * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list + * @param {Array} symbols unified symbol of the market to fetch the ticker for + * @param {object} params extra parameters specific to the binance api endpoint + * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} + */ + await this.loadMarkets (); + symbols = this.marketSymbols (symbols); + let market = undefined; + if (symbols !== undefined) { + market = this.market (symbols[0]); + } + let type = undefined; + [ type, params ] = this.handleMarketTypeAndParams ('watchTickers', market, params); + const options = this.safeValue (this.options, 'watchTickers', {}); + let name = this.safeString (options, 'name', '!ticker'); + name = this.safeString (params, 'name', name); + params = this.omit (params, 'name'); + const messageHash = name + '@arr'; + const url = this.urls['api']['ws'][type] + '/' + this.stream (type, messageHash); + const requestId = this.requestId (url); + const request = { + 'method': 'SUBSCRIBE', + 'params': [ + messageHash, + ], + 'id': requestId, + }; + const subscribe = { + 'id': requestId, + }; + const tickers = await this.watch (url, messageHash, this.extend (request, params), messageHash, subscribe); + return this.filterByArray (tickers, 'symbol', symbols, false); + } + + parseWsTicker (message) { // + // ticker // { // e: '24hrTicker', // event type // E: 1579485598569, // event time @@ -777,12 +815,23 @@ module.exports = class binance extends binanceRest { // n: 163222, // total number of trades // } // + // miniTicker + // { + // e: '24hrMiniTicker', + // E: 1671617114585, + // s: 'MOBBUSD', + // c: '0.95900000', + // o: '0.91200000', + // h: '1.04000000', + // l: '0.89400000', + // v: '2109995.32000000', + // q: '2019254.05788000' + // } + // let event = this.safeString (message, 'e', 'bookTicker'); if (event === '24hrTicker') { event = 'ticker'; } - const wsMarketId = this.safeStringLower (message, 's'); - const messageHash = wsMarketId + '@' + event; let timestamp = undefined; const now = this.milliseconds (); if (event === 'bookTicker') { @@ -795,7 +844,7 @@ module.exports = class binance extends binanceRest { const marketId = this.safeString (message, 's'); const symbol = this.safeSymbol (marketId); const last = this.safeFloat (message, 'c'); - const result = { + const ticker = { 'symbol': symbol, 'timestamp': timestamp, 'datetime': this.iso8601 (timestamp), @@ -817,10 +866,75 @@ module.exports = class binance extends binanceRest { 'quoteVolume': this.safeFloat (message, 'q'), 'info': message, }; + return ticker; + } + + handleTicker (client, message) { + // + // 24hr rolling window ticker statistics for a single symbol + // These are NOT the statistics of the UTC day, but a 24hr rolling window for the previous 24hrs + // Update Speed 1000ms + // + // { + // e: '24hrTicker', // event type + // E: 1579485598569, // event time + // s: 'ETHBTC', // symbol + // p: '-0.00004000', // price change + // P: '-0.209', // price change percent + // w: '0.01920495', // weighted average price + // x: '0.01916500', // the price of the first trade before the 24hr rolling window + // c: '0.01912500', // last (closing) price + // Q: '0.10400000', // last quantity + // b: '0.01912200', // best bid + // B: '4.10400000', // best bid quantity + // a: '0.01912500', // best ask + // A: '0.00100000', // best ask quantity + // o: '0.01916500', // open price + // h: '0.01956500', // high price + // l: '0.01887700', // low price + // v: '173518.11900000', // base volume + // q: '3332.40703994', // quote volume + // O: 1579399197842, // open time + // C: 1579485597842, // close time + // F: 158251292, // first trade id + // L: 158414513, // last trade id + // n: 163222, // total number of trades + // } + // + let event = this.safeString (message, 'e', 'bookTicker'); + if (event === '24hrTicker') { + event = 'ticker'; + } else if (event === '24hrMiniTicker') { + event = 'miniTicker'; + } + const wsMarketId = this.safeStringLower (message, 's'); + const messageHash = wsMarketId + '@' + event; + const result = this.parseWsTicker (message); + const symbol = result['symbol']; this.tickers[symbol] = result; client.resolve (result, messageHash); } + handleTickers (client, message) { + let event = undefined; + for (let i = 0; i < message.length; i++) { + const data = message[i]; + event = this.safeString (data, 'e', 'bookTicker'); + if (event === '24hrTicker') { + event = 'ticker'; + } else if (event === '24hrMiniTicker') { + event = 'miniTicker'; + } + const wsMarketId = this.safeStringLower (data, 's'); + const messageHash = wsMarketId + '@' + event; + const ticker = this.parseWsTicker (data); + const symbol = ticker['symbol']; + this.tickers[symbol] = ticker; + client.resolve (ticker, messageHash); + } + client.resolve (this.tickers, '!' + event + '@arr'); + } + async authenticate (params = {}) { const time = this.milliseconds (); let type = this.safeString2 (this.options, 'defaultType', 'authenticate', 'spot'); @@ -1477,7 +1591,10 @@ module.exports = class binance extends binanceRest { 'trade': this.handleTrade, 'aggTrade': this.handleTrade, 'kline': this.handleOHLCV, + '24hrTicker@arr': this.handleTickers, + '24hrMiniTicker@arr': this.handleTickers, '24hrTicker': this.handleTicker, + '24hrMiniTicker': this.handleTicker, 'bookTicker': this.handleTicker, 'outboundAccountPosition': this.handleBalance, 'balanceUpdate': this.handleBalance, @@ -1485,7 +1602,11 @@ module.exports = class binance extends binanceRest { 'executionReport': this.handleOrderUpdate, 'ORDER_TRADE_UPDATE': this.handleOrderUpdate, }; - const event = this.safeString (message, 'e'); + let event = this.safeString (message, 'e'); + if (Array.isArray (message)) { + const data = message[0]; + event = this.safeString (data, 'e') + '@arr'; + } const method = this.safeValue (methods, event); if (method === undefined) { const requestId = this.safeString (message, 'id'); From cabe77ca50535078ec77fcd0a191752120b57463 Mon Sep 17 00:00:00 2001 From: carlosmiei <43336371+carlosmiei@users.noreply.github.com> Date: Wed, 21 Dec 2022 16:10:09 +0000 Subject: [PATCH 2/6] fix not ticker --- js/pro/binance.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/pro/binance.js b/js/pro/binance.js index f5779ef3cbc6..654440d213da 100644 --- a/js/pro/binance.js +++ b/js/pro/binance.js @@ -65,7 +65,7 @@ module.exports = class binance extends binanceRest { 'name': 'ticker', // ticker = 1000ms L1+OHLCV, bookTicker = real-time L1 }, 'watchTickers': { - 'name': '!ticker', // !ticker or !miniTicker + 'name': '!' + 'ticker', // !ticker or !miniTicker }, 'watchBalance': { 'fetchBalanceSnapshot': false, // or true @@ -766,7 +766,7 @@ module.exports = class binance extends binanceRest { let type = undefined; [ type, params ] = this.handleMarketTypeAndParams ('watchTickers', market, params); const options = this.safeValue (this.options, 'watchTickers', {}); - let name = this.safeString (options, 'name', '!ticker'); + let name = this.safeString (options, 'name', '!' + 'ticker'); name = this.safeString (params, 'name', name); params = this.omit (params, 'name'); const messageHash = name + '@arr'; From 2d6338672b5362918a389fe4a192b4b83e649dcf Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Thu, 22 Dec 2022 19:54:12 +0800 Subject: [PATCH 3/6] binance: watch bookTickers --- js/pro/binance.js | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/js/pro/binance.js b/js/pro/binance.js index f5779ef3cbc6..95d4b1730674 100644 --- a/js/pro/binance.js +++ b/js/pro/binance.js @@ -758,10 +758,10 @@ module.exports = class binance extends binanceRest { * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); - symbols = this.marketSymbols (symbols); + const marketIds = this.marketIds (symbols); let market = undefined; - if (symbols !== undefined) { - market = this.market (symbols[0]); + if (marketIds !== undefined) { + market = this.market (marketIds[0]); } let type = undefined; [ type, params ] = this.handleMarketTypeAndParams ('watchTickers', market, params); @@ -769,14 +769,25 @@ module.exports = class binance extends binanceRest { let name = this.safeString (options, 'name', '!ticker'); name = this.safeString (params, 'name', name); params = this.omit (params, 'name'); - const messageHash = name + '@arr'; + let messageHash = ''; + let wsParams = []; + if (name === 'bookTicker') { + // simulate watchTickers with subscribe multiple individual bookTicker topic + messageHash = 'bookTicker@arr'; + for (let i = 0; i < marketIds.length; i++) { + wsParams.push (marketIds[i].toLowerCase () + '@bookTicker'); + } + } else { + messageHash = name + '@arr'; + wsParams = [ + messageHash, + ]; + } const url = this.urls['api']['ws'][type] + '/' + this.stream (type, messageHash); const requestId = this.requestId (url); const request = { 'method': 'SUBSCRIBE', - 'params': [ - messageHash, - ], + 'params': wsParams, 'id': requestId, }; const subscribe = { @@ -908,11 +919,19 @@ module.exports = class binance extends binanceRest { event = 'miniTicker'; } const wsMarketId = this.safeStringLower (message, 's'); - const messageHash = wsMarketId + '@' + event; + let messageHash = wsMarketId + '@' + event; const result = this.parseWsTicker (message); const symbol = result['symbol']; this.tickers[symbol] = result; client.resolve (result, messageHash); + // check whether message is for watching bookTickers + const messageHashes = Object.keys (client.futures); + for (let i = 0; i < messageHashes.length; i++) { + messageHash = messageHashes[i]; + if (messageHash === 'bookTicker@arr') { + client.resolve (this.tickers, messageHash); + } + } } handleTickers (client, message) { From 92b2ab05a6ed5cf6717e3dd06b4803bccef17666 Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Fri, 23 Dec 2022 11:19:17 +0800 Subject: [PATCH 4/6] binance: update --- js/pro/binance.js | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/js/pro/binance.js b/js/pro/binance.js index 6155a85474c8..be5cd6c122a7 100644 --- a/js/pro/binance.js +++ b/js/pro/binance.js @@ -4,7 +4,7 @@ const binanceRest = require ('../binance.js'); const Precise = require ('../base/Precise'); -const { ExchangeError } = require ('../base/errors'); +const { ExchangeError, ArgumentsRequired } = require ('../base/errors'); const { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } = require ('./base/Cache'); // ----------------------------------------------------------------------------- @@ -769,20 +769,23 @@ module.exports = class binance extends binanceRest { let name = this.safeString (options, 'name', '!' + 'ticker'); name = this.safeString (params, 'name', name); params = this.omit (params, 'name'); - let messageHash = ''; let wsParams = []; + const marketSymbols = this.marketSymbols (symbols); + let messageHash = name + '@arr'; if (name === 'bookTicker') { + if (marketIds === undefined) { + throw new ArgumentsRequired (this.id + ' watchTickers() requires symbols for bookTicker'); + } // simulate watchTickers with subscribe multiple individual bookTicker topic - messageHash = 'bookTicker@arr'; for (let i = 0; i < marketIds.length; i++) { wsParams.push (marketIds[i].toLowerCase () + '@bookTicker'); } } else { - messageHash = name + '@arr'; wsParams = [ messageHash, ]; } + messageHash += marketSymbols.join ('|'); const url = this.urls['api']['ws'][type] + '/' + this.stream (type, messageHash); const requestId = this.requestId (url); const request = { @@ -924,34 +927,22 @@ module.exports = class binance extends binanceRest { const symbol = result['symbol']; this.tickers[symbol] = result; client.resolve (result, messageHash); - // check whether message is for watching bookTickers + // check whether message is for watching tickers const messageHashes = Object.keys (client.futures); + const tickersEvent = event + '@arr'; for (let i = 0; i < messageHashes.length; i++) { messageHash = messageHashes[i]; - if (messageHash === 'bookTicker@arr') { + if (messageHash.indexOf (tickersEvent) >= 0 && messageHash.indexOf (symbol) >= 0) { client.resolve (this.tickers, messageHash); } } } handleTickers (client, message) { - let event = undefined; for (let i = 0; i < message.length; i++) { - const data = message[i]; - event = this.safeString (data, 'e', 'bookTicker'); - if (event === '24hrTicker') { - event = 'ticker'; - } else if (event === '24hrMiniTicker') { - event = 'miniTicker'; - } - const wsMarketId = this.safeStringLower (data, 's'); - const messageHash = wsMarketId + '@' + event; - const ticker = this.parseWsTicker (data); - const symbol = ticker['symbol']; - this.tickers[symbol] = ticker; - client.resolve (ticker, messageHash); + const ticker = message[i]; + this.handleTicker (client, ticker); } - client.resolve (this.tickers, '!' + event + '@arr'); } async authenticate (params = {}) { From a9a9fd154e7739769fb03158ce851bbc812c689b Mon Sep 17 00:00:00 2001 From: sc0Vu Date: Fri, 23 Dec 2022 23:32:23 +0800 Subject: [PATCH 5/6] binance: update --- js/pro/binance.js | 57 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/js/pro/binance.js b/js/pro/binance.js index be5cd6c122a7..91902becd7da 100644 --- a/js/pro/binance.js +++ b/js/pro/binance.js @@ -65,7 +65,7 @@ module.exports = class binance extends binanceRest { 'name': 'ticker', // ticker = 1000ms L1+OHLCV, bookTicker = real-time L1 }, 'watchTickers': { - 'name': '!' + 'ticker', // !ticker or !miniTicker + 'name': 'ticker', // ticker or miniTicker or bookTicker }, 'watchBalance': { 'fetchBalanceSnapshot': false, // or true @@ -758,20 +758,21 @@ module.exports = class binance extends binanceRest { * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); + symbols = this.marketSymbols (symbols); const marketIds = this.marketIds (symbols); let market = undefined; if (marketIds !== undefined) { - market = this.market (marketIds[0]); + market = this.safeMarket (marketIds[0]); } let type = undefined; [ type, params ] = this.handleMarketTypeAndParams ('watchTickers', market, params); const options = this.safeValue (this.options, 'watchTickers', {}); - let name = this.safeString (options, 'name', '!' + 'ticker'); + let name = this.safeString (options, 'name', 'ticker'); name = this.safeString (params, 'name', name); + const oriParams = params; params = this.omit (params, 'name'); let wsParams = []; - const marketSymbols = this.marketSymbols (symbols); - let messageHash = name + '@arr'; + const messageHash = '!' + name + '@arr'; if (name === 'bookTicker') { if (marketIds === undefined) { throw new ArgumentsRequired (this.id + ' watchTickers() requires symbols for bookTicker'); @@ -785,7 +786,6 @@ module.exports = class binance extends binanceRest { messageHash, ]; } - messageHash += marketSymbols.join ('|'); const url = this.urls['api']['ws'][type] + '/' + this.stream (type, messageHash); const requestId = this.requestId (url); const request = { @@ -797,7 +797,21 @@ module.exports = class binance extends binanceRest { 'id': requestId, }; const tickers = await this.watch (url, messageHash, this.extend (request, params), messageHash, subscribe); - return this.filterByArray (tickers, 'symbol', symbols, false); + const result = {}; + for (let i = 0; i < tickers.length; i++) { + const ticker = tickers[i]; + const tickerSymbol = ticker['symbol']; + if (symbols !== undefined && this.inArray (tickerSymbol, symbols)) { + result[tickerSymbol] = ticker; + } + } + if (Object.keys (result).length > 0) { + if (this.newUpdates) { + return result; + } + return this.filterByArray (this.tickers, 'symbol', symbols); + } + return await this.watchTickers (symbols, oriParams); } parseWsTicker (message) { @@ -922,27 +936,36 @@ module.exports = class binance extends binanceRest { event = 'miniTicker'; } const wsMarketId = this.safeStringLower (message, 's'); - let messageHash = wsMarketId + '@' + event; + const messageHash = wsMarketId + '@' + event; const result = this.parseWsTicker (message); const symbol = result['symbol']; this.tickers[symbol] = result; client.resolve (result, messageHash); - // check whether message is for watching tickers - const messageHashes = Object.keys (client.futures); - const tickersEvent = event + '@arr'; - for (let i = 0; i < messageHashes.length; i++) { - messageHash = messageHashes[i]; - if (messageHash.indexOf (tickersEvent) >= 0 && messageHash.indexOf (symbol) >= 0) { - client.resolve (this.tickers, messageHash); - } + if (event === 'bookTicker') { + // watch bookTickers + client.resolve ([ result ], '!' + 'bookTicker@arr'); } } handleTickers (client, message) { + let event = undefined; for (let i = 0; i < message.length; i++) { const ticker = message[i]; - this.handleTicker (client, ticker); + event = this.safeString (ticker, 'e'); + if (event === '24hrTicker') { + event = 'ticker'; + } else if (event === '24hrMiniTicker') { + event = 'miniTicker'; + } + const wsMarketId = this.safeStringLower (ticker, 's'); + const messageHash = wsMarketId + '@' + event; + const result = this.parseWsTicker (ticker); + const symbol = result['symbol']; + this.tickers[symbol] = result; + client.resolve (result, messageHash); } + const values = Object.values (this.tickers); + client.resolve (values, '!' + event + '@arr'); } async authenticate (params = {}) { From cd6a0679e56f4590d3f5045ce19ebe54566d0a88 Mon Sep 17 00:00:00 2001 From: carlosmiei <43336371+carlosmiei@users.noreply.github.com> Date: Wed, 4 Jan 2023 15:49:43 +0000 Subject: [PATCH 6/6] fix python transpilation --- js/pro/binance.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/pro/binance.js b/js/pro/binance.js index 91902becd7da..d0b864f48eb8 100644 --- a/js/pro/binance.js +++ b/js/pro/binance.js @@ -805,7 +805,8 @@ module.exports = class binance extends binanceRest { result[tickerSymbol] = ticker; } } - if (Object.keys (result).length > 0) { + const resultKeys = Object.keys (result); + if (resultKeys.length > 0) { if (this.newUpdates) { return result; }