UNPKG

ccxt

Version:

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

1,189 lines (1,187 loc) • 164 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, AccountSuspended, InsufficientFunds, InvalidOrder, BadSymbol, PermissionDenied, BadRequest, NotSupported } 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'; // --------------------------------------------------------------------------- /** * @class ascendex * @augments Exchange */ 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': false, 'option': false, 'addMargin': true, 'cancelAllOrders': true, 'cancelOrder': true, 'createOrder': true, 'createOrders': 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': true, 'fetchFundingRate': 'emulated', 'fetchFundingRateHistory': false, 'fetchFundingRates': true, 'fetchGreeks': false, 'fetchIndexOHLCV': false, 'fetchLeverage': 'emulated', 'fetchLeverages': true, 'fetchLeverageTiers': true, 'fetchMarginMode': 'emulated', 'fetchMarginModes': true, 'fetchMarketLeverageTiers': 'emulated', 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMySettlementHistory': false, 'fetchOHLCV': true, 'fetchOpenInterest': false, 'fetchOpenInterestHistory': false, 'fetchOpenOrders': true, 'fetchOption': false, 'fetchOptionChain': false, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': false, 'fetchPosition': false, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchSettlementHistory': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransactionFee': false, 'fetchTransactionFees': false, 'fetchTransactions': 'emulated', 'fetchTransfer': false, 'fetchTransfers': false, 'fetchVolatilityHistory': false, 'fetchWithdrawal': false, 'fetchWithdrawals': true, 'reduceMargin': true, 'sandbox': 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://github.com/user-attachments/assets/55bab6b9-d4ca-42a8-a0e6-fac81ae557f1', '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/funding-payments': 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', // 'v1PrivateAccountCategoryGetOrderHistCurrent' }, 'defaultType': 'spot', 'accountsByType': { 'spot': 'cash', 'swap': 'futures', 'margin': 'margin', }, 'transfer': { 'fillResponseFromRequest': true, }, 'networks': { 'BSC': 'BEP20 ' + '(BSC)', 'ARB': 'arbitrum', 'SOL': 'Solana', 'AVAX': 'avalanche C chain', 'OMNI': 'Omni', // 'TRC': 'TRC20', 'TRC20': 'TRC20', 'ERC20': 'ERC20', 'GO20': 'GO20', 'BEP2': 'BEP2', 'BTC': 'Bitcoin', 'BCH': 'Bitcoin ABC', 'LTC': 'Litecoin', 'MATIC': 'Matic Network', 'AKT': 'Akash', }, }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': true, 'triggerPrice': true, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': false, 'leverage': false, 'marketBuyRequiresPrice': false, 'marketBuyByCost': false, 'selfTradePrevention': false, 'iceberg': false, }, 'createOrders': { 'max': 10, }, 'fetchMyTrades': undefined, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'marketType': true, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'marketType': true, 'symbolRequired': false, }, 'fetchOrders': undefined, 'fetchClosedOrders': undefined, 'fetchOHLCV': { 'limit': 500, }, }, 'spot': { 'extends': 'default', 'fetchClosedOrders': { 'marginMode': false, 'limit': 1000, 'daysBack': 100000, 'daysBackCanceled': 1, 'untilDays': 100000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, }, 'forDerivatives': { 'extends': 'default', 'createOrder': { // todo: implementation 'attachedStopLossTakeProfit': { 'triggerPriceType': { 'last': true, 'mark': false, 'index': false, }, 'price': false, }, }, 'fetchClosedOrders': { 'marginMode': false, 'limit': 1000, 'daysBack': undefined, 'daysBackCanceled': undefined, 'untilDays': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, }, 'swap': { 'linear': { 'extends': 'forDerivatives', }, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, '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': AccountSuspended, '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': { 'XBT': 'XBT', '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); } /** * @method * @name ascendex#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.v2PublicGetAssets(params); // // { // "code": "0", // "data": [ // { // "assetCode": "USDT", // "assetName": "Tether", // "precisionScale": 9, // "nativeScale": 4, // "blockChain": [ // { // "chainName": "Solana", // "withdrawFee": "2.0", // "allowDeposit": true, // "allowWithdraw": true, // "minDepositAmt": "0.01", // "minWithdrawal": "4.0", // "numConfirmations": 1 // }, // ... // ] // }, // ] // } // const data = this.safeList(response, 'data', []); const result = {}; for (let i = 0; i < data.length; i++) { const currency = data[i]; const id = this.safeString(currency, 'assetCode'); const code = this.safeCurrencyCode(id); const chains = this.safeList(currency, 'blockChain', []); const precision = this.parseNumber(this.parsePrecision(this.safeString(currency, 'nativeScale'))); const networks = {}; for (let j = 0; j < chains.length; j++) { const networkEtnry = chains[j]; const networkId = this.safeString(networkEtnry, 'chainName'); const networkCode = this.networkCodeToId(networkId); networks[networkCode] = { 'fee': this.safeNumber(networkEtnry, 'withdrawFee'), 'active': undefined, 'withdraw': this.safeBool(networkEtnry, 'allowWithdraw'), 'deposit': this.safeBool(networkEtnry, 'allowDeposit'), 'precision': precision, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': this.safeNumber(networkEtnry, 'minWithdrawal'), 'max': undefined, }, 'deposit': { 'min': this.safeNumber(networkEtnry, 'minDepositAmt'), 'max': undefined, }, }, }; } // todo type: if (chainsLength === 0 && (assetName.endsWith (' Staking') || assetName.indexOf (' Reward ') >= 0 || assetName.indexOf ('Slot Auction') >= 0 || assetName.indexOf (' Freeze Asset') >= 0)) result[code] = this.safeCurrencyStructure({ 'id': id, 'code': code, 'info': currency, 'type': undefined, 'margin': undefined, 'name': this.safeString(currency, 'assetName'), 'active': undefined, 'deposit': undefined, 'withdraw': undefined, 'fee': undefined, 'precision': precision, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': this.safeNumber(currency, 'minWithdrawalAmt'), 'max': undefined, }, }, 'networks': networks, }); } return result; } /** * @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 */ async fetchMarkets(params = {}) { const spotPromise = this.fetchSpotMarkets(params); const contractPromise = this.fetchContractMarkets(params); const [spotMarkets, contractMarkets] = await Promise.all([spotPromise, contractPromise]); return this.arrayConcat(spotMarkets, contractMarkets); } async fetchSpotMarkets(params = {}) { const productsPromise = 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 cashPromise = 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 [products, cash] = await Promise.all([productsPromise, cashPromise]); const productsData = this.safeList(products, 'data', []); const productsById = this.indexBy(productsData, 'symbol'); const cashData = this.safeList(cash, 'data', []); const cashAndPerpetualsById = this.indexBy(cashData, '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]; if (id.indexOf('-PERP') >= 0) { continue; // skip perpetuals, as separate endpoint returns them } const market = dataById[id]; 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 minQty = this.safeNumber(market, 'minQty'); const maxQty = this.safeNumber(market, 'maxQty'); const minPrice = this.safeNumber(market, 'tickSize'); const 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); const fee = this.safeNumber(market, 'commissionReserveRate'); const marginTradable = this.safeBool(market, 'marginTradable', false); result.push({ 'id': id, 'symbol': base + '/' + quote, 'base': base, 'baseId': baseId, 'quote': quote, 'quoteId': quoteId, 'settle': undefined, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': marginTradable, 'swap': false, 'future': false, 'option': false, 'active': active, 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': fee, 'maker': fee, 'contractSize': 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'), }, }, 'created': this.safeInteger(market, 'tradingStartTime'), 'info': market, }); } return result; } async fetchContractMarkets(params = {}) { const contracts = await this.v2PublicGetFuturesContract(params); // // { // "code": 0, // "data": [ // { // "symbol": "BTC-PERP", // "status": "Normal", // "displayName": "BTCUSDT", // "settlementAsset": "USDT", // "underlying": "BTC/USDT", // "tradingStartTime": 1579701600000, // "priceFilter": { // "minPrice": "0.1", // "maxPrice": "1000000", // "tickSize": "0.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 data = this.safeList(contracts, 'data', []); const result = []; for (let i = 0; i < data.length; i++) { const market = data[i]; const id = this.safeString(market, 'symbol'); const underlying = this.safeString(market, 'underlying'); const parts = underlying.split('/'); const baseId = this.safeString(parts, 0); const base = this.safeCurrencyCode(baseId); const quoteId = this.safeString(parts, 1); const quote = this.safeCurrencyCode(quoteId); const settleId = this.safeString(market, 'settlementAsset'); const settle = this.safeCurrencyCode(settleId); const linear = settle === quote; const inverse = settle === base; const symbol = base + '/' + quote + ':' + settle; const priceFilter = this.safeDict(market, 'priceFilter'); const lotSizeFilter = this.safeDict(market, 'lotSizeFilter'); const fee = this.safeNumber(market, 'commissionReserveRate'); result.push({ 'id': id, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': 'swap', 'spot': false, 'margin': undefined, 'swap': true, 'future': false, 'option': false, 'active': this.safeString(market, 'status') === 'Normal', 'contract': true, 'linear': linear, 'inverse': inverse, 'taker': fee, 'maker': fee, 'contractSize': this.parseNumber('1'), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber(lotSizeFilter, 'lotSize'), 'price': this.safeNumber(priceFilter, 'tickSize'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(lotSizeFilter, 'minQty'), 'max': this.safeNumber(lotSizeFilter, 'maxQty'), }, 'price': { 'min': this.safeNumber(priceFilter, 'minPrice'), 'max': this.safeNumber(priceFilter, 'maxPrice'), }, 'cost': { 'min': this.safeNumber(market, 'minNotional'), 'max': this.safeNumber(market, 'maxNotional'), }, }, 'created': this.safeInteger(market, 'tradingStartTime'), 'info': market, }); } return result; } /** * @method * @name ascendex#fetchTime * @description fetches the current integer timestamp in milliseconds from the ascendex server * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {int} the current integer timestamp in milliseconds from the ascendex server */ async fetchTime(params = {}) { 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.safeDict(response, 'data', {}); return this.safeInteger(data, 'requestReceiveAt'); } /** * @method * @name ascendex#fetchAccounts * @description fetch all the accounts associated with a profile * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type */ async fetchAccounts(params = {}) { 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.safeDict(response, 'data', {}); accountGroup = this.safeString(data, 'accountGroup'); this.options['account-group'] = accountGroup; } return [ { 'id': accountGroup, 'type': undefined, 'code': undefined, 'info': response, }, ]; } parseBalance(response) { const result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; const balances = this.safeList(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 result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; const balances = this.safeList(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 result = { 'info': response, 'timestamp': undefined, 'datetime': undefined, }; const data = this.safeDict(response, 'data', {}); const collaterals = this.safeList(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); } /** * @method * @name ascendex#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://ascendex.github.io/ascendex-pro-api/#cash-account-balance * @see https://ascendex.github.io/ascendex-pro-api/#margin-account-balance * @see https://ascendex.github.io/ascendex-futures-pro-api-v2/#position * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {string} [params.type] wallet type, 'spot', 'margin', or 'swap' * @param {string} [params.marginMode] 'cross' or undefined, for spot margin trading, value of 'isolated' is invalid * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ async fetchBalance(params = {}) { await this.loadMarkets(); await this.loadAccounts(); let marketType = undefined; let marginMode = undefined; [marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params); [marginMode, params] = this.handleMarginModeAndParams('fetchBalance', params); const isMargin = this.safeBool(params, 'margin', false); const isCross = marginMode === 'cross'; marketType = (isMargin || isCross) ? 'margin' : marketType; params = this.omit(params, 'margin'); const accountsByType = this.safeDict(this.options, 'accountsByType', {}); const accountCategory = this.safeString(accountsByType, marketType, 'cash'); const account = this.safeDict(this.accounts, 0, {}); const accountGroup = this.safeString(account, 'id'); const request = { 'account-group': accountGroup, }; if ((marginMode === 'isolated') && (marketType !== 'swap')) { throw new BadRequest(this.id + ' does not supported isolated margin trading'); } if ((accountCategory === 'cash') || (accountCategory === 'margin')) { request['account-category'] = accountCategory; } let response = undefined; if ((marketType === 'spot') || (marketType === 'margin')) { response = await this.v1PrivateAccountCategoryGetBalance(this.extend(request, params)); } else if (marketType === 'swap') { response = await this.v2PrivateAccountGroupGetFuturesPosition(this.extend(request, params)); } else { throw new NotSupported(this.id + ' fetchBalance() is not currently supported for ' + marketType + ' markets'); } // // 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); } } /** * @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} [limit] the maximum amount of order book entries to return * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols */ async fetchOrderBook(symbol, limit = undefined, params = {}) { 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.safeDict(response, 'data', {}); const orderbook = this.safeDict(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.safeList(ticker, 'bid', []); const ask = this.safeList(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); } /** * @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 exchange API endpoint * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTicker(symbol, params = {}) { 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.safeDict(response, 'data