UNPKG

@proton/ccxt

Version:

A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges

1,185 lines (1,183 loc) 97.3 kB
'use strict'; var whitebit$1 = require('./abstract/whitebit.js'); var errors = require('./base/errors.js'); var Precise = require('./base/Precise.js'); var number = require('./base/functions/number.js'); var sha512 = require('./static_dependencies/noble-hashes/sha512.js'); // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- class whitebit extends whitebit$1 { describe() { return this.deepExtend(super.describe(), { 'id': 'whitebit', 'name': 'WhiteBit', 'version': 'v4', 'countries': ['EE'], 'rateLimit': 500, 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': true, 'swap': false, 'future': false, 'option': false, 'borrowMargin': false, 'cancelAllOrders': false, 'cancelOrder': true, 'cancelOrders': false, 'createOrder': true, 'createStopLimitOrder': true, 'createStopMarketOrder': true, 'createStopOrder': true, 'editOrder': false, 'fetchBalance': true, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchClosedOrders': true, 'fetchCurrencies': true, 'fetchDeposit': true, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchDepositWithdrawFee': 'emulated', 'fetchDepositWithdrawFees': true, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOrderBook': true, 'fetchOrderTrades': true, 'fetchPositionMode': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransactionFees': true, 'repayMargin': false, 'setLeverage': true, 'transfer': true, 'withdraw': true, }, 'timeframes': { '1m': '1m', '3m': '3m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '2h': '2h', '4h': '4h', '6h': '6h', '8h': '8h', '12h': '12h', '1d': '1d', '3d': '3d', '1w': '1w', '1M': '1M', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/66732963-8eb7dd00-ee66-11e9-849b-10d9282bb9e0.jpg', 'api': { 'v1': { 'public': 'https://whitebit.com/api/v1/public', 'private': 'https://whitebit.com/api/v1', }, 'v2': { 'public': 'https://whitebit.com/api/v2/public', }, 'v4': { 'public': 'https://whitebit.com/api/v4/public', 'private': 'https://whitebit.com/api/v4', }, }, 'www': 'https://www.whitebit.com', 'doc': 'https://github.com/whitebit-exchange/api-docs', 'fees': 'https://whitebit.com/fee-schedule', 'referral': 'https://whitebit.com/referral/d9bdf40e-28f2-4b52-b2f9-cd1415d82963', }, 'api': { 'web': { 'get': [ 'v1/healthcheck', ], }, 'v1': { 'public': { 'get': [ 'markets', 'tickers', 'ticker', 'symbols', 'depth/result', 'history', 'kline', ], }, 'private': { 'post': [ 'account/balance', 'order/new', 'order/cancel', 'orders', 'account/order_history', 'account/executed_history', 'account/executed_history/all', 'account/order', ], }, }, 'v2': { 'public': { 'get': [ 'markets', 'ticker', 'assets', 'fee', 'depth/{market}', 'trades/{market}', ], }, }, 'v4': { 'public': { 'get': [ 'assets', 'collateral/markets', 'fee', 'orderbook/{market}', 'ticker', 'trades/{market}', 'time', 'ping', 'markets', ], }, 'private': { 'post': [ 'collateral-account/balance', 'collateral-account/positions/history', 'collateral-account/leverage', 'collateral-account/positions/open', 'collateral-account/summary', 'main-account/address', 'main-account/balance', 'main-account/create-new-address', 'main-account/codes', 'main-account/codes/apply', 'main-account/codes/my', 'main-account/codes/history', 'main-account/fiat-deposit-url', 'main-account/history', 'main-account/withdraw', 'main-account/withdraw-pay', 'main-account/transfer', 'trade-account/balance', 'trade-account/executed-history', 'trade-account/order', 'trade-account/order/history', 'order/collateral/limit', 'order/collateral/market', 'order/collateral/trigger_market', 'order/new', 'order/market', 'order/stock_market', 'order/stop_limit', 'order/stop_market', 'order/cancel', 'orders', 'profile/websocket_token', ], }, }, }, 'fees': { 'trading': { 'tierBased': false, 'percentage': true, 'taker': this.parseNumber('0.001'), 'maker': this.parseNumber('0.001'), }, }, 'options': { 'fiatCurrencies': ['EUR', 'USD', 'RUB', 'UAH'], 'fetchBalance': { 'account': 'spot', }, 'accountsByType': { 'main': 'main', 'spot': 'spot', 'margin': 'collateral', 'trade': 'spot', }, 'networksById': { 'BEP20': 'BSC', }, 'defaultType': 'spot', 'brokerId': 'ccxt', }, 'precisionMode': number.TICK_SIZE, 'exceptions': { 'exact': { 'Unauthorized request.': errors.AuthenticationError, 'The market format is invalid.': errors.BadSymbol, 'Market is not available': errors.BadSymbol, 'Invalid payload.': errors.BadRequest, 'Amount must be greater than 0': errors.InvalidOrder, 'Not enough balance.': errors.InsufficientFunds, 'The order id field is required.': errors.InvalidOrder, 'Not enough balance': errors.InsufficientFunds, 'This action is unauthorized.': errors.PermissionDenied, 'This API Key is not authorized to perform this action.': errors.PermissionDenied, 'Unexecuted order was not found.': errors.OrderNotFound, 'The selected from is invalid.': errors.BadRequest, '503': errors.ExchangeNotAvailable, '422': errors.OrderNotFound, // {"response":null,"status":422,"errors":{"orderId":["Finished order id 1295772653 not found on your account"]},"notification":null,"warning":"Finished order id 1295772653 not found on your account","_token":null} }, 'broad': { 'Given amount is less than min amount': errors.InvalidOrder, 'Total is less than': errors.InvalidOrder, 'fee must be no less than': errors.InvalidOrder, 'Enable your key in API settings': errors.PermissionDenied, 'You don\'t have such amount for transfer': errors.InsufficientFunds, // {"code":3,"message":"Inner validation failed","errors":{"amount":["You don't have such amount for transfer (available 0.44523433, in amount: 2)"]}} }, }, }); } async fetchMarkets(params = {}) { /** * @method * @name whitebit#fetchMarkets * @description retrieves data on all markets for whitebit * @see https://whitebit-exchange.github.io/api-docs/docs/Public/http-v4#market-info * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const markets = await this.v4PublicGetMarkets(); // // [ // { // "name": "SON_USD", // Market pair name // "stock": "SON", // Ticker of stock currency // "money": "USD", // Ticker of money currency // "stockPrec": "3", // Stock currency precision // "moneyPrec": "2", // Precision of money currency // "feePrec": "4", // Fee precision // "makerFee": "0.001", // Default maker fee ratio // "takerFee": "0.001", // Default taker fee ratio // "minAmount": "0.001", // Minimal amount of stock to trade // "minTotal": "0.001", // Minimal amount of money to trade // "tradesEnabled": true, // Is trading enabled // "isCollateral": true, // Is margin trading enabled // "type": "spot" // Market type. Possible values: "spot", "futures" // }, // { // ... // } // ] // const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; const id = this.safeString(market, 'name'); const baseId = this.safeString(market, 'stock'); let quoteId = this.safeString(market, 'money'); quoteId = (quoteId === 'PERP') ? 'USDT' : quoteId; const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const active = this.safeValue(market, 'tradesEnabled'); const isCollateral = this.safeValue(market, 'isCollateral'); const typeId = this.safeString(market, 'type'); let type = undefined; let settle = undefined; let settleId = undefined; let symbol = base + '/' + quote; const swap = typeId === 'futures'; const margin = isCollateral && !swap; let contract = false; const amountPrecision = this.parseNumber(this.parsePrecision(this.safeString(market, 'stockPrec'))); const contractSize = amountPrecision; let linear = undefined; let inverse = undefined; if (swap) { settleId = quoteId; settle = this.safeCurrencyCode(settleId); symbol = symbol + ':' + settle; type = 'swap'; contract = true; linear = true; inverse = false; } else { type = 'spot'; } const entry = { 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': type, 'spot': !swap, 'margin': margin, 'swap': swap, 'future': false, 'option': false, 'active': active, 'contract': contract, 'linear': linear, 'inverse': inverse, 'taker': this.safeNumber(market, 'makerFee'), 'maker': this.safeNumber(market, 'takerFee'), 'contractSize': contractSize, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': amountPrecision, 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'moneyPrec'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(market, 'minAmount'), 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber(market, 'minTotal'), 'max': undefined, }, }, 'info': market, }; result.push(entry); } return result; } async fetchCurrencies(params = {}) { /** * @method * @name whitebit#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} an associative dictionary of currencies */ const response = await this.v4PublicGetAssets(params); // // "BTC": { // "name": "Bitcoin", // "unified_cryptoasset_id": 1, // "can_withdraw": true, // "can_deposit": true, // "min_withdraw": "0.001", // "max_withdraw": "2", // "maker_fee": "0.1", // "taker_fee": "0.1", // "min_deposit": "0.0001", // "max_deposit": "0", // }, // const ids = Object.keys(response); const result = {}; for (let i = 0; i < ids.length; i++) { const id = ids[i]; const currency = response[id]; // breaks down in Python due to utf8 encoding issues on the exchange side // const name = this.safeString (currency, 'name'); const canDeposit = this.safeValue(currency, 'can_deposit', true); const canWithdraw = this.safeValue(currency, 'can_withdraw', true); const active = canDeposit && canWithdraw; const code = this.safeCurrencyCode(id); result[code] = { 'id': id, 'code': code, 'info': currency, 'name': undefined, 'active': active, 'deposit': canDeposit, 'withdraw': canWithdraw, 'fee': undefined, 'precision': undefined, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': this.safeNumber(currency, 'min_withdraw'), 'max': this.safeNumber(currency, 'max_withdraw'), }, }, }; } return result; } async fetchTransactionFees(codes = undefined, params = {}) { /** * @method * @name whitebit#fetchTransactionFees * @description *DEPRECATED* please use fetchDepositWithdrawFees instead * @param {[string]|undefined} codes not used by fetchTransactionFees () * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} */ await this.loadMarkets(); const response = await this.v4PublicGetFee(params); // // { // "1INCH":{ // "is_depositable":true, // "is_withdrawal":true, // "ticker":"1INCH", // "name":"1inch", // "providers":[ // ], // "withdraw":{ // "max_amount":"0", // "min_amount":"21.5", // "fixed":"17.5", // "flex":null // }, // "deposit":{ // "max_amount":"0", // "min_amount":"19.5", // "fixed":null, // "flex":null // } // }, // {...} // } // const currenciesIds = Object.keys(response); const withdrawFees = {}; const depositFees = {}; for (let i = 0; i < currenciesIds.length; i++) { const currency = currenciesIds[i]; const data = response[currency]; const code = this.safeCurrencyCode(currency); const withdraw = this.safeValue(data, 'withdraw', {}); withdrawFees[code] = this.safeString(withdraw, 'fixed'); const deposit = this.safeValue(data, 'deposit', {}); depositFees[code] = this.safeString(deposit, 'fixed'); } return { 'withdraw': withdrawFees, 'deposit': depositFees, 'info': response, }; } async fetchDepositWithdrawFees(codes = undefined, params = {}) { /** * @method * @name whitebit#fetchDepositWithdrawFees * @description fetch deposit and withdraw fees * @param {[string]|undefined} codes not used by fetchDepositWithdrawFees () * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} */ await this.loadMarkets(); const response = await this.v4PublicGetFee(params); // // { // "1INCH": { // "is_depositable": true, // "is_withdrawal": true, // "ticker": "1INCH", // "name": "1inch", // "providers": [], // "withdraw": { // "max_amount": "0", // "min_amount": "21.5", // "fixed": "17.5", // "flex": null // }, // "deposit": { // "max_amount": "0", // "min_amount": "19.5", // "fixed": null, // "flex": null // } // }, // 'WBT (ERC20)': { // is_depositable: true, // is_withdrawal: true, // ticker: 'WBT', // name: 'WhiteBIT Token', // providers: [], // withdraw: { max_amount: '0', min_amount: '0.7', fixed: '0.253', flex: null }, // deposit: { max_amount: '0', min_amount: '0.35', fixed: null, flex: null } // }, // 'WBT (TRC20)': { // is_depositable: true, // is_withdrawal: true, // ticker: 'WBT', // name: 'WhiteBIT Token', // providers: [], // withdraw: { max_amount: '0', min_amount: '1.5', fixed: '0.075', flex: null }, // deposit: { max_amount: '0', min_amount: '0.75', fixed: null, flex: null } // }, // ... // } // return this.parseDepositWithdrawFees(response, codes); } parseDepositWithdrawFees(response, codes = undefined, currencyIdKey = undefined) { // // { // "1INCH": { // "is_depositable": true, // "is_withdrawal": true, // "ticker": "1INCH", // "name": "1inch", // "providers": [], // "withdraw": { // "max_amount": "0", // "min_amount": "21.5", // "fixed": "17.5", // "flex": null // }, // "deposit": { // "max_amount": "0", // "min_amount": "19.5", // "fixed": null, // "flex": null // } // }, // 'WBT (ERC20)': { // is_depositable: true, // is_withdrawal: true, // ticker: 'WBT', // name: 'WhiteBIT Token', // providers: [], // withdraw: { max_amount: '0', min_amount: '0.7', fixed: '0.253', flex: null }, // deposit: { max_amount: '0', min_amount: '0.35', fixed: null, flex: null } // }, // 'WBT (TRC20)': { // is_depositable: true, // is_withdrawal: true, // ticker: 'WBT', // name: 'WhiteBIT Token', // providers: [], // withdraw: { max_amount: '0', min_amount: '1.5', fixed: '0.075', flex: null }, // deposit: { max_amount: '0', min_amount: '0.75', fixed: null, flex: null } // }, // ... // } // const depositWithdrawFees = {}; codes = this.marketCodes(codes); const currencyIds = Object.keys(response); for (let i = 0; i < currencyIds.length; i++) { const entry = currencyIds[i]; const splitEntry = entry.split(' '); const currencyId = splitEntry[0]; const feeInfo = response[entry]; const code = this.safeCurrencyCode(currencyId); if ((codes === undefined) || (this.inArray(code, codes))) { const depositWithdrawFee = this.safeValue(depositWithdrawFees, code); if (depositWithdrawFee === undefined) { depositWithdrawFees[code] = this.depositWithdrawFee({}); } depositWithdrawFees[code]['info'][entry] = feeInfo; let networkId = this.safeString(splitEntry, 1); const withdraw = this.safeValue(feeInfo, 'withdraw'); const deposit = this.safeValue(feeInfo, 'deposit'); const withdrawFee = this.safeNumber(withdraw, 'fixed'); const depositFee = this.safeNumber(deposit, 'fixed'); const withdrawResult = { 'fee': withdrawFee, 'percentage': (withdrawFee !== undefined) ? false : undefined, }; const depositResult = { 'fee': depositFee, 'percentage': (depositFee !== undefined) ? false : undefined, }; if (networkId !== undefined) { const networkLength = networkId.length; networkId = networkId.slice(1, networkLength - 1); const networkCode = this.networkIdToCode(networkId); depositWithdrawFees[code]['networks'][networkCode] = { 'withdraw': withdrawResult, 'deposit': depositResult, }; } else { depositWithdrawFees[code]['withdraw'] = withdrawResult; depositWithdrawFees[code]['deposit'] = depositResult; } } } const depositWithdrawCodes = Object.keys(depositWithdrawFees); for (let i = 0; i < depositWithdrawCodes.length; i++) { const code = depositWithdrawCodes[i]; const currency = this.currency(code); depositWithdrawFees[code] = this.assignDefaultDepositWithdrawFees(depositWithdrawFees[code], currency); } return depositWithdrawFees; } async fetchTradingFees(params = {}) { /** * @method * @name whitebit#fetchTradingFees * @description fetch the trading fees for multiple markets * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols */ const response = await this.v4PublicGetAssets(params); // // { // '1INCH': { // name: '1inch', // unified_cryptoasset_id: '8104', // can_withdraw: true, // can_deposit: true, // min_withdraw: '33', // max_withdraw: '0', // maker_fee: '0.1', // taker_fee: '0.1', // min_deposit: '30', // max_deposit: '0' // }, // ... // } // const result = {}; for (let i = 0; i < this.symbols.length; i++) { const symbol = this.symbols[i]; const market = this.market(symbol); const fee = this.safeValue(response, market['baseId'], {}); let makerFee = this.safeString(fee, 'maker_fee'); let takerFee = this.safeString(fee, 'taker_fee'); makerFee = Precise["default"].stringDiv(makerFee, '100'); takerFee = Precise["default"].stringDiv(takerFee, '100'); result[symbol] = { 'info': fee, 'symbol': market['symbol'], 'percentage': true, 'tierBased': false, 'maker': this.parseNumber(makerFee), 'taker': this.parseNumber(takerFee), }; } return result; } async fetchTicker(symbol, params = {}) { /** * @method * @name whitebit#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @param {string} symbol unified symbol of the market to fetch the ticker for * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], }; const response = await this.v1PublicGetTicker(this.extend(request, params)); // // { // "success":true, // "message":"", // "result": { // "bid":"0.021979", // "ask":"0.021996", // "open":"0.02182", // "high":"0.022039", // "low":"0.02161", // "last":"0.021987", // "volume":"2810.267", // "deal":"61.383565474", // "change":"0.76", // }, // } // const ticker = this.safeValue(response, 'result', {}); return this.parseTicker(ticker, market); } parseTicker(ticker, market = undefined) { // // FetchTicker (v1) // // { // "bid": "0.021979", // "ask": "0.021996", // "open": "0.02182", // "high": "0.022039", // "low": "0.02161", // "last": "0.021987", // "volume": "2810.267", // "deal": "61.383565474", // "change": "0.76", // } // // FetchTickers (v4) // // "BCH_RUB": { // "base_id": 1831, // "quote_id": 0, // "last_price": "32830.21", // "quote_volume": "1494659.8024096", // "base_volume": "46.1083", // "isFrozen": false, // "change": "2.12" // in percent // } // market = this.safeMarket(undefined, market); const last = this.safeString(ticker, 'last_price'); return this.safeTicker({ 'symbol': market['symbol'], 'timestamp': undefined, 'datetime': undefined, 'high': this.safeString(ticker, 'high'), 'low': this.safeString(ticker, 'low'), 'bid': this.safeString(ticker, 'bid'), 'bidVolume': undefined, 'ask': this.safeString(ticker, 'ask'), 'askVolume': undefined, 'vwap': undefined, 'open': this.safeString(ticker, 'open'), 'close': last, 'last': last, 'previousClose': undefined, 'change': undefined, 'percentage': this.safeString(ticker, 'change'), 'average': undefined, 'baseVolume': this.safeString2(ticker, 'base_volume', 'volume'), 'quoteVolume': this.safeString2(ticker, 'quote_volume', 'deal'), 'info': ticker, }, market); } async fetchTickers(symbols = undefined, params = {}) { /** * @method * @name whitebit#fetchTickers * @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market * @param {[string]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ await this.loadMarkets(); symbols = this.marketSymbols(symbols); const response = await this.v4PublicGetTicker(params); // // "BCH_RUB": { // "base_id":1831, // "quote_id":0, // "last_price":"32830.21", // "quote_volume":"1494659.8024096", // "base_volume":"46.1083", // "isFrozen":false, // "change":"2.12" // }, // const marketIds = Object.keys(response); const result = {}; for (let i = 0; i < marketIds.length; i++) { const marketId = marketIds[i]; const market = this.safeMarket(marketId); const ticker = this.parseTicker(response[marketId], market); const symbol = ticker['symbol']; result[symbol] = ticker; } return this.filterByArray(result, 'symbol', symbols); } async fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name whitebit#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @param {string} symbol unified symbol of the market to fetch the order book for * @param {int|undefined} limit the maximum amount of order book entries to return * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], }; if (limit !== undefined) { request['depth'] = limit; // default = 50, maximum = 100 } const response = await this.v4PublicGetOrderbookMarket(this.extend(request, params)); // // { // "timestamp": 1594391413, // "asks": [ // [ // "9184.41", // "0.773162" // ], // [ ... ] // ], // "bids": [ // [ // "9181.19", // "0.010873" // ], // [ ... ] // ] // } // const timestamp = this.parseNumber(Precise["default"].stringMul(this.safeString(response, 'timestamp'), '1000')); return this.parseOrderBook(response, symbol, timestamp); } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name whitebit#fetchTrades * @description get the list of most recent trades for a particular symbol * @param {string} symbol unified symbol of the market to fetch trades for * @param {int|undefined} since timestamp in ms of the earliest trade to fetch * @param {int|undefined} limit the maximum amount of trades to fetch * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], }; const response = await this.v4PublicGetTradesMarket(this.extend(request, params)); // // [ // { // "tradeID": 158056419, // "price": "9186.13", // "quote_volume": "0.0021", // "base_volume": "9186.13", // "trade_timestamp": 1594391747, // "type": "sell" // }, // ], // return this.parseTrades(response, market, since, limit); } async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) { /** * @method * @name whitebit#fetchMyTrades * @description fetch all trades made by the user * @param {string} symbol unified symbol of the market to fetch trades for * @param {int|undefined} since timestamp in ms of the earliest trade to fetch * @param {int|undefined} limit the maximum amount of trades to fetch * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {[object]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades} */ await this.loadMarkets(); let market = undefined; const request = {}; if (symbol !== undefined) { market = this.market(symbol); request['market'] = market['id']; } const response = await this.v4PrivatePostTradeAccountExecutedHistory(this.extend(request, params)); // // when no symbol is provided // // { // "USDC_USDT":[ // { // "id":"1343815269", // "clientOrderId":"", // "time":"1641051917.532965", // "side":"sell", // "role":"2", // "amount":"9.986", // "price":"0.9995", // "deal":"9.981007", // "fee":"0.009981007", // "orderId":"58166729555" // }, // ] // } // // when a symbol is provided // // [ // { // 'id': 1343815269, // 'clientOrderId': '', // 'time': 1641051917.532965, // 'side': 'sell', // 'role': 2, // 'amount': '9.986', // 'price': '0.9995', // 'deal': '9.981007', // 'fee': '0.009981007', // 'orderId': 58166729555, // }, // ] // if (Array.isArray(response)) { return this.parseTrades(response, market, since, limit); } else { let results = []; const keys = Object.keys(response); for (let i = 0; i < keys.length; i++) { const marketId = keys[i]; const marketNew = this.safeMarket(marketId, undefined, '_'); const rawTrades = this.safeValue(response, marketId, []); const parsed = this.parseTrades(rawTrades, marketNew, since, limit); results = this.arrayConcat(results, parsed); } results = this.sortBy2(results, 'timestamp', 'id'); return this.filterBySinceLimit(results, since, limit, 'timestamp'); } } parseTrade(trade, market = undefined) { // // fetchTradesV4 // // { // "tradeID": 158056419, // "price": "9186.13", // "quote_volume": "0.0021", // "base_volume": "9186.13", // "trade_timestamp": 1594391747, // "type": "sell" // } // // orderTrades (v4Private) // // { // "time": 1593342324.613711, // "fee": "0.00000419198", // "price": "0.00000701", // "amount": "598", // "id": 149156519, // trade id // "dealOrderId": 3134995325, // orderId // "clientOrderId": "customId11", // "role": 2, // 1 = maker, 2 = taker // "deal": "0.00419198" // amount in money // } // // fetchMyTrades // // { // 'id': 1343815269, // 'clientOrderId': '', // 'time': 1641051917.532965, // 'side': 'sell', // 'role': 2, // 'amount': '9.986', // 'price': '0.9995', // 'deal': '9.981007', // 'fee': '0.009981007', // 'orderId': 58166729555, // } // market = this.safeMarket(undefined, market); const timestamp = this.safeTimestamp2(trade, 'time', 'trade_timestamp'); const orderId = this.safeString2(trade, 'dealOrderId', 'orderId'); const cost = this.safeString(trade, 'deal'); const price = this.safeString(trade, 'price'); const amount = this.safeString2(trade, 'amount', 'quote_volume'); const id = this.safeString2(trade, 'id', 'tradeID'); const side = this.safeString2(trade, 'type', 'side'); const symbol = market['symbol']; const role = this.safeInteger(trade, 'role'); let takerOrMaker = undefined; if (role !== undefined) { takerOrMaker = (role === 1) ? 'maker' : 'taker'; } let fee = undefined; const feeCost = this.safeString(trade, 'fee'); if (feeCost !== undefined) { fee = { 'cost': feeCost, 'currency': market['quote'], }; } return this.safeTrade({ 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'id': id, 'order': orderId, 'type': undefined, 'takerOrMaker': takerOrMaker, 'side': side, 'price': price, 'amount': amount, 'cost': cost, 'fee': fee, }, market); } async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { /** * @method * @name whitebit#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @param {string} symbol unified symbol of the market to fetch OHLCV data for * @param {string} timeframe the length of time each candle represents * @param {int|undefined} since timestamp in ms of the earliest candle to fetch * @param {int|undefined} limit the maximum amount of candles to fetch * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {[[int]]} A list of candles ordered as timestamp, open, high, low, close, volume */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], 'interval': this.safeString(this.timeframes, timeframe, timeframe), }; if (since !== undefined) { const maxLimit = 1440; if (limit === undefined) { limit = maxLimit; } limit = Math.min(limit, maxLimit); const start = this.parseToInt(since / 1000); const duration = this.parseTimeframe(timeframe); const end = this.sum(start, duration * limit); request['start'] = start; request['end'] = end; } if (limit !== undefined) { request['limit'] = Math.min(limit, 1440); } const response = await this.v1PublicGetKline(this.extend(request, params)); // // { // "success":true, // "message":"", // "result":[ // [1591488000,"0.025025","0.025025","0.025029","0.025023","6.181","0.154686629"], // [1591488060,"0.025028","0.025033","0.025035","0.025026","8.067","0.201921167"], // [1591488120,"0.025034","0.02505","0.02505","0.025034","20.089","0.503114696"], // ] // } // const result = this.safeValue(response, 'result', []); return this.parseOHLCVs(result, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { // // [ // 1591488000, // "0.025025", // "0.025025", // "0.025029", // "0.025023", // "6.181", // "0.154686629" // ] // return [ this.safeTimestamp(ohlcv, 0), this.safeNumber(ohlcv, 1), this.safeNumber(ohlcv, 3), this.safeNumber(ohlcv, 4), this.safeNumber(ohlcv, 2), this.safeNumber(ohlcv, 5), // volume ]; } async fetchStatus(params = {}) { /** * @method * @name whitebit#fetchStatus * @description the latest known information on the availability of the exchange API * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure} */ const response = await this.v4PublicGetPing(params); // // [ // "pong" // ] // const status = this.safeString(response, 0); return { 'status': (status === 'pong') ? 'ok' : status, 'updated': undefined, 'eta': undefined, 'url': undefined, 'info': response, }; } async fetchTime(params = {}) { /** * @method * @name whitebit#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ const response = await this.v4PublicGetTime(params); // // { // "time":1635467280514 // } // return this.safeInteger(response, 'time'); } async createOrder(symbol, type, side, amount, price = undefined, params = {}) { /** * @method * @name whitebit#createOrder * @description create a trade order * @param {string} symbol unified symbol of the market to create an order in * @param {string} type 'market' or 'limit' * @param {string} side 'buy' or 'sell' * @param {float} amount how much of currency you want to trade in units of base currency * @param {float|undefined} price the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders * @param {object} params extra parameters specific to the whitebit api endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ await this.loadMarkets(); const market = this.market(symbol); const request = { 'market': market['id'], 'side': side, 'amount': this.amountToPrecision(symbol, amount), }; const clientOrderId = this.safeString2(params, 'clOrdId', 'clientOrderId'); if (clientOrderId === undefined) { const brokerId = this.safeString(this.options, 'brokerId'); if (brokerId !== undefined) { request['clientOrderId'] = brokerId + this.uuid16(); } } else { request['clientOrderId'] = clientOrderId; params = this.omit(params, ['clientOrderId']); } const marketType = this.safeString(market, 'type'); const isLimitOrder = type === 'limit'; const isMarketOrder = type === 'market'; const stopPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'activation_price']); const isStopOrder = (stopPrice !== undefined); const postOnly = this.isPostOnly(isMarketOrder, false, params); const [marginMode, query] = this.handleMarginModeAndParams('createOrder', params); if (postOnly) { request['postOnly'] = true; } let method = undefined; if (marginMode !== undefined && marginMode !== 'cross'