kraken-api
Advanced tools
Comparing version 0.1.7 to 1.0.0
244
kraken.js
@@ -1,22 +0,77 @@ | ||
var request = require('request'); | ||
var crypto = require('crypto'); | ||
var querystring = require('querystring'); | ||
const got = require('got'); | ||
const crypto = require('crypto'); | ||
const qs = require('qs'); | ||
// Public/Private method names | ||
const methods = { | ||
public : [ 'Time', 'Assets', 'AssetPairs', 'Ticker', 'Depth', 'Trades', 'Spread', 'OHLC' ], | ||
private : [ 'Balance', 'TradeBalance', 'OpenOrders', 'ClosedOrders', 'QueryOrders', 'TradesHistory', 'QueryTrades', 'OpenPositions', 'Ledgers', 'QueryLedgers', 'TradeVolume', 'AddOrder', 'CancelOrder', 'DepositMethods', 'DepositAddresses', 'DepositStatus', 'WithdrawInfo', 'Withdraw', 'WithdrawStatus', 'WithdrawCancel' ], | ||
}; | ||
// Default options | ||
const defaults = { | ||
url : 'https://api.kraken.com', | ||
version : 0, | ||
timeout : 5000, | ||
}; | ||
// Create a signature for a request | ||
const getMessageSignature = (path, request, secret, nonce) => { | ||
const message = qs.stringify(request); | ||
const secret_buffer = new Buffer(secret, 'base64'); | ||
const hash = new crypto.createHash('sha256'); | ||
const hmac = new crypto.createHmac('sha512', secret_buffer); | ||
const hash_digest = hash.update(nonce + message).digest('binary'); | ||
const hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64'); | ||
return hmac_digest; | ||
}; | ||
// Send an API request | ||
const rawRequest = async (url, headers, data, timeout) => { | ||
// Set custom User-Agent string | ||
headers['User-Agent'] = 'Kraken Javascript API Client'; | ||
const options = { headers, timeout }; | ||
Object.assign(options, { | ||
method : 'POST', | ||
body : qs.stringify(data), | ||
}); | ||
const { body } = await got(url, options); | ||
const response = JSON.parse(body); | ||
if(response.error && response.error.length) { | ||
const error = response.error | ||
.filter((e) => e.startsWith('E')) | ||
.map((e) => e.substr(1)); | ||
if(!error.length) { | ||
throw new Error("Kraken API returned an unknown error"); | ||
} | ||
throw new Error(error.join(', ')); | ||
} | ||
return response; | ||
}; | ||
/** | ||
* KrakenClient connects to the Kraken.com API | ||
* @param {String} key API Key | ||
* @param {String} secret API Secret | ||
* @param {String} [otp] Two-factor password (optional) (also, doesn't work) | ||
* @param {String} key API Key | ||
* @param {String} secret API Secret | ||
* @param {String|Object} [options={}] Additional options. If a string is passed, will default to just setting `options.otp`. | ||
* @param {String} [options.otp] Two-factor password (optional) (also, doesn't work) | ||
* @param {Number} [options.timeout] Maximum timeout (in milliseconds) for all API-calls (passed to `request`) | ||
*/ | ||
function KrakenClient(key, secret, otp) { | ||
var self = this; | ||
class KrakenClient { | ||
constructor(key, secret, options) { | ||
// Allow passing the OTP as the third argument for backwards compatibility | ||
if(typeof options === 'string') { | ||
options = { otp : options }; | ||
} | ||
var config = { | ||
url: 'https://api.kraken.com', | ||
version: '0', | ||
key: key, | ||
secret: secret, | ||
otp: otp, | ||
timeoutMS: 5000 | ||
}; | ||
this.config = Object.assign({ key, secret }, defaults, options); | ||
} | ||
@@ -30,13 +85,15 @@ /** | ||
*/ | ||
function api(method, params, callback) { | ||
var methods = { | ||
public: ['Time', 'Assets', 'AssetPairs', 'Ticker', 'Depth', 'Trades', 'Spread', 'OHLC'], | ||
private: ['Balance', 'TradeBalance', 'OpenOrders', 'ClosedOrders', 'QueryOrders', 'TradesHistory', 'QueryTrades', 'OpenPositions', 'Ledgers', 'QueryLedgers', 'TradeVolume', 'AddOrder', 'CancelOrder', 'DepositMethods', 'DepositAddresses', 'DepositStatus', 'WithdrawInfo', 'Withdraw', 'WithdrawStatus', 'WithdrawCancel'] | ||
}; | ||
if(methods.public.indexOf(method) !== -1) { | ||
return publicMethod(method, params, callback); | ||
api(method, params, callback) { | ||
// Default params to empty object | ||
if(typeof params === 'function') { | ||
callback = params; | ||
params = {}; | ||
} | ||
else if(methods.private.indexOf(method) !== -1) { | ||
return privateMethod(method, params, callback); | ||
if(methods.public.includes(method)) { | ||
return this.publicMethod(method, params, callback); | ||
} | ||
else if(methods.private.includes(method)) { | ||
return this.privateMethod(method, params, callback); | ||
} | ||
else { | ||
@@ -54,9 +111,22 @@ throw new Error(method + ' is not a valid API method.'); | ||
*/ | ||
function publicMethod(method, params, callback) { | ||
publicMethod(method, params, callback) { | ||
params = params || {}; | ||
var path = '/' + config.version + '/public/' + method; | ||
var url = config.url + path; | ||
// Default params to empty object | ||
if(typeof params === 'function') { | ||
callback = params; | ||
params = {}; | ||
} | ||
return rawRequest(url, {}, params, callback); | ||
const path = '/' + this.config.version + '/public/' + method; | ||
const url = this.config.url + path; | ||
const response = rawRequest(url, {}, params, this.config.timeout); | ||
if(typeof callback === 'function') { | ||
response | ||
.then((result) => callback(null, result)) | ||
.catch((error) => callback(error, null)); | ||
} | ||
return response; | ||
} | ||
@@ -71,104 +141,46 @@ | ||
*/ | ||
function privateMethod(method, params, callback) { | ||
privateMethod(method, params, callback) { | ||
params = params || {}; | ||
var path = '/' + config.version + '/private/' + method; | ||
var url = config.url + path; | ||
// Default params to empty object | ||
if(typeof params === 'function') { | ||
callback = params; | ||
params = {}; | ||
} | ||
params.nonce = new Date() * 1000; // spoof microsecond | ||
const path = '/' + this.config.version + '/private/' + method; | ||
const url = this.config.url + path; | ||
if(config.otp !== undefined) { | ||
params.otp = config.otp; | ||
if(!params.nonce) { | ||
params.nonce = new Date() * 1000; // spoof microsecond | ||
} | ||
var signature = getMessageSignature(path, params, params.nonce); | ||
if(this.config.otp !== undefined) { | ||
params.otp = this.config.otp; | ||
} | ||
var headers = { | ||
'API-Key': config.key, | ||
'API-Sign': signature | ||
}; | ||
const signature = getMessageSignature( | ||
path, | ||
params, | ||
this.config.secret, | ||
params.nonce | ||
); | ||
return rawRequest(url, headers, params, callback); | ||
} | ||
/** | ||
* This method returns a signature for a request as a Base64-encoded string | ||
* @param {String} path The relative URL path for the request | ||
* @param {Object} request The POST body | ||
* @param {Integer} nonce A unique, incrementing integer | ||
* @return {String} The request signature | ||
*/ | ||
function getMessageSignature(path, request, nonce) { | ||
var message = querystring.stringify(request); | ||
var secret = new Buffer(config.secret, 'base64'); | ||
var hash = new crypto.createHash('sha256'); | ||
var hmac = new crypto.createHmac('sha512', secret); | ||
var hash_digest = hash.update(nonce + message).digest('binary'); | ||
var hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64'); | ||
return hmac_digest; | ||
} | ||
/** | ||
* This method sends the actual HTTP request | ||
* @param {String} url The URL to make the request | ||
* @param {Object} headers Request headers | ||
* @param {Object} params POST body | ||
* @param {Function} callback A callback function to call when the request is complete | ||
* @return {Object} The request object | ||
*/ | ||
function rawRequest(url, headers, params, callback) { | ||
// Set custom User-Agent string | ||
headers['User-Agent'] = 'Kraken Javascript API Client'; | ||
var options = { | ||
url: url, | ||
method: 'POST', | ||
headers: headers, | ||
form: params, | ||
timeout: config.timeoutMS | ||
const headers = { | ||
'API-Key' : this.config.key, | ||
'API-Sign' : signature, | ||
}; | ||
var req = request.post(options, function(error, response, body) { | ||
if(typeof callback === 'function') { | ||
var data; | ||
const response = rawRequest(url, headers, params, this.config.timeout); | ||
if(error) { | ||
return callback.call(self, new Error('Error in server response: ' + JSON.stringify(error)), null); | ||
} | ||
if(typeof callback === 'function') { | ||
response | ||
.then((result) => callback(null, result)) | ||
.catch((error) => callback(error, null)); | ||
} | ||
try { | ||
data = JSON.parse(body); | ||
} | ||
catch(e) { | ||
return callback.call(self, new Error('Could not understand response from server: ' + body), null); | ||
} | ||
//If any errors occured, Kraken will give back an array with error strings under | ||
//the key "error". We should then propagate back the error message as a proper error. | ||
if(data.error && data.error.length) { | ||
var krakenError = null; | ||
data.error.forEach(function(element) { | ||
if (element.charAt(0) === "E") { | ||
krakenError = element.substr(1); | ||
return false; | ||
} | ||
}); | ||
if (krakenError) { | ||
return callback.call(self, new Error('Kraken API returned error: ' + krakenError), null); | ||
} | ||
} | ||
else { | ||
return callback.call(self, null, data); | ||
} | ||
} | ||
}); | ||
return req; | ||
return response; | ||
} | ||
self.api = api; | ||
self.publicMethod = publicMethod; | ||
self.privateMethod = privateMethod; | ||
} | ||
module.exports = KrakenClient; |
{ | ||
"name": "kraken-api", | ||
"version": "0.1.7", | ||
"version": "1.0.0", | ||
"description": "kraken.com API client library for NodeJS", | ||
@@ -12,8 +12,7 @@ "keywords": [ | ||
"author": "Robert Myers (https://github.com/nothingisdead)", | ||
"contributors": [ | ||
], | ||
"contributors": [], | ||
"license": "MIT", | ||
"dependencies": { | ||
"querystring": ">=0.2.0", | ||
"request": ">=2.27.0" | ||
"got": "^7.1.0", | ||
"qs": ">=6.4.0" | ||
}, | ||
@@ -20,0 +19,0 @@ "repository": { |
@@ -6,40 +6,33 @@ Node Kraken | ||
This is an asynchronous node js client for the kraken.com API. | ||
This is an asynchronous node js client for the kraken.com API. It exposes all the API methods found here: https://www.kraken.com/help/api through the ```api``` method: | ||
It exposes all the API methods found here: https://www.kraken.com/help/api through the 'api' method: | ||
Example Usage: | ||
```javascript | ||
var KrakenClient = require('kraken-api'); | ||
var kraken = new KrakenClient('api_key', 'api_secret'); | ||
const key = '...'; // API Key | ||
const secret = '...'; // API Private Key | ||
const KrakenClient = require('kraken-api'); | ||
const kraken = new KrakenClient(key, secret); | ||
// Display user's balance | ||
kraken.api('Balance', null, function(error, data) { | ||
if(error) { | ||
console.log(error); | ||
} | ||
else { | ||
console.log(data.result); | ||
} | ||
}); | ||
(async () => { | ||
// Display user's balance | ||
console.log(await kraken.api('Balance')); | ||
// Get Ticker Info | ||
kraken.api('Ticker', {"pair": 'XBTCXLTC'}, function(error, data) { | ||
if(error) { | ||
console.log(error); | ||
} | ||
else { | ||
console.log(data.result); | ||
} | ||
}); | ||
// Get Ticker Info | ||
console.log(await kraken.api('Ticker', { pair : 'XXBTZUSD' })); | ||
})(); | ||
``` | ||
**Update:** | ||
**Updates:** | ||
As of version 0.1.0, the callback passed to the *api* function conforms to the Node.js standard of | ||
As of version 1.0.0: | ||
- All methods return a promise. | ||
- The second argument (parameters) can be omitted. | ||
- The third argument to the constructor can be an object (configuration) or a string (OTP), for backwards compatibility. | ||
As of version 0.1.0, the callback passed to the ```api``` function conforms to the Node.js standard of | ||
```javascript | ||
function(error, data) { | ||
// ... | ||
// ... | ||
} | ||
@@ -52,7 +45,4 @@ ``` | ||
I used the example php implementation at https://github.com/payward/kraken-api-client and the python implementation at https://github.com/veox/krakenex as references. | ||
I used the example php implementation at https://github.com/payward/kraken-api-client and the python implementation at https://github.com/veox/python3-krakenex as references. | ||
Feeling generous? Send me a fraction of a bitcoin! | ||
12X8GyUpfYxEP7sh1QaU4ngWYpzXJByQn5 | ||
BTC donation address: 12X8GyUpfYxEP7sh1QaU4ngWYpzXJByQn5 |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
8665
152
1
47
1
+ Addedgot@^7.1.0
+ Addedqs@>=6.4.0
+ Addedcall-bind-apply-helpers@1.0.1(transitive)
+ Addedcall-bound@1.0.3(transitive)
+ Addeddecompress-response@3.3.0(transitive)
+ Addeddunder-proto@1.0.1(transitive)
+ Addedduplexer3@0.1.5(transitive)
+ Addedes-define-property@1.0.1(transitive)
+ Addedes-errors@1.3.0(transitive)
+ Addedes-object-atoms@1.1.1(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-intrinsic@1.2.7(transitive)
+ Addedget-proto@1.0.1(transitive)
+ Addedget-stream@3.0.0(transitive)
+ Addedgopd@1.2.0(transitive)
+ Addedgot@7.1.0(transitive)
+ Addedhas-symbol-support-x@1.4.2(transitive)
+ Addedhas-symbols@1.1.0(transitive)
+ Addedhas-to-string-tag-x@1.4.1(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedis-object@1.0.2(transitive)
+ Addedis-plain-obj@1.1.0(transitive)
+ Addedis-retry-allowed@1.2.0(transitive)
+ Addedis-stream@1.1.0(transitive)
+ Addedisurl@1.0.0(transitive)
+ Addedlowercase-keys@1.0.1(transitive)
+ Addedmath-intrinsics@1.1.0(transitive)
+ Addedmimic-response@1.0.1(transitive)
+ Addedobject-inspect@1.13.4(transitive)
+ Addedp-cancelable@0.3.0(transitive)
+ Addedp-finally@1.0.0(transitive)
+ Addedp-timeout@1.2.1(transitive)
+ Addedprepend-http@1.0.4(transitive)
+ Addedqs@6.14.0(transitive)
+ Addedside-channel@1.1.0(transitive)
+ Addedside-channel-list@1.0.0(transitive)
+ Addedside-channel-map@1.0.1(transitive)
+ Addedside-channel-weakmap@1.0.2(transitive)
+ Addedtimed-out@4.0.1(transitive)
+ Addedurl-parse-lax@1.0.0(transitive)
+ Addedurl-to-options@1.0.1(transitive)
- Removedquerystring@>=0.2.0
- Removedrequest@>=2.27.0
- Removedajv@6.12.6(transitive)
- Removedasn1@0.2.6(transitive)
- Removedassert-plus@1.0.0(transitive)
- Removedasynckit@0.4.0(transitive)
- Removedaws-sign2@0.7.0(transitive)
- Removedaws4@1.13.2(transitive)
- Removedbcrypt-pbkdf@1.0.2(transitive)
- Removedcaseless@0.12.0(transitive)
- Removedcombined-stream@1.0.8(transitive)
- Removedcore-util-is@1.0.2(transitive)
- Removeddashdash@1.14.1(transitive)
- Removeddelayed-stream@1.0.0(transitive)
- Removedecc-jsbn@0.1.2(transitive)
- Removedextend@3.0.2(transitive)
- Removedextsprintf@1.3.0(transitive)
- Removedfast-deep-equal@3.1.3(transitive)
- Removedfast-json-stable-stringify@2.1.0(transitive)
- Removedforever-agent@0.6.1(transitive)
- Removedform-data@2.3.3(transitive)
- Removedgetpass@0.1.7(transitive)
- Removedhar-schema@2.0.0(transitive)
- Removedhar-validator@5.1.5(transitive)
- Removedhttp-signature@1.2.0(transitive)
- Removedis-typedarray@1.0.0(transitive)
- Removedisstream@0.1.2(transitive)
- Removedjsbn@0.1.1(transitive)
- Removedjson-schema@0.4.0(transitive)
- Removedjson-schema-traverse@0.4.1(transitive)
- Removedjson-stringify-safe@5.0.1(transitive)
- Removedjsprim@1.4.2(transitive)
- Removedmime-db@1.52.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedoauth-sign@0.9.0(transitive)
- Removedperformance-now@2.1.0(transitive)
- Removedpsl@1.15.0(transitive)
- Removedpunycode@2.3.1(transitive)
- Removedqs@6.5.3(transitive)
- Removedquerystring@0.2.1(transitive)
- Removedrequest@2.88.2(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsshpk@1.18.0(transitive)
- Removedtough-cookie@2.5.0(transitive)
- Removedtunnel-agent@0.6.0(transitive)
- Removedtweetnacl@0.14.5(transitive)
- Removeduri-js@4.4.1(transitive)
- Removeduuid@3.4.0(transitive)
- Removedverror@1.10.0(transitive)