diff --git a/src/node-binance-api.ts b/src/node-binance-api.ts index 8c083158..5fc44497 100644 --- a/src/node-binance-api.ts +++ b/src/node-binance-api.ts @@ -3718,6 +3718,25 @@ export default class Binance { return await this.publicSpotRequest('v3/ping', {}); } + parseAggTrades(symbol: string, trades: any[]): AggregatedTrade[] { + const parsedTrades: AggregatedTrade[] = []; + for (const trade of trades) { + const aggT: AggregatedTrade = { + aggId: trade.a, + symbol: symbol, + price: trade.p, + quantity: trade.q, + firstId: trade.f, + lastId: trade.l, + timestamp: trade.T, + isBuyerMaker: trade.m, + }; + if (trade.M) aggT.wasBestPrice = trade.M; + parsedTrades.push(aggT); + } + return parsedTrades; + } + /** * Get agg trades for given symbol * @see https://developers.binance.com/docs/binance-spot-api-docs/rest-api/market-data-endpoints#compressedaggregate-trades-list @@ -3727,7 +3746,8 @@ export default class Binance { */ async aggTrades(symbol: string, params: Dict = {}): Promise { //fromId startTime endTime limit const parameters = Object.assign({ symbol }, params); - return await this.publicSpotRequest('v3/aggTrades', parameters); + const res = await this.publicSpotRequest('v3/aggTrades', parameters); + return this.parseAggTrades(symbol, res); } /** @@ -3809,7 +3829,8 @@ export default class Binance { async candlesticks(symbol: string, interval: Interval = '5m', params: Dict = {}): Promise { if (!params.limit) params.limit = 500; params = Object.assign({ symbol: symbol, interval: interval }, params); - return await this.publicSpotRequest('v3/klines', params); + const res = await this.publicSpotRequest('v3/klines', params); + return this.parseCandles(res); } /** @@ -3825,6 +3846,42 @@ export default class Binance { return await this.candlesticks(symbol, interval, params); // make name consistent with futures } + parseCandles(candles: any[]): Candle[] { + const res: Candle[] = []; + // spot + // [ + // [ + // 1499040000000, // Open time + // "0.01634790", // Open + // "0.80000000", // High + // "0.01575800", // Low + // "0.01577100", // Close + // "148976.11427815", // Volume + // 1499644799999, // Close time + // "2434.19055334", // Quote asset volume + // 308, // Number of trades + // "1756.87402397", // Taker buy base asset volume + // "28.46694368", // Taker buy quote asset volume + // "17928899.62484339" // Ignore. + // ] + // ] + for (const rawCandle of candles) { + const candle: Candle = { + openTime: rawCandle[0], + open: rawCandle[1], + high: rawCandle[2], + low: rawCandle[3], + close: rawCandle[4], + volume: rawCandle[5], + closeTime: rawCandle[6], + quoteAssetVolume: rawCandle[7], + trades: rawCandle[8], + }; + res.push(candle); + } + return res; + } + // /** // * Queries the public api // * @param {string} url - the public api endpoint @@ -3958,16 +4015,15 @@ export default class Binance { async futuresCandles(symbol: string, interval: Interval = "30m", params: Dict = {}): Promise { params.symbol = symbol; params.interval = interval; - return await this.publicFuturesRequest('v1/klines', params); + const res = await this.publicFuturesRequest('v1/klines', params); + return this.parseCandles(res); } /** * @see https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/rest-api/Kline-Candlestick-Data */ async futuresCandlesticks(symbol: string, interval: Interval = "30m", params: Dict = {}): Promise { - params.symbol = symbol; - params.interval = interval; - return await this.publicFuturesRequest('v1/klines', params); + return await this.futuresCandles(symbol, interval, params); // make name consistent with spot } /** @@ -4480,10 +4536,18 @@ export default class Binance { return res; } + /** + * @see https://developers.binance.com/docs/derivatives/coin-margined-futures/market-data/rest-api/Kline-Candlestick-Data + * @param symbol + * @param interval + * @param params + * @returns + */ async deliveryCandles(symbol: string, interval: Interval = "30m", params: Dict = {}): Promise { params.symbol = symbol; params.interval = interval; - return await this.publicDeliveryRequest('v1/klines', params); + const res = await this.publicDeliveryRequest('v1/klines', params); + return this.parseCandles(res); } async deliveryContinuousKlines(pair: string, contractType = "CURRENT_QUARTER", interval: Interval = "30m", params: Dict = {}) { @@ -5739,10 +5803,11 @@ export default class Binance { } }; - const getSymbolDepthSnapshot = async (symbol: string, cb: Function) => { + const getSymbolDepthSnapshot = async (symbol: string) => { const json = await this.publicSpotRequest('v3/depth', { symbol: symbol, limit: limit }); json.symbol = symbol; - cb(null, json); + // cb(null, json); + return json; }; const updateSymbolDepthCache = json => { @@ -5778,12 +5843,13 @@ export default class Binance { const streams = symbols.map(function (symbol) { return symbol.toLowerCase() + `@depth@100ms`; }); + const mapLimit = this.mapLimit.bind(this); subscription = this.subscribeCombined(streams, handleDepthStreamData, reconnect, function () { // async.mapLimit(symbols, 50, getSymbolDepthSnapshot, (err, results) => { // if (err) throw err; // results.forEach(updateSymbolDepthCache); // }); - this.mapLimit(symbols, 50, getSymbolDepthSnapshot) + mapLimit(symbols, 50, getSymbolDepthSnapshot) .then(results => { results.forEach(updateSymbolDepthCache); }) @@ -5795,12 +5861,13 @@ export default class Binance { } else { const symbol = symbols; symbolDepthInit(symbol); + const mapLimit = this.mapLimit.bind(this); subscription = this.subscribe(symbol.toLowerCase() + `@depth@100ms`, handleDepthStreamData, reconnect, function () { // async.mapLimit([symbol], 1, getSymbolDepthSnapshot, (err, results) => { // if (err) throw err; // results.forEach(updateSymbolDepthCache); // }); - this.mapLimit([symbol], 1, getSymbolDepthSnapshot) + mapLimit([symbol], 1, getSymbolDepthSnapshot) .then(results => { results.forEach(updateSymbolDepthCache); }) diff --git a/src/types.ts b/src/types.ts index d90b9e56..6ee30827 100644 --- a/src/types.ts +++ b/src/types.ts @@ -52,9 +52,9 @@ export interface Candle { close: string volume: string closeTime: number - quoteVolume: string + quoteVolume?: string trades: number - baseAssetVolume: string + baseAssetVolume?: string quoteAssetVolume: string } @@ -258,7 +258,7 @@ export interface AggregatedTrade { lastId: number timestamp: number isBuyerMaker: boolean - wasBestPrice: boolean + wasBestPrice?: boolean } export interface Trade { diff --git a/tests/binance-class-static.test.ts b/tests/binance-class-static.test.ts index 4edd61dc..1ef4a078 100644 --- a/tests/binance-class-static.test.ts +++ b/tests/binance-class-static.test.ts @@ -65,19 +65,40 @@ describe( 'Static tests', async function () { }) it( 'OHLCVS', async function ( ) { - await binance.candlesticks( 'BTCUSDT' ) + try { + await binance.candlesticks( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } assert.equal( interceptedUrl, 'https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=5m&limit=500' ) }) it( 'Futures OHLCVS', async function ( ) { - await binance.futuresCandles( 'BTCUSDT' ) + try { + await binance.futuresCandles( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } assert.equal( interceptedUrl, 'https://fapi.binance.com/fapi/v1/klines?symbol=BTCUSDT&interval=30m' ) }) - it( 'Trades', async function ( ) { - await binance.aggTrades( 'BTCUSDT' ) + it( 'Recent Trades', async function ( ) { + try { + await binance.recentTrades( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } + assert.equal( interceptedUrl, 'https://api.binance.com/api/v3/trades?symbol=BTCUSDT&limit=500' ) + }) + + it( 'Agg Trades', async function ( ) { + try { + await binance.aggTrades( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } assert.equal( interceptedUrl, 'https://api.binance.com/api/v3/aggTrades?symbol=BTCUSDT' ) }) @@ -85,7 +106,15 @@ describe( 'Static tests', async function () { it( 'FuturesTrades', async function ( ) { await binance.futuresTrades( 'BTCUSDT' ) assert.equal( interceptedUrl, 'https://fapi.binance.com/fapi/v1/trades?symbol=BTCUSDT' ) + }) + it( 'FuturesAggTrades', async function ( ) { + try { + await binance.futuresAggTrades( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } + assert.equal( interceptedUrl, 'https://fapi.binance.com/fapi/v1/aggTrades?symbol=BTCUSDT' ) }) it( 'PositionRisk V3', async function ( ) { diff --git a/tests/static-tests.mjs b/tests/static-tests.mjs index 85a3d24d..7a33a6e3 100644 --- a/tests/static-tests.mjs +++ b/tests/static-tests.mjs @@ -75,19 +75,31 @@ describe( 'Static tests', async function () { }) it( 'OHLCVS', async function ( ) { - await binance.candlesticks( 'BTCUSDT' ) + try { + await binance.candlesticks( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } assert.equal( interceptedUrl, 'https://api.binance.com/api/v3/klines?symbol=BTCUSDT&interval=5m&limit=500' ) }) it( 'Futures OHLCVS', async function ( ) { - await binance.futuresCandles( 'BTCUSDT' ) + try { + await binance.futuresCandles( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } assert.equal( interceptedUrl, 'https://fapi.binance.com/fapi/v1/klines?symbol=BTCUSDT&interval=30m' ) }) it( 'Trades', async function ( ) { - await binance.aggTrades( 'BTCUSDT' ) + try { + await binance.aggTrades( 'BTCUSDT' ) + } catch (e) { + // console.log(e) + } assert.equal( interceptedUrl, 'https://api.binance.com/api/v3/aggTrades?symbol=BTCUSDT' ) })