UNPKG

sfccxt

Version:

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

1,160 lines (1,146 loc) 159 kB
'use strict'; // --------------------------------------------------------------------------- const Exchange = require ('./base/Exchange'); const { AccountSuspended, BadRequest, BadResponse, NetworkError, NotSupported, DDoSProtection, AuthenticationError, PermissionDenied, ExchangeError, InsufficientFunds, InvalidOrder, InvalidNonce, OrderNotFound, InvalidAddress, RateLimitExceeded, BadSymbol } = require ('./base/errors'); const { TICK_SIZE } = require ('./base/functions/number'); const Precise = require ('./base/Precise'); // --------------------------------------------------------------------------- module.exports = class digifinex extends Exchange { describe () { return this.deepExtend (super.describe (), { 'id': 'digifinex', 'name': 'DigiFinex', 'countries': [ 'SG' ], 'version': 'v3', 'rateLimit': 900, // 300 for posts 'has': { 'CORS': undefined, 'spot': true, 'margin': true, 'swap': true, 'future': false, 'option': false, 'addMargin': false, 'cancelOrder': true, 'cancelOrders': true, 'createOrder': true, 'createPostOnlyOrder': true, 'createReduceOnlyOrder': true, 'createStopLimitOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'fetchBalance': true, 'fetchBorrowInterest': true, 'fetchBorrowRate': true, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': true, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDeposits': true, 'fetchFundingHistory': false, 'fetchFundingRate': true, 'fetchFundingRateHistory': true, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchLedger': true, 'fetchLeverage': false, 'fetchLeverageTiers': true, 'fetchMarginMode': false, 'fetchMarketLeverageTiers': true, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchPosition': true, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': false, 'fetchTransfers': true, 'fetchWithdrawals': true, 'reduceMargin': false, 'setLeverage': true, 'setMargin': false, 'setMarginMode': false, 'setPositionMode': false, 'transfer': true, 'withdraw': true, }, 'timeframes': { '1m': '1', '5m': '5', '15m': '15', '30m': '30', '1h': '60', '4h': '240', '12h': '720', '1d': '1D', '1w': '1W', }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/51840849/87443315-01283a00-c5fe-11ea-8628-c2a0feaf07ac.jpg', 'api': { 'rest': 'https://openapi.digifinex.com', }, 'www': 'https://www.digifinex.com', 'doc': [ 'https://docs.digifinex.com', ], 'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328422-Fee-Structure-on-DigiFinex', 'referral': 'https://www.digifinex.com/en-ww/from/DhOzBg?channelCode=ljaUPp', }, 'api': { 'public': { 'spot': { 'get': [ '{market}/symbols', 'kline', 'margin/currencies', 'margin/symbols', 'markets', 'order_book', 'ping', 'spot/symbols', 'time', 'trades', 'trades/symbols', 'ticker', 'currencies', ], }, 'swap': { 'get': [ 'public/api_weight', 'public/candles', 'public/candles_history', 'public/depth', 'public/funding_rate', 'public/funding_rate_history', 'public/instrument', 'public/instruments', 'public/ticker', 'public/tickers', 'public/time', 'public/trades', ], }, }, 'private': { 'spot': { 'get': [ '{market}/financelog', '{market}/mytrades', '{market}/order', '{market}/order/detail', '{market}/order/current', '{market}/order/history', 'margin/assets', 'margin/financelog', 'margin/mytrades', 'margin/order', 'margin/order/current', 'margin/order/history', 'margin/positions', 'otc/financelog', 'spot/assets', 'spot/financelog', 'spot/mytrades', 'spot/order', 'spot/order/current', 'spot/order/history', 'deposit/address', 'deposit/history', 'withdraw/history', ], 'post': [ '{market}/order/cancel', '{market}/order/new', '{market}/order/batch_new', 'margin/order/cancel', 'margin/order/new', 'margin/position/close', 'spot/order/cancel', 'spot/order/new', 'transfer', 'withdraw/new', 'withdraw/cancel', ], }, 'swap': { 'get': [ 'account/balance', 'account/positions', 'account/finance_record', 'account/trading_fee_rate', 'account/transfer_record', 'trade/history_orders', 'trade/history_trades', 'trade/open_orders', 'trade/order_info', ], 'post': [ 'account/leverage', 'trade/batch_cancel_order', 'trade/batch_order', 'trade/cancel_order', 'trade/order_place', ], }, }, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'maker': this.parseNumber ('0.002'), 'taker': this.parseNumber ('0.002'), }, }, 'precisionMode': TICK_SIZE, 'exceptions': { 'exact': { '10001': [ BadRequest, "Wrong request method, please check it's a GET ot POST request" ], '10002': [ AuthenticationError, 'Invalid ApiKey' ], '10003': [ AuthenticationError, "Sign doesn't match" ], '10004': [ BadRequest, 'Illegal request parameters' ], '10005': [ DDoSProtection, 'Request frequency exceeds the limit' ], '10006': [ PermissionDenied, 'Unauthorized to execute this request' ], '10007': [ PermissionDenied, 'IP address Unauthorized' ], '10008': [ InvalidNonce, 'Timestamp for this request is invalid, timestamp must within 1 minute' ], '10009': [ NetworkError, 'Unexist endpoint, please check endpoint URL' ], '10011': [ AccountSuspended, 'ApiKey expired. Please go to client side to re-create an ApiKey' ], '20001': [ PermissionDenied, 'Trade is not open for this trading pair' ], '20002': [ PermissionDenied, 'Trade of this trading pair is suspended' ], '20003': [ InvalidOrder, 'Invalid price or amount' ], '20007': [ InvalidOrder, 'Price precision error' ], '20008': [ InvalidOrder, 'Amount precision error' ], '20009': [ InvalidOrder, 'Amount is less than the minimum requirement' ], '20010': [ InvalidOrder, 'Cash Amount is less than the minimum requirement' ], '20011': [ InsufficientFunds, 'Insufficient balance' ], '20012': [ BadRequest, 'Invalid trade type, valid value: buy/sell)' ], '20013': [ InvalidOrder, 'No order info found' ], '20014': [ BadRequest, 'Invalid date, Valid format: 2018-07-25)' ], '20015': [ BadRequest, 'Date exceeds the limit' ], '20018': [ PermissionDenied, 'Your trading rights have been banned by the system' ], '20019': [ BadSymbol, 'Wrong trading pair symbol. Correct format:"usdt_btc". Quote asset is in the front' ], '20020': [ DDoSProtection, "You have violated the API operation trading rules and temporarily forbid trading. At present, we have certain restrictions on the user's transaction rate and withdrawal rate." ], '50000': [ ExchangeError, 'Exception error' ], '20021': [ BadRequest, 'Invalid currency' ], '20022': [ BadRequest, 'The ending timestamp must be larger than the starting timestamp' ], '20023': [ BadRequest, 'Invalid transfer type' ], '20024': [ BadRequest, 'Invalid amount' ], '20025': [ BadRequest, 'This currency is not transferable at the moment' ], '20026': [ InsufficientFunds, 'Transfer amount exceed your balance' ], '20027': [ PermissionDenied, 'Abnormal account status' ], '20028': [ PermissionDenied, 'Blacklist for transfer' ], '20029': [ PermissionDenied, 'Transfer amount exceed your daily limit' ], '20030': [ BadRequest, 'You have no position on this trading pair' ], '20032': [ PermissionDenied, 'Withdrawal limited' ], '20033': [ BadRequest, 'Wrong Withdrawal ID' ], '20034': [ PermissionDenied, 'Withdrawal service of this crypto has been closed' ], '20035': [ PermissionDenied, 'Withdrawal limit' ], '20036': [ ExchangeError, 'Withdrawal cancellation failed' ], '20037': [ InvalidAddress, 'The withdrawal address, Tag or chain type is not included in the withdrawal management list' ], '20038': [ InvalidAddress, 'The withdrawal address is not on the white list' ], '20039': [ ExchangeError, "Can't be canceled in current status" ], '20040': [ RateLimitExceeded, 'Withdraw too frequently; limitation: 3 times a minute, 100 times a day' ], '20041': [ PermissionDenied, 'Beyond the daily withdrawal limit' ], '20042': [ BadSymbol, 'Current trading pair does not support API trading' ], '400002': [ BadRequest, 'Invalid Parameter' ], }, 'broad': { }, }, 'options': { 'defaultType': 'spot', 'types': [ 'spot', 'margin', 'otc' ], 'accountsByType': { 'spot': '1', 'margin': '2', 'OTC': '3', }, 'networks': { 'ARBITRUM': 'Arbitrum', 'AVALANCEC': 'AVAX-CCHAIN', 'AVALANCEX': 'AVAX-XCHAIN', 'BEP20': 'BEP20', 'BSC': 'BEP20', 'CARDANO': 'Cardano', 'CELO': 'Celo', 'CHILIZ': 'Chiliz', 'COSMOS': 'COSMOS', 'CRC20': 'Crypto.com', 'CRONOS': 'Crypto.com', 'DOGECOIN': 'DogeChain', 'ERC20': 'ERC20', 'ETH': 'ERC20', 'ETHW': 'ETHW', 'IOTA': 'MIOTA', 'KLAYTN': 'KLAY', 'MATIC': 'Polygon', 'METIS': 'MetisDAO', 'MOONBEAM': 'GLMR', 'MOONRIVER': 'Moonriver', 'OPTIMISM': 'OPETH', 'POLYGON': 'Polygon', 'RIPPLE': 'XRP', 'SOLANA': 'SOL', // SOL & SPL 'STELLAR': 'Stella', // XLM 'TERRACLASSIC': 'TerraClassic', 'TERRA': 'Terra', 'TON': 'Ton', 'TRC20': 'TRC20', 'TRON': 'TRC20', 'TRX': 'TRC20', 'VECHAIN': 'Vechain', // VET }, 'networksById': { 'Arbitrum': 'ARBITRUM', 'AVAX-CCHAIN': 'AVALANCEC', 'AVAX-XCHAIN': 'AVALANCEX', 'BEP20': 'BEP20', 'Cardano': 'CARDANO', 'Celo': 'CELO', 'Chiliz': 'CHILIZ', 'COSMOS': 'COSMOS', 'Crypto.com': 'CRC20', // CRONOS 'DogeChain': 'DOGECOIN', 'ERC20': 'ERC20', 'ETHW': 'ETHW', 'MIOTA': 'IOTA', 'KLAY': 'KLAYTN', 'Polygon': 'POLYGON', 'MetisDAO': 'METIS', 'Moonriver': 'MOONRIVER', 'GLMR': 'MOONBEAM', 'OPETH': 'OPTIMISM', 'XRP': 'RIPPLE', 'SOL': 'SOLANA', 'Stella': 'STELLAR', 'Terra': 'TERRA', 'TerraClassic': 'TERRACLASSIC', 'Ton': 'TON', 'TRC20': 'TRC20', 'Vechain': 'VECHAIN', }, }, 'commonCurrencies': { 'BHT': 'Black House Test', 'EPS': 'Epanus', 'FREE': 'FreeRossDAO', 'MBN': 'Mobilian Coin', 'TEL': 'TEL666', }, }); } async fetchCurrencies (params = {}) { /** * @method * @name digifinex#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} params extra parameters specific to the digifinex api endpoint * @returns {object} an associative dictionary of currencies */ const response = await this.publicSpotGetCurrencies (params); // // { // "data":[ // { // "deposit_status":1, // "min_deposit_amount":10, // "withdraw_fee_rate":0, // "min_withdraw_amount":10, // "min_withdraw_fee":5, // "currency":"USDT", // "withdraw_status":0, // "chain":"OMNI" // }, // { // "deposit_status":1, // "min_deposit_amount":10, // "withdraw_fee_rate":0, // "min_withdraw_amount":10, // "min_withdraw_fee":3, // "currency":"USDT", // "withdraw_status":1, // "chain":"ERC20" // }, // { // "deposit_status":0, // "min_deposit_amount":0, // "withdraw_fee_rate":0, // "min_withdraw_amount":0, // "min_withdraw_fee":0, // "currency":"DGF13", // "withdraw_status":0, // "chain":"" // }, // ], // "code":200 // } // const data = this.safeValue (response, 'data', []); const result = {}; for (let i = 0; i < data.length; i++) { const currency = data[i]; const id = this.safeString (currency, 'currency'); const code = this.safeCurrencyCode (id); const depositStatus = this.safeInteger (currency, 'deposit_status', 1); const withdrawStatus = this.safeInteger (currency, 'withdraw_status', 1); const deposit = depositStatus > 0; const withdraw = withdrawStatus > 0; const active = deposit && withdraw; const feeString = this.safeString (currency, 'min_withdraw_fee'); // withdraw_fee_rate was zero for all currencies, so this was the worst case scenario const fee = this.parseNumber (feeString); const minWithdrawString = this.safeString (currency, 'min_withdraw_amount'); const minWithdraw = this.parseNumber (minWithdrawString); const minDepositString = this.safeString (currency, 'min_deposit_amount'); const minDepositPrecisionLength = this.precisionFromString (minDepositString); // define precision with temporary way const feePrecisionLength = this.precisionFromString (feeString); const minWithdrawPrecisionLength = this.precisionFromString (minWithdrawString); const minDeposit = this.parseNumber (minDepositString); const maxFoundPrecision = Math.max (feePrecisionLength, Math.max (minWithdrawPrecisionLength, minDepositPrecisionLength)); const precision = this.parseNumber (this.parsePrecision (this.numberToString (maxFoundPrecision))); const networkId = this.safeString (currency, 'chain'); const networkCode = this.networkIdToCode (networkId); const network = { 'info': currency, 'id': networkId, 'network': networkCode, 'active': active, 'fee': this.parseNumber (feeString), 'precision': precision, 'deposit': deposit, 'withdraw': withdraw, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': minWithdraw, 'max': undefined, }, 'deposit': { 'min': minDeposit, 'max': undefined, }, }, }; if (code in result) { if (Array.isArray (result[code]['info'])) { result[code]['info'].push (currency); } else { result[code]['info'] = [ result[code]['info'], currency ]; } if (withdraw) { result[code]['withdraw'] = true; result[code]['limits']['withdraw']['min'] = Math.min (result[code]['limits']['withdraw']['min'], minWithdraw); } if (deposit) { result[code]['deposit'] = true; result[code]['limits']['deposit']['min'] = Math.min (result[code]['limits']['deposit']['min'], minDeposit); } if (active) { result[code]['active'] = true; } } else { result[code] = { 'id': id, 'code': code, 'info': currency, 'type': undefined, 'name': undefined, 'active': active, 'deposit': deposit, 'withdraw': withdraw, 'fee': fee, 'precision': undefined, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': minWithdraw, 'max': undefined, }, 'deposit': { 'min': minDeposit, 'max': undefined, }, }, 'networks': {}, }; } if (networkId !== undefined) { result[code]['networks'][networkId] = network; } else { result[code]['active'] = active; result[code]['fee'] = this.parseNumber (feeString); result[code]['deposit'] = deposit; result[code]['withdraw'] = withdraw; result[code]['limits'] = { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': minWithdraw, 'max': undefined, }, 'deposit': { 'min': minDeposit, 'max': undefined, }, }; } result[code]['precision'] = (result[code]['precision'] === undefined) ? precision : Math.max (result[code]['precision'], precision); } return result; } async fetchMarkets (params = {}) { /** * @method * @name digifinex#fetchMarkets * @description retrieves data on all markets for digifinex * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const options = this.safeValue (this.options, 'fetchMarkets', {}); const method = this.safeString (options, 'method', 'fetch_markets_v2'); return await this[method] (params); } async fetchMarketsV2 (params = {}) { const defaultType = this.safeString (this.options, 'defaultType'); const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchMarketsV2', params); const method = (marginMode !== undefined) ? 'publicSpotGetMarginSymbols' : 'publicSpotGetTradesSymbols'; let promises = [ this[method] (query), this.publicSwapGetPublicInstruments (params) ]; promises = await Promise.all (promises); const spotMarkets = promises[0]; const swapMarkets = promises[1]; // // spot and margin // // { // "symbol_list":[ // { // "order_types":["LIMIT","MARKET"], // "quote_asset":"USDT", // "minimum_value":2, // "amount_precision":4, // "status":"TRADING", // "minimum_amount":0.0001, // "symbol":"BTC_USDT", // "is_allow":1, // "zone":"MAIN", // "base_asset":"BTC", // "price_precision":2 // } // ], // "code":0 // } // // swap // // { // "code": 0, // "data": [ // { // "instrument_id": "BTCUSDTPERP", // "type": "REAL", // "contract_type": "PERPETUAL", // "base_currency": "BTC", // "quote_currency": "USDT", // "clear_currency": "USDT", // "contract_value": "0.001", // "contract_value_currency": "BTC", // "is_inverse": false, // "is_trading": true, // "status": "ONLINE", // "price_precision": 4, // "tick_size": "0.0001", // "min_order_amount": 1, // "open_max_limits": [ // { // "leverage": "50", // "max_limit": "1000000" // } // ] // }, // ] // } // const spotData = this.safeValue (spotMarkets, 'symbol_list', []); const swapData = this.safeValue (swapMarkets, 'data', []); const response = this.arrayConcat (spotData, swapData); const result = []; for (let i = 0; i < response.length; i++) { const market = response[i]; const id = this.safeString2 (market, 'symbol', 'instrument_id'); const baseId = this.safeString2 (market, 'base_asset', 'base_currency'); const quoteId = this.safeString2 (market, 'quote_asset', 'quote_currency'); const settleId = this.safeString (market, 'clear_currency'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); const settle = this.safeCurrencyCode (settleId); // // The status is documented in the exchange API docs as follows: // TRADING, HALT (delisted), BREAK (trading paused) // https://docs.digifinex.vip/en-ww/v3/#/public/spot/symbols // However, all spot markets actually have status === 'HALT' // despite that they appear to be active on the exchange website. // Apparently, we can't trust this status. // const status = this.safeString (market, 'status'); // const active = (status === 'TRADING'); // let isAllowed = this.safeInteger (market, 'is_allow', 1); let type = (defaultType === 'margin') ? 'margin' : 'spot'; const spot = settle === undefined; const swap = !spot; const margin = (marginMode !== undefined) ? true : undefined; let symbol = base + '/' + quote; let isInverse = undefined; let isLinear = undefined; if (swap) { type = 'swap'; symbol = base + '/' + quote + ':' + settle; isInverse = this.safeValue (market, 'is_inverse'); isLinear = (!isInverse) ? true : false; const isTrading = this.safeValue (market, 'isTrading'); if (isTrading) { isAllowed = true; } } result.push ({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': type, 'spot': spot, 'margin': margin, 'swap': swap, 'future': false, 'option': false, 'active': isAllowed ? true : false, 'contract': swap, 'linear': isLinear, 'inverse': isInverse, 'contractSize': this.safeNumber (market, 'contract_value'), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber (this.parsePrecision (this.safeString (market, 'amount_precision'))), 'price': this.parseNumber (this.parsePrecision (this.safeString (market, 'price_precision'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber2 (market, 'minimum_amount', 'min_order_amount'), 'max': undefined, }, 'price': { 'min': this.safeNumber (market, 'tick_size'), 'max': undefined, }, 'cost': { 'min': this.safeNumber (market, 'minimum_value'), 'max': undefined, }, }, 'info': market, }); } return result; } async fetchMarketsV1 (params = {}) { const response = await this.publicSpotGetMarkets (params); // // { // "data": [ // { // "volume_precision":4, // "price_precision":2, // "market":"btc_usdt", // "min_amount":2, // "min_volume":0.0001 // }, // ], // "date":1564507456, // "code":0 // } // const markets = this.safeValue (response, 'data', []); const result = []; for (let i = 0; i < markets.length; i++) { const market = markets[i]; const id = this.safeString (market, 'market'); const [ baseId, quoteId ] = id.split ('_'); const base = this.safeCurrencyCode (baseId); const quote = this.safeCurrencyCode (quoteId); result.push ({ 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': undefined, 'swap': false, 'future': false, 'option': false, 'active': undefined, 'contract': false, 'linear': undefined, 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'price': this.parseNumber (this.parsePrecision (this.safeString (market, 'price_precision'))), 'amount': this.parseNumber (this.parsePrecision (this.safeString (market, 'volume_precision'))), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber (market, 'min_volume'), 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': this.safeNumber (market, 'min_amount'), 'max': undefined, }, }, 'info': market, }); } return result; } parseBalance (response) { // // spot and margin // // { // "currency": "BTC", // "free": 4723846.89208129, // "total": 0 // } // // swap // // { // "equity": "0", // "currency": "BTC", // "margin": "0", // "frozen_margin": "0", // "frozen_money": "0", // "margin_ratio": "0", // "realized_pnl": "0", // "avail_balance": "0", // "unrealized_pnl": "0", // "time_stamp": 1661487402396 // } // const result = { 'info': response }; for (let i = 0; i < response.length; i++) { const balance = response[i]; const currencyId = this.safeString (balance, 'currency'); const code = this.safeCurrencyCode (currencyId); const account = this.account (); const free = this.safeString2 (balance, 'free', 'avail_balance'); const total = this.safeString2 (balance, 'total', 'equity'); account['free'] = free; account['used'] = Precise.stringSub (total, free); account['total'] = total; result[code] = account; } return this.safeBalance (result); } async fetchBalance (params = {}) { /** * @method * @name digifinex#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://docs.digifinex.com/en-ww/spot/v3/rest.html#spot-account-assets * @see https://docs.digifinex.com/en-ww/spot/v3/rest.html#margin-assets * @see https://docs.digifinex.com/en-ww/swap/v2/rest.html#accountbalance * @param {object} params extra parameters specific to the digifinex api endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure} */ await this.loadMarkets (); let marketType = undefined; [ marketType, params ] = this.handleMarketTypeAndParams ('fetchBalance', undefined, params); let method = this.getSupportedMapping (marketType, { 'spot': 'privateSpotGetSpotAssets', 'margin': 'privateSpotGetMarginAssets', 'swap': 'privateSwapGetAccountBalance', }); const [ marginMode, query ] = this.handleMarginModeAndParams ('fetchBalance', params); if (marginMode !== undefined) { method = 'privateSpotGetMarginAssets'; marketType = 'margin'; } const response = await this[method] (query); // // spot and margin // // { // "code": 0, // "list": [ // { // "currency": "BTC", // "free": 4723846.89208129, // "total": 0 // }, // ... // ] // } // // swap // // { // "code": 0, // "data": [ // { // "equity": "0", // "currency": "BTC", // "margin": "0", // "frozen_margin": "0", // "frozen_money": "0", // "margin_ratio": "0", // "realized_pnl": "0", // "avail_balance": "0", // "unrealized_pnl": "0", // "time_stamp": 1661487402396 // }, // ... // ] // } // const balanceRequest = (marketType === 'swap') ? 'data' : 'list'; const balances = this.safeValue (response, balanceRequest, []); return this.parseBalance (balances); } async fetchOrderBook (symbol, limit = undefined, params = {}) { /** * @method * @name digifinex#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://docs.digifinex.com/en-ww/spot/v3/rest.html#get-orderbook * @see https://docs.digifinex.com/en-ww/swap/v2/rest.html#orderbook * @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 digifinex api endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-book-structure} indexed by market symbols */ await this.loadMarkets (); const market = this.market (symbol); const [ marketType, query ] = this.handleMarketTypeAndParams ('fetchOrderBook', market, params); const request = {}; let method = undefined; if (marketType === 'swap') { method = 'publicSwapGetPublicDepth'; request['instrument_id'] = market['id']; } else { method = 'publicSpotGetOrderBook'; request['symbol'] = market['id']; } if (limit !== undefined) { request['limit'] = limit; } const response = await this[method] (this.extend (request, query)); // // spot // // { // "bids": [ // [9605.77,0.0016], // [9605.46,0.0003], // [9602.04,0.0127], // ], // "asks": [ // [9627.22,0.025803], // [9627.12,0.168543], // [9626.52,0.0011529], // ], // "date":1564509499, // "code":0 // } // // swap // // { // "code": 0, // "data": { // "instrument_id": "BTCUSDTPERP", // "timestamp": 1667975290425, // "asks": [ // ["18384.7",3492], // ["18402.7",5000], // ["18406.7",5000], // ], // "bids": [ // ["18366.2",4395], // ["18364.3",3070], // ["18359.4",5000], // ] // } // } // let timestamp = undefined; let orderBook = undefined; if (marketType === 'swap') { orderBook = this.safeValue (response, 'data', {}); timestamp = this.safeInteger (orderBook, 'timestamp'); } else { orderBook = response; timestamp = this.safeTimestamp (response, 'date'); } return this.parseOrderBook (orderBook, market['symbol'], timestamp); } async fetchTickers (symbols = undefined, params = {}) { /** * @method * @name digifinex#fetchTickers * @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market * @see https://docs.digifinex.com/en-ww/spot/v3/rest.html#ticker-price * @see https://docs.digifinex.com/en-ww/swap/v2/rest.html#tickers * @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 digifinex api endpoint * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); symbols = this.marketSymbols (symbols); const first = this.safeString (symbols, 0); let market = undefined; if (first !== undefined) { market = this.market (first); } let type = undefined; [ type, params ] = this.handleMarketTypeAndParams ('fetchTickers', market, params); let method = 'publicSpotGetTicker'; const request = {}; if (type === 'swap') { method = 'publicSwapGetPublicTickers'; } const response = await this[method] (this.extend (request, params)); // // spot // // { // "ticker": [{ // "vol": 40717.4461, // "change": -1.91, // "base_vol": 392447999.65374, // "sell": 9592.23, // "last": 9592.22, // "symbol": "btc_usdt", // "low": 9476.24, // "buy": 9592.03, // "high": 9793.87 // }], // "date": 1589874294, // "code": 0 // } // // swap // // { // "code": 0, // "data": [ // { // "instrument_id": "SUSHIUSDTPERP", // "index_price": "1.1297", // "mark_price": "1.1289", // "max_buy_price": "1.1856", // "min_sell_price": "1.0726", // "best_bid": "1.1278", // "best_bid_size": "500", // "best_ask": "1.1302", // "best_ask_size": "471", // "high_24h": "1.2064", // "open_24h": "1.1938", // "low_24h": "1.1239", // "last": "1.1302", // "last_qty": "29", // "volume_24h": "4946163", // "price_change_percent": "-0.053275255486681085", // "open_interest": "-", // "timestamp": 1663222782100 // }, // ... // ] // } // const result = {}; const tickers = this.safeValue2 (response, 'ticker', 'data', []); const date = this.safeInteger (response, 'date'); for (let i = 0; i < tickers.length; i++) { const rawTicker = this.extend ({ 'date': date, }, tickers[i]); const ticker = this.parseTicker (rawTicker); const symbol = ticker['symbol']; result[symbol] = ticker; } return this.filterByArray (result, 'symbol', symbols); } async fetchTicker (symbol, params = {}) { /** * @method * @name digifinex#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @see https://docs.digifinex.com/en-ww/spot/v3/rest.html#ticker-price * @see https://docs.digifinex.com/en-ww/swap/v2/rest.html#ticker * @param {string} symbol unified symbol of the market to fetch the ticker for * @param {object} params extra parameters specific to the digifinex api endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure} */ await this.loadMarkets (); const market = this.market (symbol); let method = 'publicSpotGetTicker'; const request = {}; if (market['swap']) { method = 'publicSwapGetPublicTicker'; request['instrument_id'] = market['id']; } else { request['symbol'] = market['id']; } const response = await this[method] (this.extend (request, params)); // // spot // // { // "ticker": [{ // "vol": 40717.4461, // "change": -1.91, // "base_vol": 392447999.65374, // "sell": 9592.23, // "last": 9592.22, // "symbol": "btc_usdt", // "low": 9476.24, // "buy": 9592.03, // "high": 9793.87 // }], // "date": 1589874294, // "code": 0 // } // // swap // // { // "code": 0, // "data": { // "instrument_id": "BTCUSDTPERP", // "index_price": "20141.9967", // "mark_price": "20139.3404", // "max_buy_price": "21146.4838", // "min_sell_price": "19132.2725", // "best_bid": "20140.0998", // "best_bid_size": "3116", // "best_ask": "20140.0999", // "best_ask_size": "9004", // "high_24h": "20410.6496", // "open_24h": "20308.6998", // "low_24h": "19600", // "last": "20140.0999", // "last_qty": "2", // "volume_24h": "49382816", // "price_change_percent": "-0.008301855936636448", // "open_interest": "-", // "timestamp": 1663221614998 // } // } // const date = this.safeInteger (response, 'date'); const tickers = this.safeValue (response, 'ticker', []); const data = this.safeValue (response, 'data', {}); const firstTicker = this.safeValue (tickers, 0, {}); let result = undefined; if (market['swap']) { result = data; } else { result = this.extend ({ 'date': date }, firstTicker); } return this.parseTicker (result, market); } parseTicker (ticker, market = undefined) { // // spot: fetchTicker, fetchTickers // // { // "last":0.021957, // "symbol": "btc_usdt", // "base_vol":2249.3521732227, // "change":-0.6, // "vol":102443.5111, // "sell":0.021978, // "low":0.021791, // "buy":0.021946, // "high":0.022266, // "date"1564518452, // injected from fetchTicker/fetchTickers // } // // swap: fetchTicker, fetchTickers // // { // "instrument_id": "BTCUSDTPERP", // "index_price": "20141.9967", // "mark_price": "20139.3404", // "max_buy_price": "21146.4838", // "min_sell_price": "19132.2725", // "best_bid": "20140.0998", // "best_bid_size": "3116", // "best_ask": "20140.0999", // "best_ask_size": "9004", // "high_24h": "20410.6496", // "open_24h": "20308.6998", // "low_24h": "19600", // "last": "20140.0999", // "last_qty": "2", // "volume_24h": "49382816", // "price_change_percent": "-0.008301855936636448", // "open_interest": "-", // "timestamp": 1663221614998 // } // const marketId = this.safeStringUpper2 (ticker, 'symbol', 'instrument_id'); const symbol = this.safeSymbol (marketId, market); market = this.safeMarket (marketId); let timestamp = this.safeTimestamp (ticker, 'da