UNPKG

node-bitstamp

Version:

bitstamp rest and websocket v1 and v2 api client

488 lines (364 loc) 13.1 kB
"use strict"; const Promise = require("bluebird"); const request = require("request"); const querystring = require("querystring"); const debug = require("debug")("node-bitstamp:client"); const Signature = require("./Signature.js"); // 600 requests max per 10 minutes const MAX_CALL_WINDOW = 60 * 1000; // 10 minutes const MAX_CALLS_PER_WINDOW = 60; const HTTP_METHOD = { GET: "GET", POST: "POST" }; class Bitstamp { constructor(opts = {}, base = "https://www.bitstamp.net/api/v2", old = "https://www.bitstamp.net/api"){ this.base = base; this.old = old; this.totalCallsMade = 0; this.callsInLastMinute = 0; this.lastCall = null; this._intv = setInterval(() => { this.callsInLastMinute = 0; }, MAX_CALL_WINDOW); const { key, secret, clientId, timeout, rateLimit } = opts; this.timeout = timeout || 5000; this.rateLimit = typeof rateLimit === "undefined" ? true : rateLimit; this.signature = new Signature(key, secret, clientId); } _getUrl(endpoint = "", old = false){ return `${old ? this.old : this.base}/${endpoint}`; } _getOptions(endpoint = "", body = null, method = "GET", signed = false, old = false){ const options = { method, url: this._getUrl(endpoint, old), headers: { "content-type": "application/x-www-form-urlencoded", "accept": "application/json" }, timeout: this.timeout }; if(body != null){ if(!signed){ body = querystring.stringify(body); } else { body = this.signature.signBody(body); } options.body = body; } debug("calling", options.url, ".."); return options; } call(endpoint, method = "GET", body = null, signed = false, old = false){ return new Promise((resolve, reject) => { this.totalCallsMade++; this.callsInLastMinute++; if(this.callsInLastMinute >= MAX_CALLS_PER_WINDOW && this.rateLimit){ return reject(new Error(`Must not exceed ${MAX_CALLS_PER_WINDOW} calls per ${MAX_CALL_WINDOW} ms.`)); } this.lastCall = Date.now(); const options = this._getOptions(endpoint, body, method, signed, old); request(options, (error, response, body) => { // The HTTP request did not succeed. // e.g. ESOCKETTIMEDOUT if (error){ return reject(error); } // The HTTP request worked but returned an error code. // e.g. 401 unauthorized if (response.statusCode < 200 || response.statusCode > 299) { if(!body){ return reject(new Error("No body can be provided.")); } return reject(new Error("With body: " + body)); } debug("result", options.url, response.statusCode); try { body = JSON.parse(body); } catch (error) { return reject(error); } // There was an API request error. // e.g. Insufficient funds in case of withdrawal. if (body.status === "error") { return reject(body.reason); } // Typically this happens when the request's statuscode // is not 2xx but we check here just in case. if (body.error) { return reject(body.error); } resolve({ status: response.statusCode, headers: response.headers, body }); }); }); } close(){ if(this._intv){ clearInterval(this._intv); } } _resolveEP(endpoint, currency = null){ if(!currency){ return `${endpoint}/`; } else { return `${endpoint}/${currency}/`; } } getStats(){ return { lastCall: this.lastCall, callsInLastMinute: this.callsInLastMinute, totalCallsMade: this.totalCallsMade }; } /* API */ ticker(currency = null){ const ep = "ticker"; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.GET, null, false); } tickerHour(currency = null){ const ep = "ticker_hour"; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.GET, null, false); } ohlcData(currency = null, start = null, end = null, step = 60, limit = 100){ const query = {step, limit}; if (start) { query.start = start; } if (end) { query.end = end; } const ep = "ohlc"; return this.call(this._resolveEP(ep, currency) + `?${querystring.stringify(query)}`, HTTP_METHOD.GET, null, false); } orderBook(currency = null){ const ep = "order_book"; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.GET, null, false); } transactions(currency = null, time = "hour"){ const ep = "transactions"; return this.call(this._resolveEP(ep, currency) + `?${querystring.stringify({time})}`, HTTP_METHOD.GET, null, false); } conversionRate(){ const ep = "eur_usd"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.GET, null, false, true); } /* PRIVATE */ balance(currency = null){ const ep = "balance"; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, {}, true); } userTransaction(currency = null, opts = {}){ const ep = "user_transactions"; //opts // {offset, limit, sort} return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, opts || {}, true); } cryptoTransactions(currency = null, opts = {}){ const ep = "crypto-transactions"; //opts // {offset, limit, sort} return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, opts || {}, true); } openOrders(currency = null){ const ep = "open_orders"; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, {}, true); } openOrdersAll(){ const ep = "open_orders"; return this.call(this._resolveEP(ep, "all/"), HTTP_METHOD.POST, {}, true); } orderStatus(id){ const ep = "order_status"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {id}, true); } cancelOrder(id){ const ep = "cancel_order"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {id}, true); } cancelOrdersAll(){ const ep = "cancel_all_orders"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true, true); } buyLimitOrder(amount, price, currency = null, limit_price = null, daily_order = null){ const ep = "buy"; const body = { amount, price, limit_price, daily_order }; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, body, true); } buyMarketOrder(amount, currency = null){ const ep = "buy/market"; const body = { amount }; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, body, true); } buyInstantOrder(amount , currency = null){ const ep = "buy/instant"; const body = { amount } return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, body, true ); } sellInstantOrder( amount, currency =null){ const ep = "sell/instant"; const body = { amount } return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, body, true ); } sellLimitOrder(amount, price, currency = null, limit_price = null, daily_order = null){ const ep = "sell"; const body = { amount, price, limit_price, daily_order }; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, body, true); } sellMarketOrder(amount, currency = null){ const ep = "sell/market"; const body = { amount }; return this.call(this._resolveEP(ep, currency), HTTP_METHOD.POST, body, true); } /* OTHER */ withDrawalRequests(timedelta = null){ const ep = "withdrawal_requests"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {timedelta}, true, true); } bitcoinWithdrawal(amount, address, instant = 0){ const ep = "bitcoin_withdrawal"; const body = { amount, address, instant }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true, true); } litecoinWithdrawal(amount, address){ const ep = "ltc_withdrawal"; const body = { amount, address }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true); } ethereumWithdrawal(amount, address){ const ep = "eth_withdrawal"; const body = { amount, address }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true); } rippleWithdrawal(amount, address, currency){ const ep = "ripple_withdrawal"; const body = { amount, address, currency }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true, true); } xrpWithdrawal(amount, address, destination_tag = null){ const ep = "xrp_withdrawal"; const body = { amount, address, destination_tag }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true); } bchWithdrawal(amount, address){ const ep = "bch_withdrawal"; const body = { amount, address }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true); } ethereumDepositAdress(){ const ep = "eth_address"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true); } xrpDepositAdress(){ const ep = "xrp_address"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true); } litecoinDepositAdress(){ const ep = "ltc_address"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true); } bitcoinDepositAdress(){ const ep = "bitcoin_deposit_address"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true, true); } bchDepositAdress(){ const ep = "bch_address"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true); } rippleDepositAdress(){ const ep = "ripple_address"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true, true); } unconfirmedBitcoinDeposits(){ const ep = "unconfirmed_btc"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {}, true, true); } transferSubToMain(amount, currency, subAccount = null){ const ep = "transfer-to-main"; const body = { amount, currency, subAccount }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true); } transferMainToSub(amount, currency, subAccount = null){ const ep = "transfer-from-main"; const body = { amount, currency, subAccount }; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true); } openBankWithdrawal(body = {}){ const ep = "withdrawal/open/"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, body, true); } bankWithdrawalStatus(id){ const ep = "withdrawal/status/"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {id}, true); } cancelBankWithdrawal(id){ const ep = "withdrawal/cancel/"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {id}, true); } newLiquidationAddress(liquidation_currency){ const ep = "liquidation_address/new"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {liquidation_currency}, true); } liquidationAddressInfo(address){ const ep = "liquidation_address/new"; return this.call(this._resolveEP(ep, null), HTTP_METHOD.POST, {address}, true); } } module.exports = Bitstamp;