ccxt
Version:
1,141 lines (1,139 loc) • 87.5 kB
JavaScript
// ----------------------------------------------------------------------------
// 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