UNPKG

ccxt

Version:

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

1,131 lines (1,129 loc) • 145 kB
// ---------------------------------------------------------------------------- // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN: // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code // EDIT THE CORRESPONDENT .ts FILE INSTEAD // --------------------------------------------------------------------------- import Exchange from './abstract/bitrue.js'; import { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, RateLimitExceeded, PermissionDenied, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable, OnMaintenance, NotSupported } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TRUNCATE, TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- /** * @class bitrue * @augments Exchange */ export default class bitrue extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'bitrue', 'name': 'Bitrue', 'countries': ['SG'], 'rateLimit': 10, 'certified': false, 'version': 'v1', 'pro': true, // new metainfo interface 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': true, 'future': false, 'option': false, 'addMargin': false, 'borrowCrossMargin': false, 'borrowIsolatedMargin': false, 'borrowMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'closeAllPositions': false, 'closePosition': false, 'createMarketBuyOrderWithCost': true, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createOrderWithTakeProfitAndStopLoss': false, 'createOrderWithTakeProfitAndStopLossWs': false, 'createReduceOnlyOrder': true, 'createStopLimitOrder': true, 'createStopMarketOrder': true, 'createStopOrder': true, 'fetchBalance': true, 'fetchBidsAsks': true, 'fetchBorrowInterest': false, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchClosedOrders': true, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': true, 'fetchDepositAddress': false, 'fetchDeposits': true, 'fetchDepositsWithdrawals': false, 'fetchDepositWithdrawFee': 'emulated', 'fetchDepositWithdrawFees': true, 'fetchFundingHistory': false, 'fetchFundingInterval': false, 'fetchFundingIntervals': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchGreeks': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchIsolatedPositions': false, 'fetchLeverage': false, 'fetchLeverages': false, 'fetchLeverageTiers': false, 'fetchLiquidations': false, 'fetchLongShortRatio': false, 'fetchLongShortRatioHistory': false, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarginModes': false, 'fetchMarketLeverageTiers': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMarkPrices': false, 'fetchMyLiquidations': false, 'fetchMySettlementHistory': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterest': false, 'fetchOpenInterestHistory': false, 'fetchOpenInterests': false, 'fetchOpenOrders': true, 'fetchOption': false, 'fetchOptionChain': false, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': false, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsHistory': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchSettlementHistory': false, 'fetchStatus': true, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': false, 'fetchTransactionFees': false, 'fetchTransactions': false, 'fetchTransfers': true, 'fetchVolatilityHistory': false, 'fetchWithdrawals': true, 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, 'setLeverage': true, 'setMargin': true, 'setMarginMode': false, 'setPositionMode': false, 'transfer': true, 'withdraw': true, }, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1H', '2h': '2H', '4h': '4H', '1d': '1D', '1w': '1W', }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/67abe346-1273-461a-bd7c-42fa32907c8e', 'api': { 'spot': 'https://www.bitrue.com/api', 'fapi': 'https://fapi.bitrue.com/fapi', 'dapi': 'https://fapi.bitrue.com/dapi', 'kline': 'https://www.bitrue.com/kline-api', }, 'www': 'https://www.bitrue.com', 'referral': 'https://www.bitrue.com/affiliate/landing?cn=600000&inviteCode=EZWETQE', 'doc': [ 'https://github.com/Bitrue-exchange/bitrue-official-api-docs', 'https://www.bitrue.com/api-docs', ], 'fees': 'https://bitrue.zendesk.com/hc/en-001/articles/4405479952537', }, // from spotV1PublicGetExchangeInfo: // general 25000 weight in 1 minute per IP. = 416.66 per second a weight of 0.24 for 1 // orders 750 weight in 6 seconds per IP. = 125 per second a weight of 0.8 for 1 // orders 200 weight in 10 seconds per User. = 20 per second a weight of 5 for 1 // withdraw 3000 weight in 1 hour per User. = 0.833 per second a weight of 120 for 1 // withdraw 1000 weight in 1 day per User. = 0.011574 per second a weight of 8640 for 1 'api': { 'spot': { 'kline': { 'public': { 'get': { 'public.json': 0.24, 'public{currency}.json': 0.24, }, }, }, 'v1': { 'public': { 'get': { 'ping': 0.24, 'time': 0.24, 'exchangeInfo': 0.24, 'depth': { 'cost': 1, 'byLimit': [[100, 0.24], [500, 1.2], [1000, 2.4]] }, 'trades': 0.24, 'historicalTrades': 1.2, 'aggTrades': 0.24, 'ticker/24hr': { 'cost': 0.24, 'noSymbol': 9.6 }, 'ticker/price': 0.24, 'ticker/bookTicker': 0.24, 'market/kline': 0.24, }, }, 'private': { 'get': { 'order': 5, 'openOrders': 5, 'allOrders': 25, 'account': 25, 'myTrades': 25, 'etf/net-value/{symbol}': 0.24, 'withdraw/history': 120, 'deposit/history': 120, }, 'post': { 'order': 5, 'withdraw/commit': 120, }, 'delete': { 'order': 5, }, }, }, 'v2': { 'private': { 'get': { 'myTrades': 1.2, }, }, }, }, 'fapi': { 'v1': { 'public': { 'get': { 'ping': 0.24, 'time': 0.24, 'contracts': 0.24, 'depth': 0.24, 'ticker': 0.24, 'klines': 0.24, }, }, }, 'v2': { 'private': { 'get': { 'myTrades': 5, 'openOrders': 5, 'order': 5, 'account': 5, 'leverageBracket': 5, 'commissionRate': 5, 'futures_transfer_history': 5, 'forceOrdersHistory': 5, }, 'post': { 'positionMargin': 5, 'level_edit': 5, 'cancel': 5, 'order': 25, 'allOpenOrders': 5, 'futures_transfer': 5, }, }, }, }, 'dapi': { 'v1': { 'public': { 'get': { 'ping': 0.24, 'time': 0.24, 'contracts': 0.24, 'depth': 0.24, 'ticker': 0.24, 'klines': 0.24, }, }, }, 'v2': { 'private': { 'get': { 'myTrades': 5, 'openOrders': 5, 'order': 5, 'account': 5, 'leverageBracket': 5, 'commissionRate': 5, 'futures_transfer_history': 5, 'forceOrdersHistory': 5, }, 'post': { 'positionMargin': 5, 'level_edit': 5, 'cancel': 5, 'order': 5, 'allOpenOrders': 5, 'futures_transfer': 5, }, }, }, }, }, 'fees': { 'trading': { 'feeSide': 'get', 'tierBased': false, 'percentage': true, 'taker': this.parseNumber('0.00098'), 'maker': this.parseNumber('0.00098'), }, 'future': { 'trading': { 'feeSide': 'quote', 'tierBased': true, 'percentage': true, 'taker': this.parseNumber('0.000400'), 'maker': this.parseNumber('0.000200'), 'tiers': { 'taker': [ [this.parseNumber('0'), this.parseNumber('0.000400')], [this.parseNumber('250'), this.parseNumber('0.000400')], [this.parseNumber('2500'), this.parseNumber('0.000350')], [this.parseNumber('7500'), this.parseNumber('0.000320')], [this.parseNumber('22500'), this.parseNumber('0.000300')], [this.parseNumber('50000'), this.parseNumber('0.000270')], [this.parseNumber('100000'), this.parseNumber('0.000250')], [this.parseNumber('200000'), this.parseNumber('0.000220')], [this.parseNumber('400000'), this.parseNumber('0.000200')], [this.parseNumber('750000'), this.parseNumber('0.000170')], ], 'maker': [ [this.parseNumber('0'), this.parseNumber('0.000200')], [this.parseNumber('250'), this.parseNumber('0.000160')], [this.parseNumber('2500'), this.parseNumber('0.000140')], [this.parseNumber('7500'), this.parseNumber('0.000120')], [this.parseNumber('22500'), this.parseNumber('0.000100')], [this.parseNumber('50000'), this.parseNumber('0.000080')], [this.parseNumber('100000'), this.parseNumber('0.000060')], [this.parseNumber('200000'), this.parseNumber('0.000040')], [this.parseNumber('400000'), this.parseNumber('0.000020')], [this.parseNumber('750000'), this.parseNumber('0')], ], }, }, }, 'delivery': { 'trading': { 'feeSide': 'base', 'tierBased': true, 'percentage': true, 'taker': this.parseNumber('0.000500'), 'maker': this.parseNumber('0.000100'), 'tiers': { 'taker': [ [this.parseNumber('0'), this.parseNumber('0.000500')], [this.parseNumber('250'), this.parseNumber('0.000450')], [this.parseNumber('2500'), this.parseNumber('0.000400')], [this.parseNumber('7500'), this.parseNumber('0.000300')], [this.parseNumber('22500'), this.parseNumber('0.000250')], [this.parseNumber('50000'), this.parseNumber('0.000240')], [this.parseNumber('100000'), this.parseNumber('0.000240')], [this.parseNumber('200000'), this.parseNumber('0.000240')], [this.parseNumber('400000'), this.parseNumber('0.000240')], [this.parseNumber('750000'), this.parseNumber('0.000240')], ], 'maker': [ [this.parseNumber('0'), this.parseNumber('0.000100')], [this.parseNumber('250'), this.parseNumber('0.000080')], [this.parseNumber('2500'), this.parseNumber('0.000050')], [this.parseNumber('7500'), this.parseNumber('0.0000030')], [this.parseNumber('22500'), this.parseNumber('0')], [this.parseNumber('50000'), this.parseNumber('-0.000050')], [this.parseNumber('100000'), this.parseNumber('-0.000060')], [this.parseNumber('200000'), this.parseNumber('-0.000070')], [this.parseNumber('400000'), this.parseNumber('-0.000080')], [this.parseNumber('750000'), this.parseNumber('-0.000090')], ], }, }, }, }, // exchange-specific options 'options': { 'createMarketBuyOrderRequiresPrice': true, 'fetchMarkets': [ 'spot', 'linear', 'inverse', ], // 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades 'fetchMyTradesMethod': 'v2PrivateGetMyTrades', 'hasAlreadyAuthenticatedSuccessfully': false, 'currencyToPrecisionRoundingMode': TRUNCATE, 'recvWindow': 5 * 1000, 'timeDifference': 0, 'adjustForTimeDifference': false, 'parseOrderToPrecision': false, 'newOrderRespType': { 'market': 'FULL', 'limit': 'FULL', // we change it from 'ACK' by default to 'FULL' (returns immediately if limit is not hit) }, 'networks': { 'ERC20': 'ETH', 'TRC20': 'TRX', 'AETERNITY': 'Aeternity', 'AION': 'AION', 'ALGO': 'Algorand', 'ASK': 'ASK', 'ATOM': 'ATOM', 'AVAXC': 'AVAX C-Chain', 'BCH': 'BCH', 'BEP2': 'BEP2', 'BEP20': 'BEP20', 'Bitcoin': 'Bitcoin', 'BRP20': 'BRP20', 'ADA': 'Cardano', 'CASINOCOIN': 'CasinoCoin', 'CASINOCOIN-XRPL': 'CasinoCoin XRPL', 'CONTENTOS': 'Contentos', 'DASH': 'Dash', 'DECOIN': 'Decoin', 'DFI': 'DeFiChain', 'DGB': 'DGB', 'DIVI': 'Divi', 'DOGE': 'dogecoin', 'EOS': 'EOS', 'ETC': 'ETC', 'FILECOIN': 'Filecoin', 'FREETON': 'FREETON', 'HBAR': 'HBAR', 'HEDERA': 'Hedera Hashgraph', 'HRC20': 'HRC20', 'ICON': 'ICON', 'ICP': 'ICP', 'IGNIS': 'Ignis', 'INTERNETCOMPUTER': 'Internet Computer', 'IOTA': 'IOTA', 'KAVA': 'KAVA', 'KSM': 'KSM', 'LTC': 'LiteCoin', 'LUNA': 'Luna', 'MATIC': 'MATIC', 'MOBILECOIN': 'Mobile Coin', 'MONACOIN': 'MonaCoin', 'XMR': 'Monero', 'NEM': 'NEM', 'NEP5': 'NEP5', 'OMNI': 'OMNI', 'PAC': 'PAC', 'DOT': 'Polkadot', 'RAVEN': 'Ravencoin', 'SAFEX': 'Safex', 'SOL': 'SOLANA', 'SGB': 'Songbird', 'XML': 'Stellar Lumens', 'XYM': 'Symbol', 'XTZ': 'Tezos', 'theta': 'theta', 'THETA': 'THETA', 'VECHAIN': 'VeChain', 'WANCHAIN': 'Wanchain', 'XINFIN': 'XinFin Network', 'XRP': 'XRP', 'XRPL': 'XRPL', 'ZIL': 'ZIL', }, 'defaultType': 'spot', 'timeframes': { 'spot': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1H', '2h': '2H', '4h': '4H', '12h': '12H', '1d': '1D', '1w': '1W', }, 'future': { '1m': '1min', '5m': '5min', '15m': '15min', '30m': '30min', '1h': '1h', '1d': '1day', '1w': '1week', '1M': '1month', }, }, 'accountsByType': { 'spot': 'wallet', 'future': 'contract', 'swap': 'contract', 'funding': 'wallet', 'fund': 'wallet', 'contract': 'contract', }, }, 'commonCurrencies': { 'MIM': 'MIM Swarm', }, 'precisionMode': TICK_SIZE, 'features': { 'default': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': undefined, 'triggerDirection': undefined, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyRequiresPrice': true, 'marketBuyByCost': true, 'selfTradePrevention': false, 'iceberg': true, // todo implement }, 'createOrders': undefined, 'fetchMyTrades': { 'marginMode': false, 'limit': 1000, 'daysBack': 100000, 'untilDays': 100000, 'symbolRequired': true, }, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchOrders': undefined, 'fetchClosedOrders': { 'marginMode': false, 'limit': 1000, 'daysBack': 90, 'daysBackCanceled': 1, 'untilDays': 90, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchOHLCV': { 'limit': 1440, }, }, 'spot': { 'extends': 'default', }, 'forDerivatives': { 'extends': 'default', 'createOrder': { 'marginMode': true, 'leverage': true, 'marketBuyRequiresPrice': false, 'marketBuyByCost': false, }, 'fetchOHLCV': { 'limit': 300, }, 'fetchClosedOrders': undefined, }, 'swap': { 'linear': { 'extends': 'forDerivatives', }, 'inverse': { 'extends': 'forDerivatives', }, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'exceptions': { 'exact': { 'System is under maintenance.': OnMaintenance, 'System abnormality': ExchangeError, 'You are not authorized to execute this request.': PermissionDenied, 'API key does not exist': AuthenticationError, 'Order would trigger immediately.': OrderImmediatelyFillable, 'Stop price would trigger immediately.': OrderImmediatelyFillable, 'Order would immediately match and take.': OrderImmediatelyFillable, 'Account has insufficient balance for requested action.': InsufficientFunds, 'Rest API trading is not enabled.': ExchangeNotAvailable, "You don't have permission.": PermissionDenied, 'Market is closed.': ExchangeNotAvailable, 'Too many requests. Please try again later.': DDoSProtection, '-1000': ExchangeNotAvailable, '-1001': ExchangeNotAvailable, '-1002': AuthenticationError, '-1003': RateLimitExceeded, '-1013': InvalidOrder, '-1015': RateLimitExceeded, '-1016': ExchangeNotAvailable, '-1020': BadRequest, '-1021': InvalidNonce, '-1022': AuthenticationError, '-1100': BadRequest, '-1101': BadRequest, '-1102': BadRequest, '-1103': BadRequest, '-1104': BadRequest, '-1105': BadRequest, '-1106': BadRequest, '-1111': BadRequest, '-1112': InvalidOrder, '-1114': BadRequest, '-1115': BadRequest, '-1116': BadRequest, '-1117': BadRequest, '-1166': InvalidOrder, '-1118': BadRequest, '-1119': BadRequest, '-1120': BadRequest, '-1121': BadSymbol, '-1125': AuthenticationError, '-1127': BadRequest, '-1128': BadRequest, '-1130': BadRequest, '-1131': BadRequest, '-1160': InvalidOrder, '-1156': InvalidOrder, '-2008': AuthenticationError, '-2010': ExchangeError, '-2011': OrderNotFound, '-2013': OrderNotFound, '-2014': AuthenticationError, '-2015': AuthenticationError, '-2017': InsufficientFunds, '-2019': InsufficientFunds, '-3005': InsufficientFunds, '-3006': InsufficientFunds, '-3008': InsufficientFunds, '-3010': ExchangeError, '-3015': ExchangeError, '-3022': AccountSuspended, '-4028': BadRequest, '-3020': InsufficientFunds, '-3041': InsufficientFunds, '-5013': InsufficientFunds, '-11008': InsufficientFunds, '-4051': InsufficientFunds, // {"code":-4051,"msg":"Isolated balance insufficient."} }, 'broad': { 'Insufficient account balance': InsufficientFunds, 'has no operation privilege': PermissionDenied, 'MAX_POSITION': InvalidOrder, // {"code":-2010,"msg":"Filter failure: MAX_POSITION"} }, }, }); } nonce() { return this.milliseconds() - this.options['timeDifference']; } /** * @method * @name bitrue#fetchStatus * @description the latest known information on the availability of the exchange API * @see https://github.com/Bitrue-exchange/Spot-official-api-docs#test-connectivity * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure} */ async fetchStatus(params = {}) { const response = await this.spotV1PublicGetPing(params); // // empty means working status. // // {} // const keys = Object.keys(response); const keysLength = keys.length; const formattedStatus = keysLength ? 'maintenance' : 'ok'; return { 'status': formattedStatus, 'updated': undefined, 'eta': undefined, 'url': undefined, 'info': response, }; } /** * @method * @name bitrue#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @see https://github.com/Bitrue-exchange/Spot-official-api-docs#check-server-time * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int} the current integer timestamp in milliseconds from the exchange server */ async fetchTime(params = {}) { const response = await this.spotV1PublicGetTime(params); // // { // "serverTime":1635467280514 // } // return this.safeInteger(response, 'serverTime'); } /** * @method * @name bitrue#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an associative dictionary of currencies */ async fetchCurrencies(params = {}) { const response = await this.spotV1PublicGetExchangeInfo(params); // // { // "timezone":"CTT", // "serverTime":1635464889117, // "rateLimits":[ // {"rateLimitType":"REQUESTS_WEIGHT","interval":"MINUTES","limit":6000}, // {"rateLimitType":"ORDERS","interval":"SECONDS","limit":150}, // {"rateLimitType":"ORDERS","interval":"DAYS","limit":288000}, // ], // "exchangeFilters":[], // "symbols":[ // { // "symbol":"SHABTC", // "status":"TRADING", // "baseAsset":"sha", // "baseAssetPrecision":0, // "quoteAsset":"btc", // "quotePrecision":10, // "orderTypes":["MARKET","LIMIT"], // "icebergAllowed":false, // "filters":[ // {"filterType":"PRICE_FILTER","minPrice":"0.00000001349","maxPrice":"0.00000017537","priceScale":10}, // {"filterType":"LOT_SIZE","minQty":"1.0","minVal":"0.00020","maxQty":"1000000000","volumeScale":0}, // ], // "defaultPrice":"0.0000006100", // }, // ], // "coins":[ // { // "coin": "near", // "coinFulName": "NEAR Protocol", // "chains": [ "BEP20", ], // "chainDetail": [ // { // "chain": "BEP20", // "enableWithdraw": true, // "enableDeposit": true, // "withdrawFee": "0.2000", // "minWithdraw": "5.0000", // "maxWithdraw": "1000000000000000.0000", // }, // ], // }, // ], // } // const result = {}; const coins = this.safeList(response, 'coins', []); for (let i = 0; i < coins.length; i++) { const currency = coins[i]; const id = this.safeString(currency, 'coin'); const name = this.safeString(currency, 'coinFulName'); const code = this.safeCurrencyCode(id); const networkDetails = this.safeList(currency, 'chainDetail', []); const networks = {}; for (let j = 0; j < networkDetails.length; j++) { const entry = networkDetails[j]; const networkId = this.safeString(entry, 'chain'); const network = this.networkIdToCode(networkId, code); networks[network] = { 'info': entry, 'id': networkId, 'network': network, 'deposit': this.safeBool(entry, 'enableDeposit'), 'withdraw': this.safeBool(entry, 'enableWithdraw'), 'active': undefined, 'fee': this.safeNumber(entry, 'withdrawFee'), 'precision': undefined, 'limits': { 'withdraw': { 'min': this.safeNumber(entry, 'minWithdraw'), 'max': this.safeNumber(entry, 'maxWithdraw'), }, }, }; } result[code] = this.safeCurrencyStructure({ 'id': id, 'name': name, 'code': code, 'precision': undefined, 'info': currency, 'active': undefined, 'deposit': undefined, 'withdraw': undefined, 'networks': networks, 'fee': undefined, 'fees': undefined, 'type': 'crypto', 'limits': { 'withdraw': { 'min': undefined, 'max': undefined, }, }, }); } return result; } /** * @method * @name bitrue#fetchMarkets * @description retrieves data on all markets for bitrue * @see https://github.com/Bitrue-exchange/Spot-official-api-docs#exchangeInfo_endpoint * @see https://www.bitrue.com/api-docs#current-open-contract * @see https://www.bitrue.com/api_docs_includes_file/delivery.html#current-open-contract * @param {object} [params] extra parameters specific to the exchange api endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const promisesRaw = []; const fetchMarkets = this.safeValue(this.options, 'fetchMarkets', ['spot', 'linear', 'inverse']); for (let i = 0; i < fetchMarkets.length; i++) { const marketType = fetchMarkets[i]; if (marketType === 'spot') { promisesRaw.push(this.spotV1PublicGetExchangeInfo(params)); } else if (marketType === 'linear') { promisesRaw.push(this.fapiV1PublicGetContracts(params)); } else if (marketType === 'inverse') { promisesRaw.push(this.dapiV1PublicGetContracts(params)); } else { throw new ExchangeError(this.id + ' fetchMarkets() this.options fetchMarkets "' + marketType + '" is not a supported market type'); } } const promises = await Promise.all(promisesRaw); const spotMarkets = this.safeValue(this.safeValue(promises, 0), 'symbols', []); const futureMarkets = this.safeValue(promises, 1); const deliveryMarkets = this.safeValue(promises, 2); let markets = spotMarkets; markets = this.arrayConcat(markets, futureMarkets); markets = this.arrayConcat(markets, deliveryMarkets); // // spot // // { // "timezone":"CTT", // "serverTime":1635464889117, // "rateLimits":[ // {"rateLimitType":"REQUESTS_WEIGHT","interval":"MINUTES","limit":6000}, // {"rateLimitType":"ORDERS","interval":"SECONDS","limit":150}, // {"rateLimitType":"ORDERS","interval":"DAYS","limit":288000}, // ], // "exchangeFilters":[], // "symbols":[ // { // "symbol":"SHABTC", // "status":"TRADING", // "baseAsset":"sha", // "baseAssetPrecision":0, // "quoteAsset":"btc", // "quotePrecision":10, // "orderTypes":["MARKET","LIMIT"], // "icebergAllowed":false, // "filters":[ // {"filterType":"PRICE_FILTER","minPrice":"0.00000001349","maxPrice":"0.00000017537","priceScale":10}, // {"filterType":"LOT_SIZE","minQty":"1.0","minVal":"0.00020","maxQty":"1000000000","volumeScale":0}, // ], // "defaultPrice":"0.0000006100", // }, // ], // "coins":[ // { // "coin":"sbr", // "coinFulName":"Saber", // "enableWithdraw":true, // "enableDeposit":true, // "chains":["SOLANA"], // "withdrawFee":"2.0", // "minWithdraw":"5.0", // "maxWithdraw":"1000000000000000", // }, // ], // } // // swap / delivery // // [ // { // "symbol": "H-HT-USDT", // "pricePrecision": 8, // "side": 1, // "maxMarketVolume": 100000, // "multiplier": 6, // "minOrderVolume": 1, // "maxMarketMoney": 10000000, // "type": "H", // E: perpetual contract, S: test contract, others are mixed contract // "maxLimitVolume": 1000000, // "maxValidOrder": 20, // "multiplierCoin": "HT", // "minOrderMoney": 0.001, // "maxLimitMoney": 1000000, // "status": 1 // } // ] // if (this.options['adjustForTimeDifference']) { await this.loadTimeDifference(); } return this.parseMarkets(markets); } parseMarket(market) { const id = this.safeString(market, 'symbol'); const lowercaseId = this.safeStringLower(market, 'symbol'); const side = this.safeInteger(market, 'side'); // 1 linear, 0 inverse, undefined spot let type = undefined; let isLinear = undefined; let isInverse = undefined; if (side === undefined) { type = 'spot'; } else { type = 'swap'; isLinear = (side === 1); isInverse = (side === 0); } const isContract = (type !== 'spot'); let baseId = this.safeString(market, 'baseAsset'); let quoteId = this.safeString(market, 'quoteAsset'); let settleId = undefined; let settle = undefined; if (isContract) { const symbolSplit = id.split('-'); baseId = this.safeString(symbolSplit, 1); quoteId = this.safeString(symbolSplit, 2); if (isLinear) { settleId = quoteId; } else { settleId = baseId; } settle = this.safeCurrencyCode(settleId); } const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); let symbol = base + '/' + quote; if (settle !== undefined) { symbol += ':' + settle; } const filters = this.safeList(market, 'filters', []); const filtersByType = this.indexBy(filters, 'filterType'); const status = this.safeString(market, 'status'); const priceFilter = this.safeDict(filtersByType, 'PRICE_FILTER', {}); const amountFilter = this.safeDict(filtersByType, 'LOT_SIZE', {}); const defaultPricePrecision = this.safeString(market, 'pricePrecision'); const defaultAmountPrecision = this.safeString(market, 'quantityPrecision'); const pricePrecision = this.safeString(priceFilter, 'priceScale', defaultPricePrecision); const amountPrecision = this.safeString(amountFilter, 'volumeScale', defaultAmountPrecision); const multiplier = this.safeString(market, 'multiplier'); let maxQuantity = this.safeNumber(amountFilter, 'maxQty'); if (maxQuantity === undefined) { maxQuantity = this.safeNumber(market, 'maxValidOrder'); } let minCost = this.safeNumber(amountFilter, 'minVal'); if (minCost === undefined) { minCost = this.safeNumber(market, 'minOrderMoney'); } return { 'id': id, 'lowercaseId': lowercaseId, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': type, 'spot': (type === 'spot'), 'margin': false, 'swap': isContract, 'future': false, 'option': false, 'active': (status === 'TRADING'), 'contract': isContract, 'linear': isLinear, 'inverse': isInverse, 'contractSize': this.parseNumber(Precise.stringAbs(multiplier)), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.parseNumber(this.parsePrecision(amountPrecision)), 'price': this.parseNumber(this.parsePrecision(pricePrecision)), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(amountFilter, 'minQty'), 'max': maxQuantity, }, 'price': { 'min': this.safeNumber(priceFilter, 'minPrice'), 'max': this.safeNumber(priceFilter, 'maxPrice'), }, 'cost': { 'min': minCost, 'max': undefined, }, }, 'created': undefined, 'info': market, }; } parseBalance(response) { // // spot // // { // "makerCommission":0, // "takerCommission":0, // "buyerCommission":0, // "sellerCommission":0, // "updateTime":null, // "balances":[ // {"asset":"sbr","free":"0","locked":"0"}, // {"asset":"ksm","free":"0","locked":"0"}, // {"asset":"neo3s","free":"0","locked":"0"}, // ], // "canTrade":false, // "canWithdraw":false, // "canDeposit":false // } // // swap // // { // "account":[ // { // "marginCoin":"USDT", // "coinPrecious":4, // "accountNormal":1010.4043400372839856, // "accountLock":2.9827889600000006, // "partPositionNormal":0, // "totalPositionNormal":0, // "achievedAmount":0, // "unrealizedAmount":0, // "totalMarginRate":0, // "totalEquity":1010.4043400372839856, // "partEquity":0, // "totalCost":0, // "sumMarginRate":0, // "sumOpenRealizedAmount":0, // "canUseTrialFund":0, // "sumMaintenanceMargin":null, // "futureModel":null, // "positionVos":[] // } // ] // } // const result = { 'info': response, }; const timestamp = this.safeInteger(response, 'updateTime'); const balances = this.safeValue2(response, 'balances', 'account', []); for (let i = 0; i < balances.length; i++) { const balance = balances[i]; const currencyId = this.safeString2(balance, 'asset', 'marginCoin'); const code = this.safeCurrencyCode(currencyId); const account = this.account(); account['free'] = this.safeString2(balance, 'free', 'accountNormal'); account['used'] = this.safeString2(balance, 'locked', 'accountLock'); result[code] = account; } result['timestamp'] = timestamp; result['datetime'] = this.iso8601(timestamp); return this.safeBalance(result); } /** * @method * @name bitrue#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://github.com/Bitrue-exchange/Spot-official-api-docs#account-information-user_data * @see https://www.bitrue.com/api-docs#account-information-v2-user_data-hmac-sha256 * @see https://www.bitrue.com/api_docs_includes_file/delivery.html#account-information-v2-user_data-hmac-sha256 * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.type] 'future', 'delivery', 'spot', 'swap' * @param {string} [params.subType] 'linear', 'inverse' * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ async fetchBalance(params = {}) { await this.loadMarkets(); let type = undefined; [type, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params); let subType = undefined; [subType, params] = this.handleSubTypeAndParams('fetchBalance', undefined, params); let response = undefined; let result = undefined; if (type === 'swap') { if (subType !== undefined && subType === 'inverse') { response = await this.dapiV2PrivateGetAccount(params); result = this.safeDict(response, 'data', {}); // // { // "code":"0", // "msg":"Success", // "data":{ // "account":[ // { // "marginCoin":"USD", // "coinPrecious":4, //