Comparing version 1.2.2 to 1.3.0
@@ -29,3 +29,2 @@ module.exports = { | ||
], | ||
'function-paren-newline': 'error', | ||
'implicit-arrow-linebreak': 'error', | ||
@@ -38,3 +37,2 @@ 'indent': [ | ||
'keyword-spacing': 'error', | ||
'lines-around-comment': 'error', | ||
'lines-between-class-members': 'error', | ||
@@ -106,3 +104,2 @@ 'max-len': [ | ||
'block-scoped-var': 'error', | ||
'class-methods-use-this': 'error', | ||
'curly': 'error', | ||
@@ -109,0 +106,0 @@ 'dot-location': ['error', 'property'], |
@@ -11,4 +11,4 @@ { | ||
"name": "Test REST API - exchangeInfo", | ||
"program": "${workspaceRoot}/util/test-api.js" | ||
//"args": ["exchangeInfo"] | ||
"program": "${workspaceRoot}/util/test-api.js", | ||
"args": ["account"] | ||
}, | ||
@@ -15,0 +15,0 @@ { |
# Changelog | ||
## 1.3.0 | ||
- Add the ability to have the library handle system clock drift | ||
## 1.2.2 | ||
@@ -4,0 +7,0 @@ - Fix beautification of allTickers event arrays when using combinedStreams |
159
lib/rest.js
@@ -10,3 +10,10 @@ const request = require('request'); | ||
constructor({ key, secret, recvWindow, timeout = 15000, disableBeautification }) { | ||
constructor({ | ||
key, | ||
secret, | ||
recvWindow = false, | ||
timeout = 15000, | ||
disableBeautification = false, | ||
handleDrift = false | ||
}) { | ||
this.key = key; | ||
@@ -17,8 +24,11 @@ this.secret = secret; | ||
this.disableBeautification = disableBeautification; | ||
this.handleDrift = handleDrift; | ||
this._beautifier = new Beautifier(); | ||
this._baseUrl = 'https://api.binance.com/'; | ||
this._drift = 0; | ||
this._syncInterval = 0; | ||
} | ||
_makeRequest(query, callback, route, security, method) { | ||
_makeRequest(query, callback, route, security, method, attempt = 0) { | ||
assert(_.isUndefined(callback) || _.isFunction(callback), 'callback must be a function or undefined'); | ||
@@ -66,3 +76,18 @@ assert(_.isObject(query), 'query must be an object'); | ||
if (err || response.statusCode < 200 || response.statusCode > 299) { | ||
callback(err || new Error(`Response code ${response.statusCode}`), payload); | ||
/* | ||
* If we get a response that the timestamp is ahead of the server, | ||
* calculate the drift and then attempt the request again | ||
*/ | ||
if (response.statusCode === 400 && payload.code === -1021 && | ||
this.handleDrift && attempt === 0) { | ||
this.calculateDrift() | ||
.then(() => { | ||
query.timestamp = this._getTime() + this._drift; | ||
return this._makeRequest(query, callback, route, security, method, | ||
++attempt); | ||
}); | ||
} else { | ||
callback(err || new Error(`Response code ${response.statusCode}`), payload); | ||
} | ||
} else { | ||
@@ -93,3 +118,23 @@ if (_.isArray(payload)) { | ||
if (response.statusCode < 200 || response.statusCode > 299) { | ||
reject(payload); | ||
/* | ||
* If we get a response that the timestamp is ahead of the server, | ||
* calculate the drift and then attempt the request again | ||
*/ | ||
if (response.statusCode === 400 && payload.code === -1021 && | ||
this.handleDrift && attempt === 0) { | ||
this.calculateDrift() | ||
.then(() => { | ||
query.timestamp = this._getTime() + this._drift; | ||
return this._makeRequest(query, callback, route, security, method, ++attempt); | ||
}) | ||
.then(retryPayload => { | ||
resolve(retryPayload); | ||
}) | ||
.catch(retryErr => { | ||
reject(retryErr); | ||
}); | ||
} else { | ||
reject(payload); | ||
} | ||
} else { | ||
@@ -124,2 +169,41 @@ if (_.isArray(payload)) { | ||
_setTimestamp(query) { | ||
if (!query.timestamp) { | ||
query.timestamp = this._getTime() + this._drift; | ||
} | ||
} | ||
_getTime() { | ||
return new Date().getTime(); | ||
} | ||
calculateDrift() { | ||
const systemTime = this._getTime(); | ||
return this.time() | ||
.then((response) => { | ||
// Calculate the approximate trip time from here to binance | ||
const transitTime = parseInt((this._getTime() - systemTime) / 2); | ||
this._drift = response.serverTime - (systemTime + transitTime); | ||
}); | ||
} | ||
startTimeSync(interval = 300000) { | ||
// If there's already an interval running, clear it and reset values | ||
if (this._syncInterval !== 0) { | ||
this.endTimeSync(); | ||
} | ||
// Calculate initial drift value and setup interval to periodically update it | ||
this.calculateDrift(); | ||
this._syncInterval = setInterval(() => { | ||
this.calculateDrift(); | ||
}, interval); | ||
} | ||
endTimeSync() { | ||
clearInterval(this._syncInterval); | ||
this._drift = 0; | ||
this._syncInterval = 0; | ||
} | ||
// Public APIs | ||
@@ -208,2 +292,3 @@ ping(callback) { | ||
newOrder(query = {}, callback) { | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'POST'); | ||
@@ -213,2 +298,3 @@ } | ||
testOrder(query = {}, callback) { | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/order/test', 'SIGNED', 'POST'); | ||
@@ -218,6 +304,3 @@ } | ||
queryOrder(query = {}, callback) { | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED'); | ||
@@ -227,6 +310,3 @@ } | ||
cancelOrder(query = {}, callback) { | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/order', 'SIGNED', 'DELETE'); | ||
@@ -239,6 +319,3 @@ } | ||
} | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/openOrders', 'SIGNED'); | ||
@@ -251,20 +328,13 @@ } | ||
} | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/allOrders', 'SIGNED'); | ||
} | ||
account(callback, deprecatedCallback) { | ||
/* | ||
* Leaving deprecatedCallback in so as not to change the function signature and cause | ||
* problems, remove in 2.0 | ||
*/ | ||
if (deprecatedCallback) { | ||
callback = deprecatedCallback; | ||
account(query = {}, callback) { | ||
if (_.isFunction(query)) { | ||
callback = query; | ||
query = {}; | ||
} | ||
return this._makeRequest({ timestamp: new Date().getTime() }, callback, 'api/v3/account', 'SIGNED'); | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/account', 'SIGNED'); | ||
} | ||
@@ -276,6 +346,3 @@ | ||
} | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'api/v3/myTrades', 'SIGNED'); | ||
@@ -285,6 +352,3 @@ } | ||
withdraw(query = {}, callback) { | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'wapi/v3/withdraw.html', 'SIGNED', 'POST'); | ||
@@ -297,6 +361,3 @@ } | ||
} | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'wapi/v3/depositHistory.html', 'SIGNED'); | ||
@@ -309,6 +370,3 @@ } | ||
} | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'wapi/v3/withdrawHistory.html', 'SIGNED'); | ||
@@ -321,6 +379,3 @@ } | ||
} | ||
if (!query.timestamp) { | ||
query.timestamp = new Date().getTime(); | ||
} | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'wapi/v3/depositAddress.html', 'SIGNED'); | ||
@@ -330,3 +385,5 @@ } | ||
accountStatus(callback) { | ||
return this._makeRequest({ timestamp: new Date().getTime() }, callback, 'wapi/v3/accountStatus.html', 'SIGNED'); | ||
const query = {}; | ||
this._setTimestamp(query); | ||
return this._makeRequest(query, callback, 'wapi/v3/accountStatus.html', 'SIGNED'); | ||
} | ||
@@ -333,0 +390,0 @@ |
{ | ||
"name": "binance", | ||
"version": "1.2.2", | ||
"version": "1.3.0", | ||
"description": "node.js wrapper for the Binance REST and WebSocket APIs", | ||
@@ -5,0 +5,0 @@ "main": "./lib/binance.js", |
@@ -18,3 +18,3 @@ ![npm downloads](https://img.shields.io/npm/dt/binance.svg) | ||
recvWindow: 10000, // Optional, defaults to 5000, increase if you're getting timestamp errors | ||
disableBeautification: false | ||
disableBeautification: false, | ||
/* | ||
@@ -24,2 +24,8 @@ * Optional, default is false. Binance's API returns objects with lots of one letter keys. By | ||
*/ | ||
handleDrift: false | ||
/* Optional, default is false. If turned on, the library will attempt to handle any drift of | ||
* your clock on it's own. If a request fails due to drift, it'll attempt a fix by requesting | ||
* binance's server time, calculating the difference with your own clock, and then reattempting | ||
* the request. | ||
*/ | ||
}); | ||
@@ -566,3 +572,19 @@ | ||
# Timestamp errors | ||
Most can be resolved by adjusting your `recvWindow` a bit larger, but if your clock is constantly | ||
or intermittently going out of sync with the server, the library is capable of calculating the | ||
drift and adjusting the timestamps. You have some options. The first is to add the `handleDrift` | ||
option to the constructor, setting it to `true`. In this case, if your clock is ahead of the | ||
server's, or falls behind and is outside the `recvWindow`, and a request fails, the library will | ||
calculate the drift of your clock and reattempt the request. It will also use the drift value to | ||
adjust all subsequent calls. This may add more time to the initial requests that fail, and could | ||
potentially affect highly time sensitive trades. The alternative is to use the | ||
`startTimeSync(interval_in_ms)` and `endTimeSync` functions. The former will begin an interval, | ||
and each time it's called the drift will be calculated and used on all subsequent requests. The | ||
default interval is 5 minutes, and it should be specified in milliseconds. The latter will clear | ||
the interval. You may also calculate the drift manually by calling `calculateDrift()`. The | ||
resulting value will be stored internally and used on all subsequent calls. | ||
# License | ||
[MIT](LICENSE) |
262433
1235
587