UNPKG

ccxt

Version:

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

1,141 lines (1,139 loc) • 87.5 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/ellipx.js'; import { AuthenticationError, BadRequest, DDoSProtection, ExchangeError, PermissionDenied, NotSupported, ArgumentsRequired } from './base/errors.js'; import { ed25519 } from './static_dependencies/noble-curves/ed25519.js'; import { eddsa } from './base/functions/crypto.js'; import { Precise } from './base/Precise.js'; import { sha256 } from './static_dependencies/noble-hashes/sha256.js'; import { TICK_SIZE } from './base/functions/number.js'; // --------------------------------------------------------------------------- /** * @class ellipx * @augments Exchange */ export default class ellipx extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'ellipx', 'name': 'Ellipx', 'countries': ['PL'], 'rateLimit': 200, 'version': 'v1', 'certified': false, 'pro': false, 'has': { 'CORS': undefined, 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'addMargin': false, 'cancelAllOrders': false, 'cancelAllOrdersAfter': false, 'cancelOrder': true, 'cancelOrders': false, 'cancelWithdraw': false, 'closePosition': false, 'createConvertTrade': false, 'createDepositAddress': false, 'createMarketBuyOrderWithCost': false, 'createMarketOrder': false, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createOrderWithTakeProfitAndStopLoss': false, 'createReduceOnlyOrder': false, 'createStopLimitOrder': false, 'createStopLossOrder': false, 'createStopMarketOrder': false, 'createStopOrder': false, 'createTakeProfitOrder': false, 'createTrailingAmountOrder': false, 'createTrailingPercentOrder': false, 'createTriggerOrder': false, 'fetchAccounts': false, 'fetchBalance': true, 'fetchCanceledAndClosedOrders': false, 'fetchCanceledOrders': false, 'fetchClosedOrder': false, 'fetchClosedOrders': false, 'fetchConvertCurrencies': false, 'fetchConvertQuote': false, 'fetchConvertTrade': false, 'fetchConvertTradeHistory': false, 'fetchCurrencies': true, 'fetchDepositAddress': true, 'fetchDeposits': false, 'fetchDepositsWithdrawals': false, 'fetchFundingHistory': false, 'fetchFundingRate': false, 'fetchFundingRateHistory': false, 'fetchFundingRates': false, 'fetchIndexOHLCV': false, 'fetchLedger': false, 'fetchLeverage': false, 'fetchLeverageTiers': false, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': false, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrder': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': false, 'fetchPositionHistory': false, 'fetchPositionMode': false, 'fetchPositions': false, 'fetchPositionsForSymbol': false, 'fetchPositionsHistory': false, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': false, 'fetchTicker': true, 'fetchTickers': false, 'fetchTime': false, 'fetchTrades': true, 'fetchTradingFee': true, 'fetchTradingFees': false, 'fetchTransactions': false, 'fetchTransfers': false, 'fetchWithdrawals': false, 'reduceMargin': false, 'sandbox': false, 'setLeverage': false, 'setMargin': false, 'setPositionMode': false, 'transfer': false, 'withdraw': true, }, 'timeframes': { '1m': '1m', '5m': '5m', '10m': '10m', '1h': '1h', '6h': '6h', '12h': '12h', '1d': '1d', }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/e07c3f40-281c-4cdf-bacf-fa1c58218a2c', 'api': { 'public': 'https://data.ellipx.com', 'private': 'https://app.ellipx.com/_rest', '_rest': 'https://app.ellipx.com/_rest', }, 'www': 'https://www.ellipx.com', 'doc': 'https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM', 'fees': 'https://www.ellipx.com/pages/pricing', 'referral': '', // todo }, 'api': { '_rest': { 'get': { 'Market': 1, 'Market/{currencyPair}': 1, 'Crypto/Token/Info': 1, }, }, 'public': { 'get': { 'Market/{currencyPair}:getDepth': 1, 'Market/{currencyPair}:ticker': 1, 'Market/{currencyPair}:getTrades': 1, 'Market/{currencyPair}:getGraph': 1, 'CMC:summary': 1, 'CMC/{currencyPair}:ticker': 1, }, }, 'private': { 'get': { 'User/Wallet': 1, 'Market/{currencyPair}/Order': 1, 'Market/Order/{orderUuid}': 1, 'Market/{currencyPair}/Trade': 1, 'Market/TradeFee:query': 1, 'Unit/{currency}': 1, 'Crypto/Token/{currency}': 1, 'Crypto/Token/{currency}:chains': 1, }, 'post': { 'Market/{currencyPair}/Order': 1, 'Crypto/Address:fetch': 1, 'Crypto/Disbursement:withdraw': 1, }, 'delete': { 'Market/Order/{orderUuid}': 1, }, }, }, 'fees': { 'trading': { 'tierBased': true, 'feeSide': 'get', 'percentage': true, 'maker': this.parseNumber('0.0025'), 'taker': this.parseNumber('0.0030'), 'tiers': { // volume in USDT 'maker': [ [this.parseNumber('0'), this.parseNumber('0.0025')], [this.parseNumber('10000'), this.parseNumber('0.0020')], [this.parseNumber('50000'), this.parseNumber('0.0015')], [this.parseNumber('100000'), this.parseNumber('0.0010')], [this.parseNumber('1000000'), this.parseNumber('0.0008')], [this.parseNumber('5000000'), this.parseNumber('0.0003')], [this.parseNumber('15000000'), this.parseNumber('0.0000')], [this.parseNumber('75000000'), this.parseNumber('0.0000')], [this.parseNumber('100000000'), this.parseNumber('0.0000')], // 100M+: 0bps ], 'taker': [ [this.parseNumber('0'), this.parseNumber('0.0030')], [this.parseNumber('10000'), this.parseNumber('0.0025')], [this.parseNumber('50000'), this.parseNumber('0.0020')], [this.parseNumber('100000'), this.parseNumber('0.0015')], [this.parseNumber('1000000'), this.parseNumber('0.0012')], [this.parseNumber('5000000'), this.parseNumber('0.0010')], [this.parseNumber('15000000'), this.parseNumber('0.0008')], [this.parseNumber('75000000'), this.parseNumber('0.0005')], [this.parseNumber('100000000'), this.parseNumber('0.0003')], // 100M+: 3bps ], }, }, 'stablecoin': { 'tierBased': false, 'percentage': true, 'maker': this.parseNumber('0.0000'), 'taker': this.parseNumber('0.000015'), // 0.0015% }, }, 'options': { 'defaultType': 'spot', 'recvWindow': 5 * 1000, 'broker': 'CCXT', 'networks': { 'Bitcoin': 'Bitcoin', 'Ethereum': 'ERC20', }, 'defaultNetwork': 'defaultNetwork', 'defaultNetworkCodeReplacements': { 'BTC': 'Bitcoin', 'ETH': 'Ethereum', }, }, 'features': { 'spot': { 'sandbox': false, 'createOrder': { 'marginMode': false, 'triggerPrice': false, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, 'takeProfitPrice': false, 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': false, 'FOK': false, 'PO': false, 'GTD': false, }, 'hedged': false, 'selfTradePrevention': false, 'trailing': false, 'leverage': false, 'marketBuyByCost': true, 'marketBuyRequiresPrice': false, 'iceberg': false, }, 'createOrders': undefined, 'fetchMyTrades': undefined, 'fetchOrder': { 'marginMode': false, 'trigger': false, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchOrders': { 'marginMode': false, 'limit': undefined, 'daysBack': undefined, 'untilDays': undefined, 'trigger': false, 'trailing': false, 'symbolRequired': true, }, 'fetchClosedOrders': undefined, 'fetchOHLCV': { 'limit': 100, }, }, 'swap': { 'linear': undefined, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'commonCurrencies': {}, 'exceptions': { 'exact': { // todo '400': BadRequest, '401': AuthenticationError, '403': PermissionDenied, '404': BadRequest, '429': DDoSProtection, '418': PermissionDenied, '500': ExchangeError, '504': ExchangeError, }, 'broad': {}, }, 'precisionMode': TICK_SIZE, }); } sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) { path = this.implodeParams(path, params); let url = this.urls['api'][api] + '/' + path; if (api === 'private') { this.checkRequiredCredentials(); const nonce = this.uuid(); const timestamp = this.seconds().toString(); if (method === 'GET') { body = ''; } else { body = this.json(params); } params = this.extend({ '_key': this.apiKey, '_time': timestamp, '_nonce': nonce, }, params); const query = this.urlencode(params); const bodyHash = this.hash(this.encode(body), sha256); // Create sign string components const bodyHashBytes = this.base16ToBinary(bodyHash); const nulByte = this.numberToBE(0, 1); const components = [ this.encode(method), nulByte, this.encode(path), nulByte, this.encode(query), nulByte, bodyHashBytes, ]; // Join with null byte separator using encode const signString = this.binaryConcatArray(components); const sec = this.secret; const remainder = this.calculateMod(sec.length, 4); const paddingLength = remainder ? 4 - remainder : 0; let secretWithPadding = this.secret.replaceAll('-', '+'); secretWithPadding = secretWithPadding.replaceAll('_', '/'); secretWithPadding = secretWithPadding.padEnd(this.secret.length + paddingLength, '='); const secretBytes = this.base64ToBinary(secretWithPadding); const seed = this.arraySlice(secretBytes, 0, 32); // Extract first 32 bytes as seed const signature = eddsa(signString, seed, ed25519); params['_sign'] = signature; } if (Object.keys(params).length) { url += '?' + this.urlencode(params); } if (method === 'GET') { body = undefined; } else { headers = { 'Content-Type': 'application/json', }; } return { 'url': url, 'method': method, 'body': body, 'headers': headers }; } calculateMod(a, b) { // trick to fix php transpiling error return a % b; } /** * @method * @name ellipx#fetchMarkets * @description Fetches market information from the exchange. * @see https://docs.ccxt.com/en/latest/manual.html#markets * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.1a1t05wpgfof * @param {object} [params] - Extra parameters specific to the exchange API endpoint * @returns {Promise<Market[]>} An array of market structures. */ async fetchMarkets(params = {}) { const response = await this._restGetMarket(params); // { // Market__: "mkt-lrnp2e-eaor-eobj-ua73-75j6sjxe", // Primary_Unit__: "unit-aebkye-u35b-e5zm-zt22-2qvwhsqa", // Secondary_Unit__: "unit-jcevlk-soxf-fepb-yjwm-b32q5bom", // Primary_Step: null, // Secondary_Step: null, // Status: "active", // Default_Scale: "5", // Priority: "100", // Created: { // unix: "1728113809", // us: "0", // iso: "2024-10-05 07:36:49.000000", // tz: "UTC", // full: "1728113809000000", // unixms: "1728113809000", // }, // Start: { // unix: "1728295200", // us: "0", // iso: "2024-10-07 10:00:00.000000", // tz: "UTC", // full: "1728295200000000", // unixms: "1728295200000", // }, // Key: "BTC_USDC", // Primary: { // Unit__: "unit-aebkye-u35b-e5zm-zt22-2qvwhsqa", // Currency__: "BTC", // Crypto_Token__: "crtok-c5v3mh-grfn-hl5d-lmel-fvggbf4i", // Key: "BTC", // Symbol: "BTC", // Symbol_Position: "after", // Name: "Bitcoin", // Decimals: "8", // Display_Decimals: "8", // Legacy_Decimals: null, // Type: "crypto_token", // Visible: "Y", // Created: { // unix: "1495247415", // us: "0", // iso: "2017-05-20 02:30:15.000000", // tz: "UTC", // full: "1495247415000000", // unixms: "1495247415000", // }, // }, // Secondary: { // Unit__: "unit-jcevlk-soxf-fepb-yjwm-b32q5bom", // Currency__: null, // Crypto_Token__: "crtok-ptabkh-ra4r-anbd-cqra-bqfbtnba", // Key: "USDC", // Symbol: null, // Symbol_Position: "before", // Name: "Circle USD", // Decimals: "6", // Display_Decimals: "6", // Legacy_Decimals: null, // Type: "crypto_token", // Visible: "Y", // Created: { // unix: "1694859829", // us: "0", // iso: "2023-09-16 10:23:49.000000", // tz: "UTC", // full: "1694859829000000", // unixms: "1694859829000", // }, // }, // } const markets = this.safeValue(response, 'data', []); return this.parseMarkets(markets); } parseMarket(market) { const id = this.safeString(market, 'Key'); const base = this.safeString(market['Primary'], 'Key'); const quote = this.safeString(market['Secondary'], 'Key'); const baseId = this.safeString(market['Primary'], 'Crypto_Token__'); const quoteId = this.safeString(market['Secondary'], 'Crypto_Token__'); const status = this.safeString(market, 'Status') === 'active'; const created = this.safeTimestamp(market['Created'], 'unix'); const amountPrecision = this.parseNumber(this.parsePrecision(this.safeString(market['Primary'], 'Decimals'))); const pricePrecision = this.parseNumber(this.parsePrecision(this.safeString(market['Secondary'], 'Decimals'))); const fees = this.fees; // should use fetchTradingFees return this.safeMarketStructure({ 'id': id, 'symbol': base + '/' + quote, 'base': base, 'quote': quote, 'settle': undefined, 'baseId': baseId, 'quoteId': quoteId, 'settleId': undefined, 'type': 'spot', 'spot': true, 'margin': false, 'swap': false, 'future': false, 'option': false, 'active': status, 'contract': false, 'linear': undefined, 'inverse': undefined, 'taker': fees['trading']['taker'], 'maker': fees['trading']['maker'], 'contractSize': undefined, 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': amountPrecision, 'price': pricePrecision, }, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'price': { 'min': undefined, 'max': undefined, }, 'cost': { 'min': undefined, 'max': undefined, }, }, 'info': market, 'created': created, }); } /** * @method * @name ellipx#fetchTicker * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.d2jylz4u6pmu * @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 marketId = market['id']; const request = { 'currencyPair': marketId, }; const response = await this.publicGetMarketCurrencyPairTicker(this.extend(request, params)); // // { // "data": { // "market": "BTC_USDC", // "ticker": { // "time": 1730814600, // "count": 2135, // "high": { // "v": "74766990000", // "e": 6, // "f": 74766.99 // }, // "low": { // "v": "68734020000", // "e": 6, // "f": 68734.02 // }, // "avg": { // "v": "72347941430", // "e": 6, // "f": 72347.94143 // }, // "vwap": { // "v": "73050064447", // "e": 6, // "f": 73050.064447 // }, // "vol": { // "v": "4885361", // "e": 8, // "f": 0.04885361 // }, // "secvol": { // "v": "3568759346", // "e": 6, // "f": 3568.759346 // }, // "open": { // "v": "68784020000", // "e": 6, // "f": 68784.02 // }, // "close": { // "v": "73955570000", // "e": 6, // "f": 73955.57 // } // } // }, // "request_id": "cbf183e0-7a62-4674-838c-6693031fa240", // "result": "success", // "time": 0.015463566 // } // const ticker = this.safeValue(response['data'], 'ticker', {}); return this.parseTicker(ticker, market); } parseTicker(ticker, market = undefined) { const timestamp = this.safeIntegerProduct(ticker, 'time', 1000); const open = this.parseAmount(this.safeValue(ticker, 'open')); const high = this.parseAmount(this.safeValue(ticker, 'high')); const low = this.parseAmount(this.safeValue(ticker, 'low')); const close = this.parseAmount(this.safeValue(ticker, 'close')); const avg = this.parseAmount(this.safeValue(ticker, 'avg')); const vwap = this.parseAmount(this.safeValue(ticker, 'vwap')); const baseVolume = this.parseAmount(this.safeValue(ticker, 'vol')); const quoteVolume = this.parseAmount(this.safeValue(ticker, 'secvol')); // const count = this.safeInteger(ticker, 'count'); not used return this.safeTicker({ 'symbol': this.safeSymbol(undefined, market), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'high': high, 'low': low, 'bid': undefined, 'bidVolume': undefined, 'ask': undefined, 'askVolume': undefined, 'vwap': vwap, 'open': open, 'close': close, 'last': close, 'previousClose': undefined, 'change': undefined, 'percentage': undefined, 'average': avg, 'baseVolume': baseVolume, 'quoteVolume': quoteVolume, 'info': ticker, }, market); } /** * @method * @name ellipx#fetchOrderBook * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.bqmucewhkpdz * @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 the exchange not supported yet. * @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 marketId = market['id']; const request = { 'currencyPair': marketId, }; const response = await this.publicGetMarketCurrencyPairGetDepth(this.extend(request, params)); // { // "data": { // "asks": [ // { // "price": { // "v": "74941875231", // "e": 6, // "f": 74941.875231 // }, // "amount": { // "v": "149", // "e": 8, // "f": 0.00000149 // } // }, // { // "price": { // "v": "75063426037", // "e": 6, // "f": 75063.426037 // }, // "amount": { // "v": "335", // "e": 8, // "f": 0.00000335 // } // } // ], // "bids": [ // { // "price": { // "v": "64518711040", // "e": 6, // "f": 64518.71104 // }, // "amount": { // "v": "132", // "e": 8, // "f": 0.00000132 // } // }, // { // "price": { // "v": "64263569273", // "e": 6, // "f": 64263.569273 // }, // "amount": { // "v": "210", // "e": 8, // "f": 0.0000021 // } // } // ], // "market": "BTC_USDC" // }, // "request_id": "71b7dffc-3120-4e46-a0bb-49ece5aea7e1", // "result": "success", // "time": 0.000074661 // } const data = this.safeValue(response, 'data', {}); // exchange specific v e f params const timestamp = this.milliseconds(); // the exchange does not provide timestamp for this. const dataBidsLength = data['bids'].length; const dataAsksLength = data['asks'].length; for (let i = 0; i < dataBidsLength; i++) { data['bids'][i]['price'] = this.parseAmount(data['bids'][i]['price']); data['bids'][i]['amount'] = this.parseAmount(data['bids'][i]['amount']); } for (let i = 0; i < dataAsksLength; i++) { data['asks'][i]['price'] = this.parseAmount(data['asks'][i]['price']); data['asks'][i]['amount'] = this.parseAmount(data['asks'][i]['amount']); } return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'amount'); } /** * @method * @name ellipx#fetchOHLCV * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market, default will return the last 24h period. * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.w65baeuhxwt8 * @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 API endpoint * @param {int} [params.until] timestamp in ms of the earliest candle to fetch * @returns {OHLCV[]} A list of candles ordered as timestamp, open, high, low, close, volume */ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const methodName = 'fetchOHLCV'; let paginate = false; [paginate, params] = this.handleOptionAndParams(params, methodName, 'paginate'); if (paginate) { return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000); } const market = this.market(symbol); const marketId = market['id']; const time_frame = this.safeString(this.timeframes, timeframe, undefined); const request = { 'currencyPair': marketId, 'interval': time_frame, }; if (since !== undefined) { request['start'] = Math.floor(since / 1000); } let until = undefined; [until, params] = this.handleOptionAndParams(params, methodName, 'until'); if (until !== undefined) { request['end'] = until; } // { // "data": { // "market": "BTC_USDC", // "real_end": 1730970780, // "requested_end": 1730970784, // "start": 1730884200, // "stats": [ // { // "time": 1730884200, // "count": 48, // "high": {"v": "73898950000", "e": 6, "f": 73898.95}, // "low": {"v": "73642930000", "e": 6, "f": 73642.93}, // "open": {"v": "73830990000", "e": 6, "f": 73830.99}, // "close": {"v": "73682510000", "e": 6, "f": 73682.51}, // "vol": {"v": "88159", "e": 8, "f": 0.00088159} // } // ] // } // } // No limit parameter supported by the API const response = await this.publicGetMarketCurrencyPairGetGraph(this.extend(request, params)); const data = this.safeDict(response, 'data', {}); const ohlcv = this.safeList(data, 'stats', []); return this.parseOHLCVs(ohlcv, market, timeframe, since, limit); } parseOHLCV(ohlcv, market = undefined) { return [ this.safeInteger(ohlcv, 'time') * 1000, this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'open'))), this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'high'))), this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'low'))), this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'close'))), this.parseNumber(this.parseAmount(this.safeDict(ohlcv, 'vol'))), // volume ]; } /** * @method * @name ellipx#fetchCurrencies * @description fetches information on all currencies from the exchange, including deposit/withdrawal details and available chains * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.x65f9s9j74jf * @param {object} [params] extra parameters specific to the ellipx API endpoint * @param {string} [params.Can_Deposit] filter currencies by deposit availability, Y for available * @param {number} [params.results_per_page] number of results per page, default 100 * @param {string} [params._expand] additional fields to expand in response, default '/Crypto_Token,/Crypto_Chain' * @returns {Promise<Currencies>} An object of currency structures indexed by currency codes */ async fetchCurrencies(params = {}) { const response = await this._restGetCryptoTokenInfo(this.extend({ 'Can_Deposit': 'Y', 'results_per_page': 100, '_expand': '/Crypto_Token,/Crypto_Chain', }, params)); const result = {}; const data = this.safeList(response, 'data', []); for (let i = 0; i < data.length; i++) { const networkEntry = data[i]; // // { // "Crypto_Token_Info__": "crtev-5nsn35-f4ir-g5hp-iaft-i4ztx6zu", // "Crypto_Token__": "crtok-c5v3mh-grfn-hl5d-lmel-fvggbf4i", // "Crypto_Chain__": "chain-xjbini-7wlz-dmzf-gm7z-zf7ei6fq", // "Type": "native", // "Symbol": null, // "Name": null, // "Contract_Address": null, // "Minimum_Deposit": { // "v": "6", // "e": "6", // "f": "6.0e-6" // }, // "Minimum_Withdraw": { // "v": "15", // "e": "5", // "f": "0.00015" // }, // "Withdraw_Fee": { // "v": "1", // "e": "4", // "f": "0.0001" // }, // "Minimum_Collect": null, // "Status": "valid", // "Can_Deposit": "Y", // "Decimals": null, // "Priority": "100", // "Created": { // "unix": "1727552199", // "us": "0", // "iso": "2024-09-28 19:36:39.000000", // "tz": "UTC", // "full": "1727552199000000", // "unixms": "1727552199000" // }, // "Crypto_Token": { // "Crypto_Token__": "crtok-c5v3mh-grfn-hl5d-lmel-fvggbf4i", // "Name": "Bitcoin", // "Symbol": "BTC", // "Decimals": "8", // "CMC_Id": "1", // "Priority": "100", // "Can_Deposit": "Y", // "Category": "token", // "Testnet": "N", // "Created": { // "unix": "1727552113", // "us": "0", // "iso": "2024-09-28 19:35:13.000000", // "tz": "UTC", // "full": "1727552113000000", // "unixms": "1727552113000" // }, // "Logo": [ // { // "Crypto_Token_Logo__": "ctklg-aoozyr-rzm5-fphf-dhm7-5wbtetha", // "Crypto_Token__": "crtok-c5v3mh-grfn-hl5d-lmel-fvggbf4i", // "Blob__": "blob-d6hvgx-37s5-dh5h-ogj5-qxqvnaoy", // "Default": "Y", // "Format": "png", // "Priority": "0", // "Created": { // "unix": "1730196627", // "us": "929660", // "iso": "2024-10-29 10:10:27.929660", // "tz": "UTC", // "full": "1730196627929660", // "unixms": "1730196627929" // }, // "Source": { // "Media_Image__": "blob-d6hvgx-37s5-dh5h-ogj5-qxqvnaoy", // "Url": "https://static.atonline.net/image/m_X7_tnmIYFCwn6EUVQuMKqrCuPB3CMl4ONTegeYpC0wIg68YZM0CuBpbjspnYwz/1a942eab068a2173e66d08c736283cfe22e1c1ed" // } // } // ] // }, // "Crypto_Chain": { // "Crypto_Chain__": "chain-xjbini-7wlz-dmzf-gm7z-zf7ei6fq", // "EVM_Chain__": null, // "Crypto_Token__": "crtok-c5v3mh-grfn-hl5d-lmel-fvggbf4i", // "Name": "Bitcoin", // "Key": "bitcoin", // "Type": "Bitcoin", // "Curve": "secp256k1", // "Backend_Url": null, // "Wallet_Verification_Methods": { // "signature": true // }, // "Block_Margin": "3", // "Created": { // "unix": "1725340084", // "us": "0", // "iso": "2024-09-03 05:08:04.000000", // "tz": "UTC", // "full": "1725340084000000", // "unixms": "1725340084000" // } // } // } // const id = this.safeString(networkEntry, 'Crypto_Token__'); const token = this.safeDict(networkEntry, 'Crypto_Token', {}); const code = this.safeCurrencyCode(this.safeString(token, 'Symbol')); if (!(code in result)) { result[code] = { 'id': id, 'code': code, 'info': [], 'type': undefined, 'name': this.safeString(token, 'Name'), 'active': undefined, 'deposit': undefined, 'withdraw': undefined, 'fee': undefined, 'precision': undefined, 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': undefined, 'max': undefined, }, 'deposit': { 'min': undefined, 'max': undefined, }, }, 'networks': {}, }; } const networkId = this.safeString(networkEntry, 'Crypto_Chain__'); const cryptoChainDict = this.safeString(networkEntry, 'Crypto_Chain'); const networkName = this.safeString(cryptoChainDict, 'Type', 'default'); const networkCode = this.networkIdToCode(networkName); result[code]['networks'][networkCode] = { 'id': networkId, 'network': networkCode, 'active': this.safeString(networkEntry, 'Status') === 'valid', 'deposit': this.safeString(networkEntry, 'Can_Deposit') === 'Y', 'withdraw': undefined, 'fee': this.parseNumber(this.parseAmount(networkEntry['Withdraw_Fee'])), 'precision': this.parseNumber(this.parsePrecision(this.safeString(token, 'Decimals'))), 'limits': { 'amount': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': this.parseAmount(networkEntry['Minimum_Withdraw']), 'max': undefined, }, 'deposit': { 'min': this.parseAmount(networkEntry['Minimum_Deposit']), 'max': undefined, }, }, }; const infos = this.safeList(result[code], 'info', []); infos.push(networkEntry); result[code]['info'] = infos; } // only after all entries are formed in currencies, restructure each entry const allKeys = Object.keys(result); for (let i = 0; i < allKeys.length; i++) { const code = allKeys[i]; result[code] = this.safeCurrencyStructure(result[code]); // this is needed after adding network entry } return result; } /** * @method * @name ellipx#fetchTrades * @description fetches all completed trades for a particular market/symbol * @param {string} symbol unified market symbol (e.g. 'BTC/USDT') * @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 EllipX API endpoint * @param {string} [params.before] get trades before the given trade ID * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { await this.loadMarkets(); const market = this.market(symbol); const marketId = market['id']; const request = { 'currencyPair': marketId, }; // endpoint support before trade id. // The actual endpoint URL will be: https://data.ellipx.com/Market/{currencyPair}:getTrades // { // "id": "BTC_USDC:1731053859:914141972:0", // "pair": [ // "BTC", // "USDC" // ], // "bid": { // "id": "mktor-swishf-uv6n-hrzj-63ye-bdqnk33q", // "iss": "ellipx:beta", // "uniq": "order:1731053859:914141972:0" // }, // "ask": { // "id": "mktor-p3ozvt-qurz-gmzo-bf5n-g4rcuy6u", // "iss": "ellipx:beta", // "uniq": "order:1731053859:874659786:0" // }, // "type": "bid", // "amount": { // "v": "412", // "e": 8, // "f": 0.00000412 // }, // "price": { // "v": "75878090000", // "e": 6, // "f": 75878.09 // }, // "date": "2024-11-08T08:17:39.914141972Z" // } const response = await this.publicGetMarketCurrencyPairGetTrades(this.extend(request, params)); const data = this.safeDict(response, 'data', {}); const trades = this.safeList(data, 'trades', []); return this.parseTrades(trades, market, since, limit); } parseTrade(trade, market = undefined) { // Format of trade ID: "BTC_USDC:1731053859:914141972:0" const id = this.safeString(trade, 'id'); // fetchTrades and fetchMyTrades return different trade structures const date = this.safeDict(trade, 'date'); let timestamp = undefined; if (date === undefined) { timestamp = this.parse8601(this.safeString(trade, 'date')); } else { timestamp = this.safeInteger(date, 'unixms'); } const type = this.safeString(trade, 'type'); const side = (type === 'bid') ? 'buy' : 'sell'; const amount = this.safeDict(trade, 'amount'); const price = this.safeDict(trade, 'price'); const amountFloat = this.parseAmount(amount); const priceFloat = this.parseAmount(price); // fetchTrades and fetchMyTrades return different trade structures const pair = this.safeList(trade, 'pair'); let marketSymbol = undefined; if (pair === undefined) { const symbol = this.safeString(trade, 'pair'); const [base, quote] = symbol.split('_'); marketSymbol = base + '/' + quote; } else { marketSymbol = this.safeString(pair, 0) + '/' + this.safeString(pair, 1); } const bidOrder = this.safeDict(trade, 'bid'); const askOrder = this.safeDict(trade, 'ask'); const isBuy = (side === 'buy'); const orderId = isBuy ? this.safeString(bidOrder, 'id') : this.safeString(askOrder, 'id'); return this.safeTrade({ 'id': id, 'info': trade, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': marketSymbol, 'type': undefined, 'side': side, 'order': orderId, 'takerOrMaker': undefined, 'price': priceFloat, 'amount': amountFloat, 'cost': undefined, 'fee': undefined, }); } /** * @method * @name ellipx#fetchBalance * @description query for balance and get the amount of funds available for trading or funds locked in orders * @see https://docs.google.com/document/d/1ZXzTQYffKE_EglTaKptxGQERRnunuLHEMmar7VC9syM/edit?tab=t.0#heading=h.ihrjov144txg * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure} */ async fetchBalance(params = {}) { await this.loadMarkets(); const response = await this.privateGetUserWallet(params); // { // "User_Wallet__": "usw-vv7hzo-qel5-gupk-neqi-7f3wz5pq", // "User__": "usr-...", // "Realm__": "usrr-cb3c7n-qvxv-fdrb-uc2q-gpja2foi", // "Unit__": "unit-aebkye-u35b-e5zm-zt22-2qvwhsqa", // "Balance": { // "value": "0.00006394", // "value_int": "6394", // "value_disp": "0.00006394", // "value_xint": { // "v": "6394", // "e": 8, // "f": 0.00006394 // }, // "display": "0.00006394BTC", // "display_short": "0.00006394BTC", // "currency": "BTC", // "unit": "BTC", // "has_vat": false, // "tax_profile": null // }, // "Balance_Date": { // "unix": 1731128270, // "us": 426208, // "iso": "2024-11-09 04:57:50.426208", // "tz": "UTC", // "full": "1731128270426208", // "unixms": "1731128270426" // }, // "Liabilities": { // "value": "0.00000000", // "value_int": "0", // "value_disp": "0.00000000", // "value_xint": { // "v": "0", // "e": 8, // "f": 0 // }, // "display": "0.00000000BTC", // "display_short": "0.00000000BTC", // "currenc