UNPKG

@proton/ccxt

Version:

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

1,188 lines (1,186 loc) 138 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/ascendex.js'; import { ArgumentsRequired, AuthenticationError, ExchangeError, InsufficientFunds, InvalidOrder, BadSymbol, PermissionDenied, BadRequest } from './base/errors.js'; import { Precise } from './base/Precise.js'; import { TICK_SIZE } from './base/functions/number.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; // --------------------------------------------------------------------------- export default class ascendex extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'ascendex', 'name': 'AscendEX', 'countries': ['SG'], // 8 requests per minute = 0.13333 per second => rateLimit = 750 // testing 400 works 'rateLimit': 400, 'certified': false, 'pro': true, // new metainfo interface 'has': { 'CORS': undefined, 'spot': true, 'margin': true, 'swap': true, 'future': true, 'option': false, 'addMargin': true, 'cancelAllOrders': true, 'cancelOrder': true, 'createOrder': true, 'createPostOnlyOrder': true, 'createReduceOnlyOrder': true, 'createStopLimitOrder': true, 'createStopMarketOrder': true, 'createStopOrder': true, 'fetchAccounts': true, 'fetchBalance': true, 'fetchClosedOrders': true, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDepositAddresses': false, 'fetchDepositAddressesByNetwork': false, 'fetchDeposits': true, 'fetchDepositsWithdrawals': true, 'fetchDepositWithdrawFee': 'emulated', 'fetchDepositWithdrawFees': true, 'fetchFundingHistory': false, 'fetchFundingRate': 'emulated', 'fetchFundingRateHistory': false, 'fetchFundingRates': true, 'fetchIndexOHLCV': false, 'fetchLeverage': false, 'fetchLeverageTiers': true, 'fetchMarginMode': false, 'fetchMarketLeverageTiers': 'emulated', 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchOHLCV': true, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': false, 'fetchPosition': false, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransactionFee': false, 'fetchTransactionFees': false, 'fetchTransactions': true, 'fetchTransfer': false, 'fetchTransfers': false, 'fetchWithdrawal': false, 'fetchWithdrawals': true, 'reduceMargin': true, 'setLeverage': true, 'setMarginMode': true, 'setPositionMode': false, 'transfer': true, }, 'timeframes': { '1m': '1', '5m': '5', '15m': '15', '30m': '30', '1h': '60', '2h': '120', '4h': '240', '6h': '360', '12h': '720', '1d': '1d', '1w': '1w', '1M': '1m', }, 'version': 'v2', 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/112027508-47984600-8b48-11eb-9e17-d26459cc36c6.jpg', 'api': { 'rest': 'https://ascendex.com', }, 'test': { 'rest': 'https://api-test.ascendex-sandbox.com', }, 'www': 'https://ascendex.com', 'doc': [ 'https://ascendex.github.io/ascendex-pro-api/#ascendex-pro-api-documentation', ], 'fees': 'https://ascendex.com/en/feerate/transactionfee-traderate', 'referral': { 'url': 'https://ascendex.com/en-us/register?inviteCode=EL6BXBQM', 'discount': 0.25, }, }, 'api': { 'v1': { 'public': { 'get': { 'assets': 1, 'products': 1, 'ticker': 1, 'barhist/info': 1, 'barhist': 1, 'depth': 1, 'trades': 1, 'cash/assets': 1, 'cash/products': 1, 'margin/assets': 1, 'margin/products': 1, 'futures/collateral': 1, 'futures/contracts': 1, 'futures/ref-px': 1, 'futures/market-data': 1, 'futures/funding-rates': 1, 'risk-limit-info': 1, 'exchange-info': 1, }, }, 'private': { 'get': { 'info': 1, 'wallet/transactions': 1, 'wallet/deposit/address': 1, 'data/balance/snapshot': 1, 'data/balance/history': 1, }, 'accountCategory': { 'get': { 'balance': 1, 'order/open': 1, 'order/status': 1, 'order/hist/current': 1, 'risk': 1, }, 'post': { 'order': 1, 'order/batch': 1, }, 'delete': { 'order': 1, 'order/all': 1, 'order/batch': 1, }, }, 'accountGroup': { 'get': { 'cash/balance': 1, 'margin/balance': 1, 'margin/risk': 1, 'futures/collateral-balance': 1, 'futures/position': 1, 'futures/risk': 1, 'futures/funding-payments': 1, 'order/hist': 1, 'spot/fee': 1, }, 'post': { 'transfer': 1, 'futures/transfer/deposit': 1, 'futures/transfer/withdraw': 1, }, }, }, }, 'v2': { 'public': { 'get': { 'assets': 1, 'futures/contract': 1, 'futures/collateral': 1, 'futures/pricing-data': 1, 'futures/ticker': 1, 'risk-limit-info': 1, }, }, 'private': { 'data': { 'get': { 'order/hist': 1, }, }, 'get': { 'account/info': 1, }, 'accountGroup': { 'get': { 'order/hist': 1, 'futures/position': 1, 'futures/free-margin': 1, 'futures/order/hist/current': 1, 'futures/order/open': 1, 'futures/order/status': 1, }, 'post': { 'futures/isolated-position-margin': 1, 'futures/margin-type': 1, 'futures/leverage': 1, 'futures/transfer/deposit': 1, 'futures/transfer/withdraw': 1, 'futures/order': 1, 'futures/order/batch': 1, 'futures/order/open': 1, 'subuser/subuser-transfer': 1, 'subuser/subuser-transfer-hist': 1, }, 'delete': { 'futures/order': 1, 'futures/order/batch': 1, 'futures/order/all': 1, }, }, }, }, }, 'fees': { 'trading': { 'feeSide': 'get', 'tierBased': true, 'percentage': true, 'taker': this.parseNumber('0.002'), 'maker': this.parseNumber('0.002'), }, }, 'precisionMode': TICK_SIZE, 'options': { 'account-category': 'cash', 'account-group': undefined, 'fetchClosedOrders': { 'method': 'v2PrivateDataGetOrderHist', // 'v1PrivateAccountGroupGetAccountCategoryOrderHistCurrent' }, 'defaultType': 'spot', 'accountsByType': { 'spot': 'cash', 'swap': 'futures', 'future': 'futures', 'margin': 'margin', }, 'transfer': { 'fillResponseFromRequest': true, }, 'networks': { 'BSC': 'BEP20 (BSC)', 'ARB': 'arbitrum', 'SOL': 'Solana', 'AVAX': 'avalanche C chain', 'OMNI': 'Omni', }, 'networksById': { 'BEP20 (BSC)': 'BSC', 'arbitrum': 'ARB', 'Solana': 'SOL', 'avalanche C chain': 'AVAX', 'Omni': 'OMNI', }, }, 'exceptions': { 'exact': { // not documented '1900': BadRequest, '2100': AuthenticationError, '5002': BadSymbol, '6001': BadSymbol, '6010': InsufficientFunds, '60060': InvalidOrder, '600503': InvalidOrder, // documented '100001': BadRequest, '100002': BadRequest, '100003': BadRequest, '100004': BadRequest, '100005': BadRequest, '100006': BadRequest, '100007': BadRequest, '100008': BadSymbol, '100009': AuthenticationError, '100010': BadRequest, '100011': BadRequest, '100012': BadRequest, '100013': BadRequest, '100101': ExchangeError, '150001': BadRequest, '200001': AuthenticationError, '200002': ExchangeError, '200003': ExchangeError, '200004': ExchangeError, '200005': ExchangeError, '200006': ExchangeError, '200007': ExchangeError, '200008': ExchangeError, '200009': ExchangeError, '200010': AuthenticationError, '200011': ExchangeError, '200012': ExchangeError, '200013': ExchangeError, '200014': PermissionDenied, '200015': PermissionDenied, '300001': InvalidOrder, '300002': InvalidOrder, '300003': InvalidOrder, '300004': InvalidOrder, '300005': InvalidOrder, '300006': InvalidOrder, '300007': InvalidOrder, '300008': InvalidOrder, '300009': InvalidOrder, '300011': InsufficientFunds, '300012': BadSymbol, '300013': InvalidOrder, '300014': InvalidOrder, '300020': InvalidOrder, '300021': InvalidOrder, '300031': InvalidOrder, '310001': InsufficientFunds, '310002': InvalidOrder, '310003': InvalidOrder, '310004': BadSymbol, '310005': InvalidOrder, '510001': ExchangeError, '900001': ExchangeError, // HUMAN_CHALLENGE Human change do not pass }, 'broad': {}, }, 'commonCurrencies': { 'BOND': 'BONDED', 'BTCBEAR': 'BEAR', 'BTCBULL': 'BULL', 'BYN': 'BeyondFi', 'PLN': 'Pollen', }, }); } getAccount(params = {}) { // get current or provided bitmax sub-account const account = this.safeValue(params, 'account', this.options['account']); const lowercaseAccount = account.toLowerCase(); return this.capitalize(lowercaseAccount); } async fetchCurrencies(params = {}) { /** * @method * @name ascendex#fetchCurrencies * @description fetches all available currencies on an exchange * @param {object} params extra parameters specific to the ascendex api endpoint * @returns {object} an associative dictionary of currencies */ const assets = await this.v1PublicGetAssets(params); // // { // "code":0, // "data":[ // { // "assetCode" : "LTCBULL", // "assetName" : "3X Long LTC Token", // "precisionScale" : 9, // "nativeScale" : 4, // "withdrawalFee" : "0.2", // "minWithdrawalAmt" : "1.0", // "status" : "Normal" // }, // ] // } // const margin = await this.v1PublicGetMarginAssets(params); // // { // "code":0, // "data":[ // { // "assetCode":"BTT", // "borrowAssetCode":"BTT-B", // "interestAssetCode":"BTT-I", // "nativeScale":0, // "numConfirmations":1, // "withdrawFee":"100.0", // "minWithdrawalAmt":"1000.0", // "statusCode":"Normal", // "statusMessage":"", // "interestRate":"0.001" // } // ] // } // const cash = await this.v1PublicGetCashAssets(params); // // { // "code":0, // "data":[ // { // "assetCode":"LTCBULL", // "nativeScale":4, // "numConfirmations":20, // "withdrawFee":"0.2", // "minWithdrawalAmt":"1.0", // "statusCode":"Normal", // "statusMessage":"" // } // ] // } // const assetsData = this.safeValue(assets, 'data', []); const marginData = this.safeValue(margin, 'data', []); const cashData = this.safeValue(cash, 'data', []); const assetsById = this.indexBy(assetsData, 'assetCode'); const marginById = this.indexBy(marginData, 'assetCode'); const cashById = this.indexBy(cashData, 'assetCode'); const dataById = this.deepExtend(assetsById, marginById, cashById); const ids = Object.keys(dataById); const result = {}; for (let i = 0; i < ids.length; i++) { const id = ids[i]; const currency = dataById[id]; const code = this.safeCurrencyCode(id); const scale = this.safeString2(currency, 'precisionScale', 'nativeScale'); const precision = this.parseNumber(this.parsePrecision(scale)); const fee = this.safeNumber2(currency, 'withdrawFee', 'withdrawalFee'); const status = this.safeString2(currency, 'status', 'statusCode'); const active = (status === 'Normal'); const marginInside = ('borrowAssetCode' in currency); result[code] = { 'id': id, 'code': code, 'info': currency, 'type': undefined, 'margin': marginInside, 'name': this.safeString(currency, 'assetName'), 'active': active, 'deposit': undefined, 'withdraw': undefined, 'fee': fee, 'precision': precision, 'limits': { 'amount': { 'min': precision, 'max': undefined, }, 'withdraw': { 'min': this.safeNumber(currency, 'minWithdrawalAmt'), 'max': undefined, }, }, 'networks': {}, }; } return result; } async fetchMarkets(params = {}) { /** * @method * @name ascendex#fetchMarkets * @description retrieves data on all markets for ascendex * @param {object} params extra parameters specific to the exchange api endpoint * @returns {[object]} an array of objects representing market data */ const products = await this.v1PublicGetProducts(params); // // { // "code": 0, // "data": [ // { // "symbol": "LBA/BTC", // "baseAsset": "LBA", // "quoteAsset": "BTC", // "status": "Normal", // "minNotional": "0.000625", // "maxNotional": "6.25", // "marginTradable": false, // "commissionType": "Quote", // "commissionReserveRate": "0.001", // "tickSize": "0.000000001", // "lotSize": "1" // }, // ] // } // const cash = await this.v1PublicGetCashProducts(params); // // { // "code": 0, // "data": [ // { // "symbol": "QTUM/BTC", // "displayName": "QTUM/BTC", // "domain": "BTC", // "tradingStartTime": 1569506400000, // "collapseDecimals": "0.0001,0.000001,0.00000001", // "minQty": "0.000000001", // "maxQty": "1000000000", // "minNotional": "0.000625", // "maxNotional": "12.5", // "statusCode": "Normal", // "statusMessage": "", // "tickSize": "0.00000001", // "useTick": false, // "lotSize": "0.1", // "useLot": false, // "commissionType": "Quote", // "commissionReserveRate": "0.001", // "qtyScale": 1, // "priceScale": 8, // "notionalScale": 4 // } // ] // } // const perpetuals = await this.v2PublicGetFuturesContract(params); // // { // "code": 0, // "data": [ // { // "symbol": "BTC-PERP", // "status": "Normal", // "displayName": "BTCUSDT", // "settlementAsset": "USDT", // "underlying": "BTC/USDT", // "tradingStartTime": 1579701600000, // "priceFilter": { // "minPrice": "1", // "maxPrice": "1000000", // "tickSize": "1" // }, // "lotSizeFilter": { // "minQty": "0.0001", // "maxQty": "1000000000", // "lotSize": "0.0001" // }, // "commissionType": "Quote", // "commissionReserveRate": "0.001", // "marketOrderPriceMarkup": "0.03", // "marginRequirements": [ // { // "positionNotionalLowerBound": "0", // "positionNotionalUpperBound": "50000", // "initialMarginRate": "0.01", // "maintenanceMarginRate": "0.006" // }, // ... // ] // } // ] // } // const productsData = this.safeValue(products, 'data', []); const productsById = this.indexBy(productsData, 'symbol'); const cashData = this.safeValue(cash, 'data', []); const perpetualsData = this.safeValue(perpetuals, 'data', []); const cashAndPerpetualsData = this.arrayConcat(cashData, perpetualsData); const cashAndPerpetualsById = this.indexBy(cashAndPerpetualsData, 'symbol'); const dataById = this.deepExtend(productsById, cashAndPerpetualsById); const ids = Object.keys(dataById); const result = []; for (let i = 0; i < ids.length; i++) { const id = ids[i]; const market = dataById[id]; const settleId = this.safeValue(market, 'settlementAsset'); const settle = this.safeCurrencyCode(settleId); const status = this.safeString(market, 'status'); const domain = this.safeString(market, 'domain'); let active = false; if (((status === 'Normal') || (status === 'InternalTrading')) && (domain !== 'LeveragedETF')) { active = true; } const spot = settle === undefined; const swap = !spot; const linear = swap ? true : undefined; let minQty = this.safeNumber(market, 'minQty'); let maxQty = this.safeNumber(market, 'maxQty'); let minPrice = this.safeNumber(market, 'tickSize'); let maxPrice = undefined; const underlying = this.safeString2(market, 'underlying', 'symbol'); const parts = underlying.split('/'); const baseId = this.safeString(parts, 0); const quoteId = this.safeString(parts, 1); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); let symbol = base + '/' + quote; if (swap) { const lotSizeFilter = this.safeValue(market, 'lotSizeFilter'); minQty = this.safeNumber(lotSizeFilter, 'minQty'); maxQty = this.safeNumber(lotSizeFilter, 'maxQty'); const priceFilter = this.safeValue(market, 'priceFilter'); minPrice = this.safeNumber(priceFilter, 'minPrice'); maxPrice = this.safeNumber(priceFilter, 'maxPrice'); symbol = base + '/' + quote + ':' + settle; } const fee = this.safeNumber(market, 'commissionReserveRate'); const marginTradable = this.safeValue(market, 'marginTradable', false); result.push({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': swap ? 'swap' : 'spot', 'spot': spot, 'margin': spot ? marginTradable : undefined, 'swap': swap, 'future': false, 'option': false, 'active': active, 'contract': swap, 'linear': linear, 'inverse': swap ? !linear : undefined, 'taker': fee, 'maker': fee, 'contractSize': swap ? this.parseNumber('1') : undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber(market, 'lotSize'), 'price': this.safeNumber(market, 'tickSize'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': minQty, 'max': maxQty, }, 'price': { 'min': minPrice, 'max': maxPrice, }, 'cost': { 'min': this.safeNumber(market, 'minNotional'), 'max': this.safeNumber(market, 'maxNotional'), }, }, 'info': market, }); } return result; } async fetchTime(params = {}) { /** * @method * @name ascendex#fetchTime * @description fetches the current integer timestamp in milliseconds from the ascendex server * @param {object} params extra parameters specific to the ascendex api endpoint * @returns {int} the current integer timestamp in milliseconds from the ascendex server */ const request = { 'requestTime': this.milliseconds(), }; const response = await this.v1PublicGetExchangeInfo(this.extend(request, params)); // // { // "code": 0, // "data": { // "requestTimeEcho": 1656560463601, // "requestReceiveAt": 1656560464331, // "latency": 730 // } // } // const data = this.safeValue(response, 'data'); return this.safeInteger(data, 'requestReceiveAt'); } async fetchAccounts(params = {}) { /** * @method * @name ascendex#fetchAccounts * @description fetch all the accounts associated with a profile * @param {object} params extra parameters specific to the ascendex api endpoint * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type */ let accountGroup = this.safeString(this.options, 'account-group'); let response = undefined; if (accountGroup === undefined) { response = await this.v1PrivateGetInfo(params); // // { // "code":0, // "data":{ // "email":"igor.kroitor@gmail.com", // "accountGroup":8, // "viewPermission":true, // "tradePermission":true, // "transferPermission":true, // "cashAccount":["cshrHKLZCjlZ2ejqkmvIHHtPmLYqdnda"], // "marginAccount":["martXoh1v1N3EMQC5FDtSj5VHso8aI2Z"], // "futuresAccount":["futc9r7UmFJAyBY2rE3beA2JFxav2XFF"], // "userUID":"U6491137460" // } // } // const data = this.safeValue(response, 'data', {}); accountGroup = this.safeString(data, 'accountGroup'); this.options['account-group'] = accountGroup; } return [ { 'id': accountGroup, 'type': undefined, 'currency': undefined, 'info': response, }, ]; } parseBalance(response) { const timestamp = this.milliseconds(); const result = { 'info': response, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), }; const balances = this.safeValue(response, 'data', []); for (let i = 0; i < balances.length; i++) { const balance = balances[i]; const code = this.safeCurrencyCode(this.safeString(balance, 'asset')); const account = this.account(); account['free'] = this.safeString(balance, 'availableBalance'); account['total'] = this.safeString(balance, 'totalBalance'); result[code] = account; } return this.safeBalance(result); } parseMarginBalance(response) { const timestamp = this.milliseconds(); const result = { 'info': response, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), }; const balances = this.safeValue(response, 'data', []); for (let i = 0; i < balances.length; i++) { const balance = balances[i]; const code = this.safeCurrencyCode(this.safeString(balance, 'asset')); const account = this.account(); account['free'] = this.safeString(balance, 'availableBalance'); account['total'] = this.safeString(balance, 'totalBalance'); const debt = this.safeString(balance, 'borrowed'); const interest = this.safeString(balance, 'interest'); account['debt'] = Precise.stringAdd(debt, interest); result[code] = account; } return this.safeBalance(result); } parseSwapBalance(response) { const timestamp = this.milliseconds(); const result = { 'info': response, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), }; const data = this.safeValue(response, 'data', {}); const collaterals = this.safeValue(data, 'collaterals', []); for (let i = 0; i < collaterals.length; i++) { const balance = collaterals[i]; const code = this.safeCurrencyCode(this.safeString(balance, 'asset')); const account = this.account(); account['total'] = this.safeString(balance, 'balance'); result[code] = account; } return this.safeBalance(result); } async fetchBalance(params = {}) { /** * @method * @name ascendex#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @param {object} params extra parameters specific to the ascendex api endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure} */ await this.loadMarkets(); await this.loadAccounts(); let query = undefined; let marketType = undefined; [marketType, query] = this.handleMarketTypeAndParams('fetchBalance', undefined, params); const isMargin = this.safeValue(params, 'margin', false); marketType = isMargin ? 'margin' : marketType; params = this.omit(params, 'margin'); const options = this.safeValue(this.options, 'fetchBalance', {}); const accountsByType = this.safeValue(this.options, 'accountsByType', {}); const accountCategory = this.safeString(accountsByType, marketType, 'cash'); const account = this.safeValue(this.accounts, 0, {}); const accountGroup = this.safeString(account, 'id'); const request = { 'account-group': accountGroup, }; const defaultMethod = this.safeString(options, 'method', 'v1PrivateAccountCategoryGetBalance'); const method = this.getSupportedMapping(marketType, { 'spot': defaultMethod, 'margin': defaultMethod, 'swap': 'v2PrivateAccountGroupGetFuturesPosition', }); if ((accountCategory === 'cash') || (accountCategory === 'margin')) { request['account-category'] = accountCategory; } const response = await this[method](this.extend(request, query)); // // cash // // { // 'code': 0, // 'data': [ // { // 'asset': 'BCHSV', // 'totalBalance': '64.298000048', // 'availableBalance': '64.298000048', // }, // ] // } // // margin // // { // 'code': 0, // 'data': [ // { // 'asset': 'BCHSV', // 'totalBalance': '64.298000048', // 'availableBalance': '64.298000048', // 'borrowed': '0', // 'interest': '0', // }, // ] // } // // swap // // { // "code": 0, // "data": { // "accountId": "fut2ODPhGiY71Pl4vtXnOZ00ssgD7QGn", // "ac": "FUTURES", // "collaterals": [ // {"asset":"ADA","balance":"0.355803","referencePrice":"1.05095","discountFactor":"0.9"}, // {"asset":"USDT","balance":"0.000014519","referencePrice":"1","discountFactor":"1"} // ], // }j // } // if (marketType === 'swap') { return this.parseSwapBalance(response); } else if (marketType === 'margin') { return this.parseMarginBalance(response); } else { return this.parseBalance(response); } } async fetchOrderBook(symbol, limit = undefined, params = {}) { /** * @method * @name ascendex#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 ascendex 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 = { 'symbol': market['id'], }; const response = await this.v1PublicGetDepth(this.extend(request, params)); // // { // "code":0, // "data":{ // "m":"depth-snapshot", // "symbol":"BTC-PERP", // "data":{ // "ts":1590223998202, // "seqnum":115444921, // "asks":[ // ["9207.5","18.2383"], // ["9207.75","18.8235"], // ["9208","10.7873"], // ], // "bids":[ // ["9207.25","0.4009"], // ["9207","0.003"], // ["9206.5","0.003"], // ] // } // } // } // const data = this.safeValue(response, 'data', {}); const orderbook = this.safeValue(data, 'data', {}); const timestamp = this.safeInteger(orderbook, 'ts'); const result = this.parseOrderBook(orderbook, symbol, timestamp); result['nonce'] = this.safeInteger(orderbook, 'seqnum'); return result; } parseTicker(ticker, market = undefined) { // // { // "symbol":"QTUM/BTC", // "open":"0.00016537", // "close":"0.00019077", // "high":"0.000192", // "low":"0.00016537", // "volume":"846.6", // "ask":["0.00018698","26.2"], // "bid":["0.00018408","503.7"], // "type":"spot" // } // const timestamp = undefined; const marketId = this.safeString(ticker, 'symbol'); const type = this.safeString(ticker, 'type'); const delimiter = (type === 'spot') ? '/' : undefined; const symbol = this.safeSymbol(marketId, market, delimiter); const close = this.safeString(ticker, 'close'); const bid = this.safeValue(ticker, 'bid', []); const ask = this.safeValue(ticker, 'ask', []); const open = this.safeString(ticker, 'open'); return this.safeTicker({ 'symbol': symbol, 'timestamp': timestamp, 'datetime': undefined, 'high': this.safeString(ticker, 'high'), 'low': this.safeString(ticker, 'low'), 'bid': this.safeString(bid, 0), 'bidVolume': this.safeString(bid, 1), 'ask': this.safeString(ask, 0), 'askVolume': this.safeString(ask, 1), 'vwap': undefined, 'open': open, 'close': close, 'last': close, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': undefined, 'baseVolume': this.safeString(ticker, 'volume'), 'quoteVolume': undefined, 'info': ticker, }, market); } async fetchTicker(symbol, params = {}) { /** * @method * @name ascendex#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 ascendex 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 = { 'symbol': market['id'], }; const response = await this.v1PublicGetTicker(this.extend(request, params)); // // { // "code":0, // "data":{ // "symbol":"BTC-PERP", // or "BTC/USDT" // "open":"9073", // "close":"9185.75", // "high":"9185.75", // "low":"9185.75", // "volume":"576.8334", // "ask":["9185.75","15.5863"], // "bid":["9185.5","0.003"], // "type":"derivatives", // or "spot" // } // } // const data = this.safeValue(response, 'data', {}); return this.parseTicker(data, market); } async fetchTickers(symbols = undefined, params = {}) { /** * @method * @name ascendex#fetchTickers * @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market * @see https://ascendex.github.io/ascendex-pro-api/#ticker * @see https://ascendex.github.io/ascendex-futures-pro-api-v2/#ticker * @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 ascendex api endpoint * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ await this.loadMarkets(); const request = {}; let market = undefined; if (symbols !== undefined) { const symbol = this.safeValue(symbols, 0); market = this.market(symbol); const marketIds = this.marketIds(symbols); request['symbol'] = marketIds.join(','); } let type = undefined; [type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params); let response = undefined; if (type === 'spot') { response = await this.v1PublicGetTicker(this.extend(request, params)); } else { response = await this.v2PublicGetFuturesTicker(this.extend(request, params)); } // // { // "code":0, // "data":[ // { // "symbol":"QTUM/BTC", // "open":"0.00016537", // "close":"0.00019077", // "high":"0.000192", // "low":"0.00016537", // "volume":"846.6", // "ask":["0.00018698","26.2"], // "bid":["0.00018408","503.7"], // "type":"spot" // } // ] // } // const data = this.safeValue(response, 'data', []); if (!Array.isArray(data)) { return this.parseTickers([data], symbols); } return this.parseTickers(data, symbols); } parseOHLCV(ohlcv, market = undefined) { // // { // "m":"bar", // "s":"BTC/USDT", // "data":{ // "i":"1", // "ts":1590228000000, // "o":"9139.59", // "c":"9131.94", // "h":"9139.99", // "l":"9121.71", // "v":"25.20648" // } // } // const data = this.safeValue(ohlcv, 'data', {}); return [ this.safeInteger(data, 'ts'), this.safeNumber(data, 'o'), this.safeNumber(data, 'h'), this.safeNumber(data, 'l'), this.safeNumber(data, 'c'), this.safeNumber(data, 'v'), ]; } async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { /** * @method * @name ascendex#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 ascendex 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 = { 'symbol': market['id'], 'interval': this.safeString(this.timeframes, timeframe, timeframe), }; // if since and limit are not specified // the exchange will return just 1 last candle by default const duration = this.parseTimeframe(timeframe); const options = this.safeValue(this.options, 'fetchOHLCV', {}); const defaultLimit = this.safeInteger(options, 'limit', 500); if (since !== undefined) { request['from'] = since; if (limit === undefined) { limit = defaultLimit; } else { limit = Math.min(limit, defaultLimit); } request['to'] = this.sum(since, limit * duration * 1000, 1); } else if (limit !== undefined) { request['n'] = limit; // max 500 } const response = await this.v1PublicGetBarhist(this.extend(request, params)); // // { // "code":0, // "data":[ // { // "m":"bar", // "s":"BTC/USDT", // "data":{ // "i":"1", // "ts":1590228000000, // "o":"9139.59", // "c":"9131.94", // "h":"9139.99", // "l":"9121.71", // "v":"25.20648" // } // } // ] // } // const data = this.safeValue(response, 'data', []); return this.parseOHLCVs(data, market, timeframe, since, limit); } parseTrade(trade, market = undefined) { // // public fetchTrades // // { // "p":"9128.5", // price // "q":"0.0030", // quantity // "ts":1590229002385, // timestamp // "bm":false, // if true, the buyer is the market maker, we only use this field to "define the side" of a public trade // "seqnum":180143985289898554 // } // const timestamp = this.safeInteger(trade, 'ts'); const priceString = this.safeString2(trade, 'price', 'p'); const amountString = this.safeString(trade, 'q'); const buyerIsMaker = this.safeValue(trade, 'bm', false); const side = buyerIsMaker ? 'sell' : 'buy'; market = this.safeMarket(undefined, market); return this.safeTrade({ 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': market['symbol'], 'id': undefined, 'order': undefined, 'type': undefined, 'takerOrMaker': undefined, 'side': side, 'price': priceString, 'amount': amountString, 'cost': undefined, 'fee': undefined, }, market); } async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { /** * @method * @name ascendex#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://ascendex.github.io/ascendex-pro-api/#market-trades * @param {string} symbol unified symbol of the market to fetch trades for * @param {int|undefined} since timestamp in ms of the earliest trade to