UNPKG

ccxt

Version:

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

1,160 lines (1,158 loc) • 78.7 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/cex.js'; import { ExchangeError, ArgumentsRequired, NullResponse, PermissionDenied, InsufficientFunds, BadRequest, AuthenticationError } 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 cex * @augments Exchange */ export default class cex extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'cex', 'name': 'CEX.IO', 'countries': ['GB', 'EU', 'CY', 'RU'], 'rateLimit': 300, 'pro': true, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'borrowCrossMargin': false, 'borrowIsolatedMargin': false, 'borrowMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'closeAllPositions': false, 'closePosition': false, 'createOrder': true, 'createOrderWithTakeProfitAndStopLoss': false, 'createOrderWithTakeProfitAndStopLossWs': false, 'createPostOnlyOrder': false, 'createReduceOnlyOrder': false, 'createStopOrder': true, 'createTriggerOrder': true, 'fetchAccounts': true, 'fetchBalance': true, 'fetchBorrowInterest': false, 'fetchBorrowRate': false, 'fetchBorrowRateHistories': false, 'fetchBorrowRateHistory': false, 'fetchBorrowRates': false, 'fetchBorrowRatesPerSymbol': false, 'fetchClosedOrder': true, 'fetchClosedOrders': true, 'fetchCrossBorrowRate': false, 'fetchCrossBorrowRates': false, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDepositsWithdrawals': true, 'fetchFundingHistory': false, 'fetchFundingInterval': false, 'fetchFundingIntervals': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchGreeks': false, 'fetchIndexOHLCV': false, 'fetchIsolatedBorrowRate': false, 'fetchIsolatedBorrowRates': false, 'fetchIsolatedPositions': false, 'fetchLedger': true, '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, 'fetchOHLCV': true, 'fetchOpenInterest': false, 'fetchOpenInterestHistory': false, 'fetchOpenInterests': false, 'fetchOpenOrder': true, 'fetchOpenOrders': true, 'fetchOption': false, 'fetchOptionChain': false, 'fetchOrderBook': true, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsForSymbol': false, 'fetchPositionsHistory': false, 'fetchPositionsRisk': false, 'fetchPremiumIndexOHLCV': false, 'fetchSettlementHistory': false, 'fetchTicker': true, 'fetchTickers': true, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFees': true, 'fetchVolatilityHistory': false, 'reduceMargin': false, 'repayCrossMargin': false, 'repayIsolatedMargin': false, 'repayMargin': false, 'setLeverage': false, 'setMargin': false, 'setMarginMode': false, 'setPositionMode': false, 'transfer': true, }, 'urls': { 'logo': 'https://user-images.githubusercontent.com/1294454/27766442-8ddc33b0-5ed8-11e7-8b98-f786aef0f3c9.jpg', 'api': { 'public': 'https://trade.cex.io/api/spot/rest-public', 'private': 'https://trade.cex.io/api/spot/rest', }, 'www': 'https://cex.io', 'doc': 'https://trade.cex.io/docs/', 'fees': [ 'https://cex.io/fee-schedule', 'https://cex.io/limits-commissions', ], 'referral': 'https://cex.io/r/0/up105393824/0/', }, 'api': { 'public': { 'get': {}, 'post': { 'get_server_time': 1, 'get_pairs_info': 1, 'get_currencies_info': 1, 'get_processing_info': 10, 'get_ticker': 1, 'get_trade_history': 1, 'get_order_book': 1, 'get_candles': 1, }, }, 'private': { 'get': {}, 'post': { 'get_my_current_fee': 5, 'get_fee_strategy': 1, 'get_my_volume': 5, 'do_create_account': 1, 'get_my_account_status_v3': 5, 'get_my_wallet_balance': 5, 'get_my_orders': 5, 'do_my_new_order': 1, 'do_cancel_my_order': 1, 'do_cancel_all_orders': 5, 'get_order_book': 1, 'get_candles': 1, 'get_trade_history': 1, 'get_my_transaction_history': 1, 'get_my_funding_history': 5, 'do_my_internal_transfer': 1, 'get_processing_info': 10, 'get_deposit_address': 5, 'do_deposit_funds_from_wallet': 1, 'do_withdrawal_funds_to_wallet': 1, }, }, }, 'features': { 'spot': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': false, 'GTD': true, }, 'hedged': false, 'leverage': false, 'marketBuyRequiresPrice': false, 'marketBuyByCost': true, 'selfTradePrevention': false, 'trailing': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': undefined, 'fetchOrder': undefined, 'fetchOpenOrders': { 'marginMode': false, 'limit': 1000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': undefined, 'fetchClosedOrders': { 'marginMode': false, 'limit': 1000, 'daysBack': 100000, 'daysBackCanceled': 1, 'untilDays': 100000, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 1000, }, }, 'swap': { 'linear': undefined, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'precisionMode': TICK_SIZE, 'exceptions': { 'exact': {}, 'broad': { 'You have negative balance on following accounts': InsufficientFunds, 'Mandatory parameter side should be one of BUY,SELL': BadRequest, 'API orders from Main account are not allowed': BadRequest, 'check failed': BadRequest, 'Insufficient funds': InsufficientFunds, 'Get deposit address for main account is not allowed': PermissionDenied, 'Market Trigger orders are not allowed': BadRequest, 'key not passed or incorrect': AuthenticationError, }, }, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '2h': '2h', '4h': '4h', '1d': '1d', }, 'options': { 'networks': { 'BTC': 'bitcoin', 'ERC20': 'ERC20', 'BSC20': 'binancesmartchain', 'DOGE': 'dogecoin', 'ALGO': 'algorand', 'XLM': 'stellar', 'ATOM': 'cosmos', 'LTC': 'litecoin', 'XRP': 'ripple', 'FTM': 'fantom', 'MINA': 'mina', 'THETA': 'theta', 'XTZ': 'tezos', 'TIA': 'celestia', 'CRONOS': 'cronos', 'MATIC': 'polygon', 'TON': 'ton', 'TRC20': 'tron', 'SOLANA': 'solana', 'SGB': 'songbird', 'DYDX': 'dydx', 'DASH': 'dash', 'ZIL': 'zilliqa', 'EOS': 'eos', 'AVALANCHEC': 'avalanche', 'ETHPOW': 'ethereumpow', 'NEAR': 'near', 'ARB': 'arbitrum', 'DOT': 'polkadot', 'OPT': 'optimism', 'INJ': 'injective', 'ADA': 'cardano', 'ONT': 'ontology', 'ICP': 'icp', 'KAVA': 'kava', 'KSM': 'kusama', 'SEI': 'sei', // 'OSM': 'osmosis', 'NEO': 'neo', 'NEO3': 'neo3', // 'TERRAOLD': 'terra', // tbd // 'TERRA': 'terra2', // tbd // 'EVER': 'everscale', // tbd 'XDC': 'xdc', }, }, }); } /** * @method * @name cex#fetchCurrencies * @description fetches all available currencies on an exchange * @see https://trade.cex.io/docs/#rest-public-api-calls-currencies-info * @param {dict} [params] extra parameters specific to the exchange API endpoint * @returns {dict} an associative dictionary of currencies */ async fetchCurrencies(params = {}) { const promises = []; promises.push(this.publicPostGetCurrenciesInfo(params)); // // { // "ok": "ok", // "data": [ // { // "currency": "ZAP", // "fiat": false, // "precision": "8", // "walletPrecision": "6", // "walletDeposit": true, // "walletWithdrawal": true // }, // ... // promises.push(this.publicPostGetProcessingInfo(params)); // // { // "ok": "ok", // "data": { // "ADA": { // "name": "Cardano", // "blockchains": { // "cardano": { // "type": "coin", // "deposit": "enabled", // "minDeposit": "1", // "withdrawal": "enabled", // "minWithdrawal": "5", // "withdrawalFee": "1", // "withdrawalFeePercent": "0", // "depositConfirmations": "15" // } // } // }, // ... // const responses = await Promise.all(promises); const dataCurrencies = this.safeList(responses[0], 'data', []); const dataNetworks = this.safeDict(responses[1], 'data', {}); const currenciesIndexed = this.indexBy(dataCurrencies, 'currency'); const data = this.deepExtend(currenciesIndexed, dataNetworks); return this.parseCurrencies(this.toArray(data)); } parseCurrency(rawCurrency) { const id = this.safeString(rawCurrency, 'currency'); const code = this.safeCurrencyCode(id); const type = this.safeBool(rawCurrency, 'fiat') ? 'fiat' : 'crypto'; const currencyPrecision = this.parseNumber(this.parsePrecision(this.safeString(rawCurrency, 'precision'))); const networks = {}; const rawNetworks = this.safeDict(rawCurrency, 'blockchains', {}); const keys = Object.keys(rawNetworks); for (let j = 0; j < keys.length; j++) { const networkId = keys[j]; const rawNetwork = rawNetworks[networkId]; const networkCode = this.networkIdToCode(networkId); const deposit = this.safeString(rawNetwork, 'deposit') === 'enabled'; const withdraw = this.safeString(rawNetwork, 'withdrawal') === 'enabled'; networks[networkCode] = { 'id': networkId, 'network': networkCode, 'margin': undefined, 'deposit': deposit, 'withdraw': withdraw, 'active': undefined, 'fee': this.safeNumber(rawNetwork, 'withdrawalFee'), 'precision': currencyPrecision, 'limits': { 'deposit': { 'min': this.safeNumber(rawNetwork, 'minDeposit'), 'max': undefined, }, 'withdraw': { 'min': this.safeNumber(rawNetwork, 'minWithdrawal'), 'max': undefined, }, }, 'info': rawNetwork, }; } return this.safeCurrencyStructure({ 'id': id, 'code': code, 'name': undefined, 'type': type, 'active': undefined, 'deposit': this.safeBool(rawCurrency, 'walletDeposit'), 'withdraw': this.safeBool(rawCurrency, 'walletWithdrawal'), 'fee': undefined, 'precision': currencyPrecision, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': undefined, 'max': undefined, }, }, 'networks': networks, 'info': rawCurrency, }); } /** * @method * @name cex#fetchMarkets * @description retrieves data on all markets for ace * @see https://trade.cex.io/docs/#rest-public-api-calls-pairs-info * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const response = await this.publicPostGetPairsInfo(params); // // { // "ok": "ok", // "data": [ // { // "base": "AI", // "quote": "USD", // "baseMin": "30", // "baseMax": "2516000", // "baseLotSize": "0.000001", // "quoteMin": "10", // "quoteMax": "1000000", // "quoteLotSize": "0.01000000", // "basePrecision": "6", // "quotePrecision": "8", // "pricePrecision": "4", // "minPrice": "0.0377", // "maxPrice": "19.5000" // }, // ... // const data = this.safeList(response, 'data', []); return this.parseMarkets(data); } parseMarket(market) { const baseId = this.safeString(market, 'base'); const base = this.safeCurrencyCode(baseId); const quoteId = this.safeString(market, 'quote'); const quote = this.safeCurrencyCode(quoteId); const id = base + '-' + quote; // not actual id, but for this exchange we can use this abbreviation, because e.g. tickers have hyphen in between const symbol = base + '/' + quote; return this.safeMarketStructure({ 'id': id, 'symbol': symbol, 'base': base, 'baseId': baseId, 'quote': quote, 'quoteId': quoteId, 'settle': undefined, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'contract': false, 'linear': undefined, 'inverse': undefined, 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'limits': { 'amount': { 'min': this.safeNumber(market, 'baseMin'), 'max': this.safeNumber(market, 'baseMax'), }, 'price': { 'min': this.safeNumber(market, 'minPrice'), 'max': this.safeNumber(market, 'maxPrice'), }, 'cost': { 'min': this.safeNumber(market, 'quoteMin'), 'max': this.safeNumber(market, 'quoteMax'), }, 'leverage': { 'min': undefined, 'max': undefined, }, }, 'precision': { 'amount': this.safeString(market, 'baseLotSize'), 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))), // 'cost': this.parseNumber (this.parsePrecision (this.safeString (market, 'quoteLotSize'))), // buggy, doesn't reflect their documentation 'base': this.parseNumber(this.parsePrecision(this.safeString(market, 'basePrecision'))), 'quote': this.parseNumber(this.parsePrecision(this.safeString(market, 'quotePrecision'))), }, 'active': undefined, 'created': undefined, 'info': market, }); } /** * @method * @name cex#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @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.publicPostGetServerTime(params); // // { // "ok": "ok", // "data": { // "timestamp": "1728472063472", // "ISODate": "2024-10-09T11:07:43.472Z" // } // } // const data = this.safeDict(response, 'data'); const timestamp = this.safeInteger(data, 'timestamp'); return timestamp; } /** * @method * @name cex#fetchTicker * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://trade.cex.io/docs/#rest-public-api-calls-ticker * @param {string} symbol * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTicker(symbol, params = {}) { await this.loadMarkets(); const response = await this.fetchTickers([symbol], params); return this.safeDict(response, symbol, {}); } /** * @method * @name cex#fetchTickers * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market * @see https://trade.cex.io/docs/#rest-public-api-calls-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 exchange API endpoint * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure} */ async fetchTickers(symbols = undefined, params = {}) { await this.loadMarkets(); const request = {}; if (symbols !== undefined) { request['pairs'] = this.marketIds(symbols); } const response = await this.publicPostGetTicker(this.extend(request, params)); // // { // "ok": "ok", // "data": { // "AI-USD": { // "bestBid": "0.3917", // "bestAsk": "0.3949", // "bestBidChange": "0.0035", // "bestBidChangePercentage": "0.90", // "bestAskChange": "0.0038", // "bestAskChangePercentage": "0.97", // "low": "0.3787", // "high": "0.3925", // "volume30d": "2945.722277", // "lastTradeDateISO": "2024-10-11T06:18:42.077Z", // "volume": "120.736000", // "quoteVolume": "46.65654070", // "lastTradeVolume": "67.914000", // "volumeUSD": "46.65", // "last": "0.3949", // "lastTradePrice": "0.3925", // "priceChange": "0.0038", // "priceChangePercentage": "0.97" // }, // ... // const data = this.safeDict(response, 'data', {}); return this.parseTickers(data, symbols); } parseTicker(ticker, market = undefined) { const marketId = this.safeString(ticker, 'id'); const symbol = this.safeSymbol(marketId, market); return this.safeTicker({ 'symbol': symbol, 'timestamp': undefined, 'datetime': undefined, 'high': this.safeNumber(ticker, 'high'), 'low': this.safeNumber(ticker, 'low'), 'bid': this.safeNumber(ticker, 'bestBid'), 'bidVolume': undefined, 'ask': this.safeNumber(ticker, 'bestAsk'), 'askVolume': undefined, 'vwap': undefined, 'open': undefined, 'close': this.safeString(ticker, 'last'), 'previousClose': undefined, 'change': this.safeNumber(ticker, 'priceChange'), 'percentage': this.safeNumber(ticker, 'priceChangePercentage'), 'average': undefined, 'baseVolume': this.safeString(ticker, 'volume'), 'quoteVolume': this.safeString(ticker, 'quoteVolume'), 'info': ticker, }, market); } /** * @method * @name cex#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://trade.cex.io/docs/#rest-public-api-calls-trade-history * @param {string} symbol unified symbol of the market to fetch trades for * @param {int} [since] timestamp in ms of the earliest trade to fetch * @param {int} [limit] the maximum amount of trades to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest entry * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const request = { 'pair': market['id'], }; if (since !== undefined) { request['fromDateISO'] = this.iso8601(since); } let until = undefined; [until, params] = this.handleParamInteger2(params, 'until', 'till'); if (until !== undefined) { request['toDateISO'] = this.iso8601(until); } if (limit !== undefined) { request['pageSize'] = Math.min(limit, 10000); // has a bug, still returns more trades } const response = await this.publicPostGetTradeHistory(this.extend(request, params)); // // { // "ok": "ok", // "data": { // "pageSize": "10", // "trades": [ // { // "tradeId": "1728630559823-0", // "dateISO": "2024-10-11T07:09:19.823Z", // "side": "SELL", // "price": "60879.5", // "amount": "0.00165962" // }, // ... followed by older trades // const data = this.safeDict(response, 'data', {}); const trades = this.safeList(data, 'trades', []); return this.parseTrades(trades, market, since, limit); } parseTrade(trade, market = undefined) { // // public fetchTrades // // { // "tradeId": "1728630559823-0", // "dateISO": "2024-10-11T07:09:19.823Z", // "side": "SELL", // "price": "60879.5", // "amount": "0.00165962" // }, // const dateStr = this.safeString(trade, 'dateISO'); const timestamp = this.parse8601(dateStr); market = this.safeMarket(undefined, market); return this.safeTrade({ 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': market['symbol'], 'id': this.safeString(trade, 'tradeId'), 'order': undefined, 'type': undefined, 'takerOrMaker': undefined, 'side': this.safeStringLower(trade, 'side'), 'price': this.safeString(trade, 'price'), 'amount': this.safeString(trade, 'amount'), 'cost': undefined, 'fee': undefined, }, market); } /** * @method * @name cex#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://trade.cex.io/docs/#rest-public-api-calls-order-book * @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 = { 'pair': market['id'], }; const response = await this.publicPostGetOrderBook(this.extend(request, params)); // // { // "ok": "ok", // "data": { // "timestamp": "1728636922648", // "currency1": "BTC", // "currency2": "USDT", // "bids": [ // [ // "60694.1", // "13.12849761" // ], // [ // "60694.0", // "0.71829244" // ], // ... // const orderBook = this.safeDict(response, 'data', {}); const timestamp = this.safeInteger(orderBook, 'timestamp'); return this.parseOrderBook(orderBook, market['symbol'], timestamp); } /** * @method * @name cex#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market * @see https://trade.cex.io/docs/#rest-public-api-calls-candles * @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} [since] timestamp in ms of the earliest candle to fetch * @param {int} [limit] the maximum amount of candles to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest entry * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume */ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { let dataType = undefined; [dataType, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'dataType'); if (dataType === undefined) { throw new ArgumentsRequired(this.id + ' fetchOHLCV requires a parameter "dataType" to be either "bestBid" or "bestAsk"'); } await this.loadMarkets(); const market = this.market(symbol); const request = { 'pair': market['id'], 'resolution': this.timeframes[timeframe], 'dataType': dataType, }; if (since !== undefined) { request['fromISO'] = this.iso8601(since); } let until = undefined; [until, params] = this.handleParamInteger2(params, 'until', 'till'); if (until !== undefined) { request['toISO'] = this.iso8601(until); } else if (since === undefined) { // exchange still requires that we provide one of them request['toISO'] = this.iso8601(this.milliseconds()); } if (since !== undefined && until !== undefined && limit !== undefined) { throw new ArgumentsRequired(this.id + ' fetchOHLCV does not support fetching candles with both a limit and since/until'); } else if ((since !== undefined || until !== undefined) && limit === undefined) { throw new ArgumentsRequired(this.id + ' fetchOHLCV requires a limit parameter when fetching candles with since or until'); } if (limit !== undefined) { request['limit'] = limit; } const response = await this.publicPostGetCandles(this.extend(request, params)); // // { // "ok": "ok", // "data": [ // { // "timestamp": "1728643320000", // "open": "61061", // "high": "61095.1", // "low": "61048.5", // "close": "61087.8", // "volume": "0", // "resolution": "1m", // "isClosed": true, // "timestampISO": "2024-10-11T10:42:00.000Z" // }, // ... // const data = this.safeList(response, 'data', []); return this.parseOHLCVs(data, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { return [ this.safeInteger(ohlcv, 'timestamp'), this.safeNumber(ohlcv, 'open'), this.safeNumber(ohlcv, 'high'), this.safeNumber(ohlcv, 'low'), this.safeNumber(ohlcv, 'close'), this.safeNumber(ohlcv, 'volume'), ]; } /** * @method * @name cex#fetchTradingFees * @description fetch the trading fees for multiple markets * @see https://trade.cex.io/docs/#rest-public-api-calls-candles * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols */ async fetchTradingFees(params = {}) { await this.loadMarkets(); const response = await this.privatePostGetMyCurrentFee(params); // // { // "ok": "ok", // "data": { // "tradingFee": { // "AI-USD": { // "percent": "0.25" // }, // ... // const data = this.safeDict(response, 'data', {}); const fees = this.safeDict(data, 'tradingFee', {}); return this.parseTradingFees(fees, true); } parseTradingFees(response, useKeyAsId = false) { const result = {}; const keys = Object.keys(response); for (let i = 0; i < keys.length; i++) { const key = keys[i]; let market = undefined; if (useKeyAsId) { market = this.safeMarket(key); } const parsed = this.parseTradingFee(response[key], market); result[parsed['symbol']] = parsed; } for (let i = 0; i < this.symbols.length; i++) { const symbol = this.symbols[i]; if (!(symbol in result)) { const market = this.market(symbol); result[symbol] = this.parseTradingFee(response, market); } } return result; } parseTradingFee(fee, market = undefined) { return { 'info': fee, 'symbol': this.safeString(market, 'symbol'), 'maker': this.safeNumber(fee, 'percent'), 'taker': this.safeNumber(fee, 'percent'), 'percentage': undefined, 'tierBased': undefined, }; } async fetchAccounts(params = {}) { await this.loadMarkets(); const response = await this.privatePostGetMyAccountStatusV3(params); // // { // "ok": "ok", // "data": { // "convertedCurrency": "USD", // "balancesPerAccounts": { // "": { // "AI": { // "balance": "0.000000", // "balanceOnHold": "0.000000" // }, // "USDT": { // "balance": "0.00000000", // "balanceOnHold": "0.00000000" // } // } // } // } // } // const data = this.safeDict(response, 'data', {}); const balances = this.safeDict(data, 'balancesPerAccounts', {}); const arrays = this.toArray(balances); return this.parseAccounts(arrays, params); } parseAccount(account) { return { 'id': undefined, 'type': undefined, 'code': undefined, 'info': account, }; } /** * @method * @name cex#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://trade.cex.io/docs/#rest-private-api-calls-account-status-v3 * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {object} [params.method] 'privatePostGetMyWalletBalance' or 'privatePostGetMyAccountStatusV3' * @param {object} [params.account] in case 'privatePostGetMyAccountStatusV3' is chosen, this can specify the account name (default is empty string) * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ async fetchBalance(params = {}) { let accountName = undefined; [accountName, params] = this.handleParamString(params, 'account', ''); // default is empty string let method = undefined; [method, params] = this.handleParamString(params, 'method', 'privatePostGetMyWalletBalance'); let accountBalance = undefined; if (method === 'privatePostGetMyAccountStatusV3') { const response = await this.privatePostGetMyAccountStatusV3(params); // // { // "ok": "ok", // "data": { // "convertedCurrency": "USD", // "balancesPerAccounts": { // "": { // "AI": { // "balance": "0.000000", // "balanceOnHold": "0.000000" // }, // .... // const data = this.safeDict(response, 'data', {}); const balances = this.safeDict(data, 'balancesPerAccounts', {}); accountBalance = this.safeDict(balances, accountName, {}); } else { const response = await this.privatePostGetMyWalletBalance(params); // // { // "ok": "ok", // "data": { // "AI": { // "balance": "25.606429" // }, // "USDT": { // "balance": "7.935449" // }, // ... // accountBalance = this.safeDict(response, 'data', {}); } return this.parseBalance(accountBalance); } parseBalance(response) { const result = { 'info': response, }; const keys = Object.keys(response); for (let i = 0; i < keys.length; i++) { const key = keys[i]; const balance = this.safeDict(response, key, {}); const code = this.safeCurrencyCode(key); const account = { 'used': this.safeString(balance, 'balanceOnHold'), 'total': this.safeString(balance, 'balance'), }; result[code] = account; } return this.safeBalance(result); } /** * @method * @name cex#fetchOrders * @description fetches information on multiple orders made by the user * @see https://trade.cex.io/docs/#rest-private-api-calls-orders * @param {string} status order status to fetch for * @param {string} symbol unified market symbol of the market orders were made in * @param {int} [since] the earliest time in ms to fetch orders for * @param {int} [limit] the maximum number of order structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest entry * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const request = {}; const isClosedOrders = (status === 'closed'); if (isClosedOrders) { request['archived'] = true; } let market = undefined; if (symbol !== undefined) { market = this.market(symbol); request['pair'] = market['id']; } if (limit !== undefined) { request['pageSize'] = limit; } if (since !== undefined) { request['serverCreateTimestampFrom'] = since; } else if (isClosedOrders) { // exchange requires a `since` parameter for closed orders, so set default to allowed 365 request['serverCreateTimestampFrom'] = this.milliseconds() - 364 * 24 * 60 * 60 * 1000; } let until = undefined; [until, params] = this.handleParamInteger2(params, 'until', 'till'); if (until !== undefined) { request['serverCreateTimestampTo'] = until; } const response = await this.privatePostGetMyOrders(this.extend(request, params)); // // if called without `pair` // // { // "ok": "ok", // "data": [ // { // "orderId": "1313003", // "clientOrderId": "037F0AFEB93A", // "clientId": "up421412345", // "accountId": null, // "status": "FILLED", // "statusIsFinal": true, // "currency1": "AI", // "currency2": "USDT", // "side": "BUY", // "orderType": "Market", // "timeInForce": "IOC", // "comment": null, // "rejectCode": null, // "rejectReason": null, // "initialOnHoldAmountCcy1": null, // "initialOnHoldAmountCcy2": "10.23456700", // "executedAmountCcy1": "25.606429", // "executedAmountCcy2": "10.20904439", // "requestedAmountCcy1": null, // "requestedAmountCcy2": "10.20904439", // "originalAmountCcy2": "10.23456700", // "feeAmount": "0.02552261", // "feeCurrency": "USDT", // "price": null, // "averagePrice": "0.3986", // "clientCreateTimestamp": "1728474625320", // "serverCreateTimestamp": "1728474624956", // "lastUpdateTimestamp": "1728474628015", // "expireTime": null, // "effectiveTime": null // }, // ... // const data = this.safeList(response, 'data', []); return this.parseOrders(data, market, since, limit); } /** * @method * @name cex#fetchClosedOrders * @see https://trade.cex.io/docs/#rest-private-api-calls-orders * @description fetches information on multiple canceled orders made by the user * @param {string} symbol unified market symbol of the market orders were made in * @param {int} [since] timestamp in ms of the earliest order, default is undefined * @param {int} [limit] max number of orders to return, default is undefined * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { return await this.fetchOrdersByStatus('closed', symbol, since, limit, params); } /** * @method * @name cex#fetchOpenOrders * @see https://trade.cex.io/docs/#rest-private-api-calls-orders * @description fetches information on multiple canceled orders made by the user * @param {string} symbol unified market symbol of the market orders were made in * @param {int} [since] timestamp in ms of the earliest order, default is undefined * @param {int} [limit] max number of orders to return, default is undefined * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) { return await this.fetchOrdersByStatus('open', symbol, since, limit, params); } /** * @method * @name cex#fetchOpenOrder * @description fetches information on an open order made by the user * @see https://trade.cex.io/docs/#rest-private-api-calls-orders * @param {string} id order id * @param {string} [symbol] unified symbol of the market the order was made in * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchOpenOrder(id, symbol = undefined, params = {}) { await this.loadMarkets(); const request = { 'orderId': parseInt(id), }; const result = await this.fetchOpenOrders(symbol, undefined, undefined, this.extend(request, params)); return result[0]; } /** * @method * @name cex#fetchClosedOrder * @description fetches information on an closed order made by the user * @see https://trade.cex.io/docs/#rest-private-api-calls-orders * @param {string} id order id * @param {string} [symbol] unified symbol of the market the order was made in * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure} */ async fetchClosedOrder(id, symbol = undefined, params = {}) { await this.loadMarkets(); const request = { 'orderId': parseInt(id), }; const result = await this.fetchClosedOrders(symbol, undefined, undefined, this.extend(request, params)); return result[0]; } parseOrderStatus(status) { const statuses = { 'PENDING_NEW': 'open', 'NEW': 'open', 'PARTIALLY_FILLED': 'open', 'FILLED': 'closed', 'EXPIRED': 'expired', 'REJECTED': 'rejected', 'PENDING_CANCEL': 'canceling', 'CANCELLED': 'canceled', }; return this.safeString(statuses, status, status); } parseOrder(order, market = undefined) { // // "orderId": "1313003", // "clientOrderId": "037F0AFEB93A", // "clientId": "up421412345", // "accountId": null, // "status": "FILLED", // "statusIsFinal": true, // "currency1": "AI", // "currency2": "USDT", // "side": "BUY", // "orderType": "Market", // "timeInForce": "IOC", // "comment": null, // "rejectCode": null, //