diff --git a/README.md b/README.md index fcc6f167..1edcf582 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,8 @@ Actively maintained, typed, and safe SDK for the Binance REST APIs and Websocket ### Features - Spot, Margin, Futures and Delivery API -- Testnet support +- Demo trading support +- Testnet support (deprecated) - Proxy support (REST and WS) - Customizable HTTP headers - Customizable request parameters diff --git a/src/node-binance-api.ts b/src/node-binance-api.ts index 83c71ccd..8bfb8ebe 100644 --- a/src/node-binance-api.ts +++ b/src/node-binance-api.ts @@ -30,24 +30,33 @@ export default class Binance { domain = 'com'; base = `https://api.binance.${this.domain}/api/`; baseTest = `https://testnet.binance.vision/api/`; + baseDemo = `https://demo-api.binance.com/api/`; wapi = `https://api.binance.${this.domain}/wapi/`; sapi = `https://api.binance.${this.domain}/sapi/`; fapi = `https://fapi.binance.${this.domain}/fapi/`; dapi = `https://dapi.binance.${this.domain}/dapi/`; fapiTest = `https://testnet.binancefuture.com/fapi/`; + fapiDemo = `https://demo-fapi.binance.com/fapi/`; dapiTest = `https://testnet.binancefuture.com/dapi/`; + dapiDemo = `https://demo-dapi.binance.com/dapi/`; fstream = `wss://fstream.binance.${this.domain}/stream?streams=`; fstreamSingle = `wss://fstream.binance.${this.domain}/ws/`; fstreamSingleTest = `wss://stream.binancefuture.${this.domain}/ws/`; + fstreamSingleDemo = `wss://fstream.binancefuture.com/ws/`; fstreamTest = `wss://stream.binancefuture.${this.domain}/stream?streams=`; + fstreamDemo = `wss://fstream.binancefuture.com/stream?streams=`; dstream = `wss://dstream.binance.${this.domain}/stream?streams=`; dstreamSingle = `wss://dstream.binance.${this.domain}/ws/`; dstreamSingleTest = `wss://dstream.binancefuture.${this.domain}/ws/`; + dstreamSingleDemo = `wss://dstream.binancefuture.com/ws/`; dstreamTest = `wss://dstream.binancefuture.${this.domain}/stream?streams=`; + dstreamDemo = `wss://dstream.binancefuture.com/stream?streams=`; stream = `wss://stream.binance.${this.domain}:9443/ws/`; streamTest = `wss://stream.testnet.binance.vision/ws/`; + streamDemo = `wss://demo-stream.binance.com/ws/`; combineStream = `wss://stream.binance.${this.domain}:9443/stream?streams=`; combineStreamTest = `wss://stream.testnet.binance.vision/stream?streams=`; + combineStreamDemo = `wss://demo-stream.binance.com/stream?streams=`; verbose = false; @@ -65,7 +74,8 @@ export default class Binance { APISECRET: string = undefined; PRIVATEKEY: string = undefined; PRIVATEKEYPASSWORD: string = undefined; - test = false; + test = false; // sandbox mode + demo = false; // demo mode timeOffset: number = 0; @@ -150,6 +160,7 @@ export default class Binance { keepAlive: true, verbose: false, test: false, + demo: false, hedgeMode: false, localAddress: false, family: 4, @@ -214,8 +225,10 @@ export default class Binance { if (this.Options.PRIVATEKEY) this.PRIVATEKEY = this.Options.PRIVATEKEY; if (this.Options.PRIVATEKEYPASSWORD) this.PRIVATEKEYPASSWORD = this.Options.PRIVATEKEYPASSWORD; if (this.Options.test) this.test = true; + if (this.Options.demo) this.demo = true; if (this.Options.headers) this.headers = this.Options.Headers; if (this.Options.domain) this.domain = this.Options.domain; + if (this.Options.httpsProxy) this.httpsProxy = this.Options.httpsProxy; } async setOptions(opt = {}): Promise { @@ -233,6 +246,7 @@ export default class Binance { extend = (...args: any[]) => Object.assign({}, ...args); getSpotUrl() { + if (this.Options.demo) return this.baseDemo; if (this.Options.test) return this.baseTest; return this.base; } @@ -242,30 +256,53 @@ export default class Binance { } getFapiUrl() { + if (this.Options.demo) return this.fapiDemo; if (this.Options.test) return this.fapiTest; return this.fapi; } getDapiUrl() { + if (this.Options.demo) return this.dapiDemo; if (this.Options.test) return this.dapiTest; return this.dapi; } getCombineStreamUrl() { + if (this.Options.demo) return this.combineStreamDemo; if (this.Options.test) return this.combineStreamTest; return this.combineStream; } getStreamUrl() { + if (this.Options.demo) return this.streamDemo; if (this.Options.test) return this.streamTest; return this.stream; } - getFStreamUrl() { + getDStreamSingleUrl() { + if (this.Options.demo) return this.dstreamSingleDemo; + if (this.Options.test) return this.dstreamSingleTest; + return this.dstreamSingle; + } + + getFStreamSingleUrl() { + if (this.Options.demo) return this.fstreamSingleDemo; if (this.Options.test) return this.fstreamSingleTest; return this.fstreamSingle; } + getFStreamUrl() { + if (this.Options.demo) return this.fstreamDemo; + if (this.Options.test) return this.fstreamTest; + return this.fstream; + } + + getDStreamUrl() { + if (this.Options.demo) return this.dstreamDemo; + if (this.Options.test) return this.dstreamTest; + return this.dstream; + } + uuid22(a?: any) { return a ? (a ^ Math.random() * 16 >> a / 4).toString(16) : (([1e7] as any) + 1e3 + 4e3 + 8e5).replace(/[018]/g, this.uuid22); } @@ -1462,14 +1499,14 @@ export default class Binance { host: this.parseProxy(socksproxy)[1], port: this.parseProxy(socksproxy)[2] }); - ws = new WebSocket((this.getFStreamUrl()) + endpoint, { agent }); + ws = new WebSocket((this.getFStreamSingleUrl()) + endpoint, { agent }); } else if (httpsproxy) { const config = url.parse(httpsproxy); const agent = new HttpsProxyAgent(config); if (this.Options.verbose) this.Options.log(`futuresSubscribeSingle: using proxy server: ${agent}`); - ws = new WebSocket((this.getFStreamUrl()) + endpoint, { agent }); + ws = new WebSocket((this.getFStreamSingleUrl()) + endpoint, { agent }); } else { - ws = new WebSocket((this.getFStreamUrl()) + endpoint); + ws = new WebSocket((this.getFStreamSingleUrl()) + endpoint); } if (this.Options.verbose) this.Options.log('futuresSubscribeSingle: Subscribed to ' + endpoint); @@ -1517,14 +1554,14 @@ export default class Binance { host: this.parseProxy(socksproxy)[1], port: this.parseProxy(socksproxy)[2] }); - ws = new WebSocket((this.Options.test ? this.fstreamTest : this.fstream) + queryParams, { agent }); + ws = new WebSocket(this.getFStreamUrl() + queryParams, { agent }); } else if (httpsproxy) { if (this.Options.verbose) this.Options.log(`futuresSubscribe: using proxy server ${httpsproxy}`); const config = url.parse(httpsproxy); const agent = new HttpsProxyAgent(config); - ws = new WebSocket((this.Options.test ? this.fstreamTest : this.fstream) + queryParams, { agent }); + ws = new WebSocket(this.getFStreamUrl() + queryParams, { agent }); } else { - ws = new WebSocket((this.Options.test ? this.fstreamTest : this.fstream) + queryParams); + ws = new WebSocket(this.getFStreamUrl() + queryParams); } ws.reconnect = this.Options.reconnect; @@ -2175,14 +2212,14 @@ export default class Binance { host: this.parseProxy(socksproxy)[1], port: this.parseProxy(socksproxy)[2] }); - ws = new WebSocket((this.Options.test ? this.dstreamSingleTest : this.dstreamSingle) + endpoint, { agent }); + ws = new WebSocket((this.getDStreamSingleUrl()) + endpoint, { agent }); } else if (httpsproxy) { const config = url.parse(httpsproxy); const agent = new HttpsProxyAgent(config); if (this.Options.verbose) this.Options.log(`deliverySubscribeSingle: using proxy server: ${agent}`); - ws = new WebSocket((this.Options.test ? this.dstreamSingleTest : this.dstreamSingle) + endpoint, { agent }); + ws = new WebSocket((this.getDStreamSingleUrl()) + endpoint, { agent }); } else { - ws = new WebSocket((this.Options.test ? this.dstreamSingleTest : this.dstreamSingle) + endpoint); + ws = new WebSocket((this.getDStreamSingleUrl()) + endpoint); } if (this.Options.verbose) this.Options.log('deliverySubscribeSingle: Subscribed to ' + endpoint); @@ -2229,14 +2266,14 @@ export default class Binance { host: this.parseProxy(socksproxy)[1], port: this.parseProxy(socksproxy)[2] }); - ws = new WebSocket((this.Options.test ? this.dstreamTest : this.dstream) + queryParams, { agent }); + ws = new WebSocket((this.getDStreamUrl()) + queryParams, { agent }); } else if (httpsproxy) { if (this.Options.verbose) this.Options.log(`deliverySubscribe: using proxy server ${httpsproxy}`); const config = url.parse(httpsproxy); const agent = new HttpsProxyAgent(config); - ws = new WebSocket((this.Options.test ? this.dstreamTest : this.dstream) + queryParams, { agent }); + ws = new WebSocket((this.getDStreamUrl()) + queryParams, { agent }); } else { - ws = new WebSocket((this.Options.test ? this.dstreamTest : this.dstream) + queryParams); + ws = new WebSocket((this.getDStreamUrl()) + queryParams); } ws.reconnect = this.Options.reconnect; @@ -5663,7 +5700,8 @@ export default class Binance { * @param {Function} subscribed_callback - subscription callback */ userFutureData(all_updates_callback?: Callback, margin_call_callback?: Callback, account_update_callback?: Callback, order_update_callback?: Callback, subscribed_callback?: Callback, account_config_update_callback?: Callback) { - const url = (this.Options.test) ? this.fapiTest : this.fapi; + // const url = (this.Options.test) ? this.fapiTest : this.fapi; + const url = this.getFapiUrl(); const reconnect = () => { if (this.Options.reconnect) this.userFutureData(all_updates_callback, margin_call_callback, account_update_callback, order_update_callback, subscribed_callback); @@ -5708,7 +5746,7 @@ export default class Binance { order_update_callback?: Callback, subscribed_callback?: Callback ) { - const url = this.Options.test ? this.dapiTest : this.dapi; + const url = this.getDapiUrl(); const reconnect = async () => { if (this.Options.reconnect) diff --git a/src/types.ts b/src/types.ts index 73c7c8d5..77bd5e3f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -136,6 +136,7 @@ export interface IConstructorArgs { useServerTime: boolean; reconnect: boolean; test: boolean; + demo: boolean; hedgeMode: boolean; httpsProxy: string; socksProxy: string; diff --git a/tests/binance-class-live.test.ts b/tests/binance-class-live.test.ts index 30c98088..c447d951 100644 --- a/tests/binance-class-live.test.ts +++ b/tests/binance-class-live.test.ts @@ -37,14 +37,15 @@ let debug = function (x) { const binance = new Binance().options({ APIKEY: 'X4BHNSimXOK6RKs2FcKqExquJtHjMxz5hWqF0BBeVnfa5bKFMk7X0wtkfEz0cPrJ', APISECRET: 'x8gLihunpNq0d46F2q0TWJmeCDahX5LMXSlv3lSFNbMI3rujSOpTDKdhbcmPSf2i', - test: true + test: true, + httpsProxy: 'http://188.245.226.105:8911' }); const futuresBinance = new Binance().options({ - APIKEY: '227719da8d8499e8d3461587d19f259c0b39c2b462a77c9b748a6119abd74401', - APISECRET: 'b14b935f9cfacc5dec829008733c40da0588051f29a44625c34967b45c11d73c', - hedgeMode: true, - test: true + APIKEY: 'HjhMFvuF1veWQVdUbLIy7TiCYe9fj4W6sEukmddD8TM9kPVRHMK6nS2SdV5mwE5u', + APISECRET: 'Suu9pWcO9zbvVuc6cSQsVuiiw2DmmA8DgHrUfePF9s2RtaHa0zxK3eAF4MfIk7Pd', + demo: true, + httpsProxy: 'http://188.245.226.105:8911' }); /*global describe*/ @@ -307,6 +308,7 @@ describe('Futures MarketBuy', function () { assert(res['orderId'] !== undefined) futuresOrderId = res['orderId']; } catch (e) { + console.error(e); const exceptionA = '{"code":-2010,"msg":"Account has insufficient balance for requested action."}'; const exceptionB = '{"code":-2019,"msg":"Margin is insufficient."}' const eStr = e.toString(); diff --git a/tests/binance-ws-futures.test.ts b/tests/binance-ws-futures.test.ts index 7f7d4d98..fae40c17 100644 --- a/tests/binance-ws-futures.test.ts +++ b/tests/binance-ws-futures.test.ts @@ -13,10 +13,11 @@ const TIMEOUT = 40000; const futuresBinance = new Binance().options({ - APIKEY: '227719da8d8499e8d3461587d19f259c0b39c2b462a77c9b748a6119abd74401', - APISECRET: 'b14b935f9cfacc5dec829008733c40da0588051f29a44625c34967b45c11d73c', + APIKEY: 'HjhMFvuF1veWQVdUbLIy7TiCYe9fj4W6sEukmddD8TM9kPVRHMK6nS2SdV5mwE5u', + APISECRET: 'Suu9pWcO9zbvVuc6cSQsVuiiw2DmmA8DgHrUfePF9s2RtaHa0zxK3eAF4MfIk7Pd', hedgeMode: true, - test: true + demo: true, + httpsProxy: 'http://188.245.226.105:8911' }); diff --git a/tests/binance-ws-spot.test.ts b/tests/binance-ws-spot.test.ts index b1cfaa58..df91e1ff 100644 --- a/tests/binance-ws-spot.test.ts +++ b/tests/binance-ws-spot.test.ts @@ -15,7 +15,8 @@ const TIMEOUT = 40000; const binance = new Binance().options({ APIKEY: 'X4BHNSimXOK6RKs2FcKqExquJtHjMxz5hWqF0BBeVnfa5bKFMk7X0wtkfEz0cPrJ', APISECRET: 'x8gLihunpNq0d46F2q0TWJmeCDahX5LMXSlv3lSFNbMI3rujSOpTDKdhbcmPSf2i', - test: true + test: true, + httsProxy: 'http://188.245.226.105:8911' }); const futuresBinance = new Binance().options({