ccxt
Version:
1,162 lines (1,159 loc) • 256 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/coincatch.js';
import { ArgumentsRequired, AuthenticationError, BadRequest, BadSymbol, DDoSProtection, ExchangeError, InvalidNonce, InsufficientFunds, InvalidOrder, NotSupported, OnMaintenance, OrderNotFound, PermissionDenied, RateLimitExceeded } 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 coincatch
* @augments Exchange
*/
export default class coincatch extends Exchange {
describe() {
return this.deepExtend(super.describe(), {
'id': 'coincatch',
'name': 'CoinCatch',
'countries': ['VG'],
'rateLimit': 50,
'version': 'v1',
'certified': false,
'pro': true,
'has': {
'CORS': undefined,
'spot': true,
'margin': false,
'swap': true,
'future': false,
'option': false,
'addMargin': true,
'cancelAllOrders': true,
'cancelAllOrdersAfter': false,
'cancelOrder': true,
'cancelOrders': true,
'cancelWithdraw': false,
'closePosition': false,
'createConvertTrade': false,
'createDepositAddress': false,
'createLimitBuyOrder': true,
'createLimitSellOrder': true,
'createMarketBuyOrder': true,
'createMarketBuyOrderWithCost': true,
'createMarketOrder': true,
'createMarketOrderWithCost': false,
'createMarketSellOrder': true,
'createMarketSellOrderWithCost': false,
'createOrder': true,
'createOrders': true,
'createOrderWithTakeProfitAndStopLoss': true,
'createPostOnlyOrder': true,
'createReduceOnlyOrder': true,
'createStopLimitOrder': true,
'createStopLossOrder': true,
'createStopMarketOrder': true,
'createStopOrder': true,
'createTakeProfitOrder': true,
'createTrailingAmountOrder': false,
'createTrailingPercentOrder': false,
'createTriggerOrder': true,
'fetchAccounts': false,
'fetchBalance': true,
'fetchCanceledAndClosedOrders': true,
'fetchCanceledOrders': false,
'fetchClosedOrder': false,
'fetchClosedOrders': false,
'fetchConvertCurrencies': false,
'fetchConvertQuote': false,
'fetchConvertTrade': false,
'fetchConvertTradeHistory': false,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchDepositsWithdrawals': false,
'fetchDepositWithdrawFees': true,
'fetchFundingHistory': false,
'fetchFundingRate': true,
'fetchFundingRateHistory': true,
'fetchFundingRates': false,
'fetchIndexOHLCV': false,
'fetchLedger': true,
'fetchLeverage': true,
'fetchLeverageTiers': false,
'fetchMarginAdjustmentHistory': false,
'fetchMarginMode': true,
'fetchMarkets': true,
'fetchMarkOHLCV': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterestHistory': false,
'fetchOpenOrder': false,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrders': false,
'fetchOrderTrades': true,
'fetchPosition': true,
'fetchPositionHistory': false,
'fetchPositionMode': true,
'fetchPositions': true,
'fetchPositionsForSymbol': true,
'fetchPositionsHistory': false,
'fetchPremiumIndexOHLCV': false,
'fetchStatus': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
'fetchTransactions': false,
'fetchTransfers': false,
'fetchWithdrawals': true,
'reduceMargin': true,
'sandbox': false,
'setLeverage': true,
'setMargin': false,
'setMarginMode': true,
'setPositionMode': true,
'transfer': false,
'withdraw': true,
},
'timeframes': {
'1m': '1m',
'3m': '3m',
'5m': '5m',
'15': '15m',
'30': '30m',
'1h': '1H',
'2h': '2H',
'4h': '4H',
'6h': '6H',
'12h': '12H',
'1d': '1D',
'3d': '3D',
'1w': '1W',
'1M': '1M',
},
'urls': {
'logo': 'https://github.com/user-attachments/assets/3d49065f-f05d-4573-88a2-1b5201ec6ff3',
'api': {
'public': 'https://api.coincatch.com',
'private': 'https://api.coincatch.com',
},
'www': 'https://www.coincatch.com/',
'doc': 'https://coincatch.github.io/github.io/en/',
'fees': 'https://www.coincatch.com/en/rate/',
'referral': {
'url': 'https://partner.coincatch.cc/bg/92hy70391729607848548',
'discount': 0.1,
},
},
'api': {
'public': {
'get': {
'api/spot/v1/public/time': 1,
'api/spot/v1/public/currencies': 20 / 3,
'api/spot/v1/market/ticker': 1,
'api/spot/v1/market/tickers': 1,
'api/spot/v1/market/fills': 2,
'api/spot/v1/market/fills-history': 2,
'api/spot/v1/market/candles': 1,
'api/spot/v1/market/history-candles': 1,
'api/spot/v1/market/depth': 1,
'api/spot/v1/market/merge-depth': 1,
'api/mix/v1/market/contracts': 1,
'api/mix/v1/market/merge-depth': 1,
'api/mix/v1/market/depth': 1,
'api/mix/v1/market/ticker': 1,
'api/mix/v1/market/tickers': 1,
'api/mix/v1/market/fills': 1,
'api/mix/v1/market/fills-history': 1,
'api/mix/v1/market/candles': 1,
'pi/mix/v1/market/index': 1,
'api/mix/v1/market/funding-time': 1,
'api/mix/v1/market/history-fundRate': 1,
'api/mix/v1/market/current-fundRate': 1,
'api/mix/v1/market/open-interest': 1,
'api/mix/v1/market/mark-price': 1,
'api/mix/v1/market/symbol-leverage': 1,
'api/mix/v1/market/queryPositionLever': 1,
},
},
'private': {
'get': {
'api/spot/v1/wallet/deposit-address': 4,
'pi/spot/v1/wallet/withdrawal-list': 1,
'api/spot/v1/wallet/withdrawal-list-v2': 1,
'api/spot/v1/wallet/deposit-list': 1,
'api/spot/v1/account/getInfo': 1,
'api/spot/v1/account/assets': 2,
'api/spot/v1/account/transferRecords': 1,
'api/mix/v1/account/account': 2,
'api/mix/v1/account/accounts': 2,
'api/mix/v1/position/singlePosition-v2': 2,
'api/mix/v1/position/allPosition-v2': 4,
'api/mix/v1/account/accountBill': 2,
'api/mix/v1/account/accountBusinessBill': 4,
'api/mix/v1/order/current': 1,
'api/mix/v1/order/marginCoinCurrent': 1,
'api/mix/v1/order/history': 2,
'api/mix/v1/order/historyProductType': 4,
'api/mix/v1/order/detail': 2,
'api/mix/v1/order/fills': 2,
'api/mix/v1/order/allFills': 2,
'api/mix/v1/plan/currentPlan': 1,
'api/mix/v1/plan/historyPlan': 2, // done
},
'post': {
'api/spot/v1/wallet/transfer-v2': 4,
'api/spot/v1/wallet/withdrawal-v2': 4,
'api/spot/v1/wallet/withdrawal-inner-v2': 1,
'api/spot/v1/account/bills': 2,
'api/spot/v1/trade/orders': 2,
'api/spot/v1/trade/batch-orders': { 'cost': 4, 'step': 10 },
'api/spot/v1/trade/cancel-order': 1,
'api/spot/v1/trade/cancel-order-v2': 2,
'api/spot/v1/trade/cancel-symbol-order': 2,
'api/spot/v1/trade/cancel-batch-orders': 1,
'api/spot/v1/trade/cancel-batch-orders-v2': 1,
'api/spot/v1/trade/orderInfo': 1,
'api/spot/v1/trade/open-orders': 1,
'api/spot/v1/trade/history': 1,
'api/spot/v1/trade/fills': 1,
'api/spot/v1/plan/placePlan': 1,
'api/spot/v1/plan/modifyPlan': 1,
'api/spot/v1/plan/cancelPlan': 1,
'api/spot/v1/plan/currentPlan': 1,
'api/spot/v1/plan/historyPlan': 1,
'api/spot/v1/plan/batchCancelPlan': 2,
'api/mix/v1/account/open-count': 1,
'api/mix/v1/account/setLeverage': 4,
'api/mix/v1/account/setMargin': 4,
'api/mix/v1/account/setMarginMode': 4,
'api/mix/v1/account/setPositionMode': 4,
'api/mix/v1/order/placeOrder': 2,
'api/mix/v1/order/batch-orders': { 'cost': 4, 'step': 10 },
'api/mix/v1/order/cancel-order': 2,
'api/mix/v1/order/cancel-batch-orders': 2,
'api/mix/v1/order/cancel-symbol-orders': 2,
'api/mix/v1/order/cancel-all-orders': 2,
'api/mix/v1/plan/placePlan': 2,
'api/mix/v1/plan/modifyPlan': 2,
'api/mix/v1/plan/modifyPlanPreset': 2,
'api/mix/v1/plan/placeTPSL': 2,
'api/mix/v1/plan/placeTrailStop': 2,
'api/mix/v1/plan/placePositionsTPSL': 2,
'api/mix/v1/plan/modifyTPSLPlan': 2,
'api/mix/v1/plan/cancelPlan': 2,
'api/mix/v1/plan/cancelSymbolPlan': 2,
'api/mix/v1/plan/cancelAllPlan': 2, // done
},
},
},
'requiredCredentials': {
'apiKey': true,
'secret': true,
'password': true,
},
'fees': {
'trading': {
'spot': {
'tierBased': false,
'percentage': true,
'feeSide': 'get',
'maker': this.parseNumber('0.001'),
'taker': this.parseNumber('0.001'),
},
},
},
'options': {
'brokerId': '47cfy',
'createMarketBuyOrderRequiresPrice': true,
'timeframes': {
'spot': {
'1m': '1min',
'5m': '5min',
'15m': '15min',
'30m': '30min',
'1h': '1h',
'4h': '4h',
'6h': '6h',
'12h': '12h',
'1d': '1day',
'3d': '3day',
'1w': '1week',
'1M': '1M',
},
'swap': {
'1m': '1m',
'3m': '3m',
'5m': '5m',
'15': '15m',
'30': '30m',
'1h': '1H',
'2h': '2H',
'4h': '4H',
'6h': '6H',
'12h': '12H',
'1d': '1D',
'3d': '3D',
'1w': '1W',
'1M': '1M',
},
},
'currencyIdsListForParseMarket': undefined,
'broker': '',
'networks': {
'BTC': 'BITCOIN',
'ERC20': 'ERC20',
'TRC20': 'TRC20',
'BEP20': 'BEP20',
'ARB': 'ArbitrumOne',
'OPTIMISM': 'Optimism',
'LTC': 'LTC',
'BCH': 'BCH',
'ETC': 'ETC',
'SOL': 'SOL',
'NEO3': 'NEO3',
'STX': 'stacks',
'EGLD': 'Elrond',
'NEAR': 'NEARProtocol',
'ACA': 'AcalaToken',
'KLAY': 'Klaytn',
'FTM': 'Fantom',
'TERRA': 'Terra',
'WAVES': 'WAVES',
'TAO': 'TAO',
'SUI': 'SUI',
'SEI': 'SEI',
'RUNE': 'THORChain',
'ZIL': 'ZIL',
'SXP': 'Solar',
'FET': 'FET',
'AVAX': 'C-Chain',
'XRP': 'XRP',
'EOS': 'EOS',
'DOGE': 'DOGECOIN',
'CAP20': 'CAP20',
'MATIC': 'Polygon',
'CSPR': 'CSPR',
'GLMR': 'Moonbeam',
'MINA': 'MINA',
'CFX': 'CFX',
'STRAT': 'StratisEVM',
'TIA': 'Celestia',
'ChilizChain': 'ChilizChain',
'APT': 'Aptos',
'ONT': 'Ontology',
'ICP': 'ICP',
'ADA': 'Cardano',
'FIL': 'FIL',
'CELO': 'CELO',
'DOT': 'DOT',
'XLM': 'StellarLumens',
'ATOM': 'ATOM',
'CRO': 'CronosChain',
},
'networksById': {
'TRC20': 'TRC20',
'TRX(TRC20)': 'TRC20',
'ArbitrumOne': 'ARB',
'THORChain': 'RUNE',
'Solar': 'SXP',
'C-Chain': 'AVAX',
'CAP20': 'CAP20',
'CFXeSpace': 'CFX',
'CFX': 'CFX',
'StratisEVM': 'STRAT',
'ChilizChain': 'ChilizChain',
'StellarLumens': 'XLM',
'CronosChain': 'CRO', // todo check
},
},
'features': {
'default': {
'sandbox': false,
'createOrder': {
'marginMode': false,
'triggerPrice': true,
'triggerPriceType': {
'last': true,
'mark': true,
'index': false,
},
'triggerDirection': false,
'stopLossPrice': false,
'takeProfitPrice': false,
'attachedStopLossTakeProfit': undefined,
'timeInForce': {
'IOC': true,
'FOK': true,
'PO': true,
'GTD': false,
},
'hedged': false,
'trailing': false,
'leverage': false,
'marketBuyByCost': true,
'marketBuyRequiresPrice': false,
'selfTradePrevention': false,
'iceberg': false,
},
'createOrders': {
'max': 50,
},
'fetchMyTrades': {
'marginMode': false,
'limit': 500,
'daysBack': 100000,
'untilDays': 100000,
'symbolRequired': true,
},
'fetchOrder': {
'marginMode': false,
'trigger': false,
'trailing': false,
'symbolRequired': false,
},
'fetchOpenOrders': {
'marginMode': false,
'limit': 100,
'trigger': true,
'trailing': false,
'marketType': true,
'symbolRequired': false,
},
'fetchOrders': undefined,
'fetchClosedOrders': undefined,
'fetchOHLCV': {
'limit': 1000,
},
},
'spot': {
'extends': 'default',
},
'forDerivatives': {
'extends': 'default',
'createOrder': {
// todo check
'attachedStopLossTakeProfit': {
'triggerPriceType': undefined,
'price': false,
},
},
'fetchMyTrades': {
'limit': 100,
},
},
'swap': {
'linear': {
'extends': 'forDerivatives',
},
'inverse': {
'extends': 'forDerivatives',
},
},
'future': {
'linear': undefined,
'inverse': undefined,
},
},
'commonCurrencies': {},
'exceptions': {
'exact': {
'22001': OrderNotFound,
'429': DDoSProtection,
'40001': AuthenticationError,
'40002': AuthenticationError,
'40003': AuthenticationError,
'40005': InvalidNonce,
'40006': AuthenticationError,
'40007': BadRequest,
'40008': InvalidNonce,
'40009': AuthenticationError,
'40011': AuthenticationError,
'40012': AuthenticationError,
'40013': ExchangeError,
'40014': PermissionDenied,
'40015': ExchangeError,
'40016': PermissionDenied,
'40017': ExchangeError,
'40018': PermissionDenied,
'40019': BadRequest,
'40020': BadRequest,
'40034': BadRequest,
'400172': BadRequest,
'40912': BadRequest,
'40913': BadRequest,
'40102': BadRequest,
'40200': OnMaintenance,
'40305': BadRequest,
'40409': ExchangeError,
'40704': ExchangeError,
'40724': BadRequest,
'40725': ExchangeError,
'40762': InsufficientFunds,
'40774': BadRequest,
'40808': BadRequest,
'43001': OrderNotFound,
'43002': InvalidOrder,
'43004': OrderNotFound,
'43005': RateLimitExceeded,
'43006': BadRequest,
'43007': BadRequest,
'43008': BadRequest,
'43009': BadRequest,
'43010': BadRequest,
'43011': BadRequest,
'43012': InsufficientFunds,
'43117': InsufficientFunds,
'43118': BadRequest,
'43122': BadRequest,
'45006': InsufficientFunds,
'45110': BadRequest, // less than the minimum amount {0} {1}
// {"code":"40913","msg":"orderId or clientOrderId must be passed one","requestTime":1726160988275,"data":null}
},
'broad': {},
},
'precisionMode': TICK_SIZE,
});
}
calculateRateLimiterCost(api, method, path, params, config = {}) {
const step = this.safeInteger(config, 'step');
const cost = this.safeInteger(config, 'cost', 1);
const orders = this.safeList2(params, 'orderList', 'orderDataList', []);
const ordersLength = orders.length;
if ((step !== undefined) && (ordersLength > step)) {
const numberOfSteps = Math.ceil(ordersLength / step);
return cost * numberOfSteps;
}
else {
return cost;
}
}
/**
* @method
* @name coincatch#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @see https://coincatch.github.io/github.io/en/spot/#get-server-time
* @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.publicGetApiSpotV1PublicTime(params);
//
// {
// "code": "00000",
// "msg": "success",
// "requestTime": 1725046822028,
// "data": "1725046822028"
// }
//
return this.safeInteger(response, 'data');
}
/**
* @method
* @name coincatch#fetchCurrencies
* @description fetches all available currencies on an exchange
* @see https://coincatch.github.io/github.io/en/spot/#get-coin-list
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an associative dictionary of currencies
*/
async fetchCurrencies(params = {}) {
const response = await this.publicGetApiSpotV1PublicCurrencies(params);
const data = this.safeList(response, 'data', []);
//
// {
// "code": "00000",
// "msg": "success",
// "requestTime": 1725102364202,
// "data": [
// {
// "coinId": "1",
// "coinName": "BTC",
// "transfer": "true",
// "chains": [
// {
// "chainId": "10",
// "chain": "BITCOIN",
// "needTag": "false",
// "withdrawable": "true",
// "rechargeable": "true",
// "withdrawFee": "0.0005",
// "extraWithDrawFee": "0",
// "depositConfirm": "1",
// "withdrawConfirm": "1",
// "minDepositAmount": "0.00001",
// "minWithdrawAmount": "0.001",
// "browserUrl": "https://blockchair.com/bitcoin/transaction/"
// }
// ]
// },
// ...
// ]
// }
//
const result = {};
const currenciesIds = [];
for (let i = 0; i < data.length; i++) {
const currecy = data[i];
const currencyId = this.safeString(currecy, 'coinName');
currenciesIds.push(currencyId);
const code = this.safeCurrencyCode(currencyId);
const networks = this.safeList(currecy, 'chains');
const parsedNetworks = {};
for (let j = 0; j < networks.length; j++) {
const network = networks[j];
const networkId = this.safeString(network, 'chain');
const networkCode = this.networkCodeToId(networkId);
parsedNetworks[networkId] = {
'id': networkId,
'network': networkCode,
'limits': {
'deposit': {
'min': this.safeNumber(network, 'minDepositAmount'),
'max': undefined,
},
'withdraw': {
'min': this.safeNumber(network, 'minWithdrawAmount'),
'max': undefined,
},
},
'active': undefined,
'deposit': this.safeString(network, 'rechargeable') === 'true',
'withdraw': this.safeString(network, 'withdrawable') === 'true',
'fee': this.safeNumber(network, 'withdrawFee'),
'precision': undefined,
'info': network,
};
}
result[code] = this.safeCurrencyStructure({
'id': currencyId,
'numericId': this.safeInteger(currecy, 'coinId'),
'code': code,
'precision': undefined,
'type': undefined,
'name': undefined,
'active': undefined,
'deposit': undefined,
'withdraw': undefined,
'fee': undefined,
'limits': {
'deposit': {
'min': undefined,
'max': undefined,
},
'withdraw': {
'min': undefined,
'max': undefined,
},
},
'networks': parsedNetworks,
'info': currecy,
});
}
if (this.safeList(this.options, 'currencyIdsListForParseMarket') === undefined) {
this.options['currencyIdsListForParseMarket'] = currenciesIds;
}
return result;
}
/**
* @method
* @name coincatch#fetchDepositWithdrawFees
* @description fetch deposit and withdraw fees
* @see https://coincatch.github.io/github.io/en/spot/#get-coin-list
* @param {string[]} [codes] list of unified currency codes
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a list of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure}
*/
async fetchDepositWithdrawFees(codes = undefined, params = {}) {
await this.loadMarkets();
const response = await this.publicGetApiSpotV1PublicCurrencies(params);
const data = this.safeList(response, 'data', []);
return this.parseDepositWithdrawFees(data, codes, 'coinName');
}
parseDepositWithdrawFee(fee, currency = undefined) {
//
// {
// "coinId":"1",
// "coinName":"BTC",
// "transfer":"true",
// "chains":[
// {
// "chain":null,
// "needTag":"false",
// "withdrawable":"true",
// "rechargeAble":"true",
// "withdrawFee":"0.005",
// "depositConfirm":"1",
// "withdrawConfirm":"1",
// "minDepositAmount":"0.001",
// "minWithdrawAmount":"0.001",
// "browserUrl":"https://blockchair.com/bitcoin/testnet/transaction/"
// }
// ]
// }
//
const chains = this.safeList(fee, 'chains', []);
const chainsLength = chains.length;
const result = {
'info': fee,
'withdraw': {
'fee': undefined,
'percentage': undefined,
},
'deposit': {
'fee': undefined,
'percentage': undefined,
},
'networks': {},
};
for (let i = 0; i < chainsLength; i++) {
const chain = chains[i];
const networkId = this.safeString(chain, 'chain');
const currencyCode = this.safeString(currency, 'code');
const networkCode = this.networkIdToCode(networkId, currencyCode);
result['networks'][networkCode] = {
'deposit': { 'fee': undefined, 'percentage': undefined },
'withdraw': { 'fee': this.safeNumber(chain, 'withdrawFee'), 'percentage': false },
};
if (chainsLength === 1) {
result['withdraw']['fee'] = this.safeNumber(chain, 'withdrawFee');
result['withdraw']['percentage'] = false;
}
}
return result;
}
/**
* @method
* @name coincatch#fetchMarkets
* @description retrieves data on all markets for the exchange
* @see https://coincatch.github.io/github.io/en/spot/#get-all-tickers
* @see https://coincatch.github.io/github.io/en/mix/#get-all-symbols
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object[]} an array of objects representing market data
*/
async fetchMarkets(params = {}) {
let response = await this.publicGetApiSpotV1MarketTickers(params);
//
// {
// "code": "00000",
// "msg": "success",
// "requestTime": 1725114040155,
// "data": [
// {
// "symbol": "BTCUSDT",
// "high24h": "59461.34",
// "low24h": "57723.23",
// "close": "59056.02",
// "quoteVol": "18240112.23368",
// "baseVol": "309.05564",
// "usdtVol": "18240112.2336744",
// "ts": "1725114038951",
// "buyOne": "59055.85",
// "sellOne": "59057.45",
// "bidSz": "0.0139",
// "askSz": "0.0139",
// "openUtc0": "59126.71",
// "changeUtc": "-0.0012",
// "change": "0.01662"
// },
// ...
// ]
// }
//
if (this.safeList(this.options, 'currencyIdsListForParseMarket') === undefined) {
await this.fetchCurrencies();
}
const spotMarkets = this.safeList(response, 'data', []);
const request = {};
let productType = undefined;
[productType, params] = this.handleOptionAndParams(params, 'fetchMarkets', 'productType', productType);
let swapMarkets = [];
request['productType'] = 'umcbl';
response = await this.publicGetApiMixV1MarketContracts(this.extend(request, params));
//
// {
// "code": "00000",
// "msg": "success",
// "requestTime": 1725297439225,
// "data": [
// {
// "symbol": "BTCUSDT_UMCBL",
// "makerFeeRate": "0.0002",
// "takerFeeRate": "0.0006",
// "feeRateUpRatio": "0.005",
// "openCostUpRatio": "0.01",
// "quoteCoin": "USDT",
// "baseCoin": "BTC",
// "buyLimitPriceRatio": "0.01",
// "sellLimitPriceRatio": "0.01",
// "supportMarginCoins": [ "USDT" ],
// "minTradeNum": "0.001",
// "priceEndStep": "1",
// "volumePlace": "3",
// "pricePlace": "1",
// "sizeMultiplier": "0.001",
// "symbolType": "perpetual",
// "symbolStatus": "normal",
// "offTime": "-1",
// "limitOpenTime": "-1",
// "maintainTime": "",
// "symbolName": "BTCUSDT",
// "minTradeUSDT": null,
// "maxPositionNum": null,
// "maxOrderNum": null
// }
// ]
// }
//
const swapUMCBL = this.safeList(response, 'data', []);
request['productType'] = 'dmcbl';
response = await this.publicGetApiMixV1MarketContracts(this.extend(request, params));
//
// {
// "code":"00000",
// "msg":"success",
// "requestTime":1725297439646,
// "data":[
// {
// "symbol":"BTCUSD_DMCBL",
// "makerFeeRate":"0.0002",
// "takerFeeRate":"0.0006",
// "feeRateUpRatio":"0.005",
// "openCostUpRatio":"0.01",
// "quoteCoin":"USD",
// "baseCoin":"BTC",
// "buyLimitPriceRatio":"0.01",
// "sellLimitPriceRatio":"0.01",
// "supportMarginCoins":[
// "BTC",
// "ETH"
// ],
// "minTradeNum":"0.001",
// "priceEndStep":"1",
// "volumePlace":"3",
// "pricePlace":"1",
// "sizeMultiplier":"0.001",
// "symbolType":"perpetual",
// "symbolStatus":"normal",
// "offTime":"-1",
// "limitOpenTime":"-1",
// "maintainTime":"",
// "symbolName":"BTCUSD",
// "minTradeUSDT":null,
// "maxPositionNum":null,
// "maxOrderNum":null
// }
// ]
// }
const swapDMCBL = this.safeList(response, 'data', []);
const swapDMCBLExtended = [];
for (let i = 0; i < swapDMCBL.length; i++) {
const market = swapDMCBL[i];
const supportMarginCoins = this.safeList(market, 'supportMarginCoins', []);
for (let j = 0; j < supportMarginCoins.length; j++) {
const settle = supportMarginCoins[j];
const obj = {
'supportMarginCoins': [settle],
};
swapDMCBLExtended.push(this.extend(market, obj));
}
}
swapMarkets = this.arrayConcat(swapUMCBL, swapDMCBLExtended);
const markets = this.arrayConcat(spotMarkets, swapMarkets);
return this.parseMarkets(markets);
}
parseMarket(market) {
//
// spot
// {
// "symbol": "BTCUSDT",
// "high24h": "59461.34",
// "low24h": "57723.23",
// "close": "59056.02",
// "quoteVol": "18240112.23368",
// "baseVol": "309.05564",
// "usdtVol": "18240112.2336744",
// "ts": "1725114038951",
// "buyOne": "59055.85",
// "sellOne": "59057.45",
// "bidSz": "0.0139",
// "askSz": "0.0139",
// "openUtc0": "59126.71",
// "changeUtc": "-0.0012",
// "change": "0.01662"
// },
//
// swap
// {
// "symbol": "BTCUSDT_UMCBL",
// "makerFeeRate": "0.0002",
// "takerFeeRate": "0.0006",
// "feeRateUpRatio": "0.005",
// "openCostUpRatio": "0.01",
// "quoteCoin": "USDT",
// "baseCoin": "BTC",
// "buyLimitPriceRatio": "0.01",
// "sellLimitPriceRatio": "0.01",
// "supportMarginCoins": [ "USDT" ],
// "minTradeNum": "0.001",
// "priceEndStep": "1",
// "volumePlace": "3",
// "pricePlace": "1",
// "sizeMultiplier": "0.001",
// "symbolType": "perpetual",
// "symbolStatus": "normal",
// "offTime": "-1",
// "limitOpenTime": "-1",
// "maintainTime": "",
// "symbolName": "BTCUSDT",
// "minTradeUSDT": null,
// "maxPositionNum": null,
// "maxOrderNum": null
// }
//
let marketId = this.safeString(market, 'symbol');
const tradingFees = this.safeDict(this.fees, 'trading');
const fees = this.safeDict(tradingFees, 'spot');
let baseId = this.safeString(market, 'baseCoin');
let quoteId = this.safeString(market, 'quoteCoin');
let settleId = undefined;
let suffix = '';
let settle = undefined;
let type = 'spot';
let isLinear = undefined;
let isInverse = undefined;
let subType = undefined;
const isSpot = baseId === undefined; // for now spot markets have no properties baseCoin and quoteCoin
if (isSpot) {
const parsedMarketId = this.parseSpotMarketId(marketId);
baseId = this.safeString(parsedMarketId, 'baseId');
quoteId = this.safeString(parsedMarketId, 'quoteId');
marketId += '_SPBL'; // spot markets should have current suffix
}
else {
type = 'swap';
fees['taker'] = this.safeNumber(market, 'takerFeeRate');
fees['maker'] = this.safeNumber(market, 'makerFeeRate');
const supportMarginCoins = this.safeList(market, 'supportMarginCoins', []);
settleId = this.safeString(supportMarginCoins, 0);
settle = this.safeCurrencyCode(settleId);
suffix = ':' + settle;
isLinear = quoteId === settleId; // todo check
isInverse = baseId === settleId; // todo check
if (isLinear) {
subType = 'linear';
}
else if (isInverse) {
subType = 'inverse';
}
}
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const symbol = base + '/' + quote + suffix;
const symbolStatus = this.safeString(market, 'symbolStatus');
const active = symbolStatus ? (symbolStatus === 'normal') : undefined;
const volumePlace = this.safeString(market, 'volumePlace');
const amountPrecisionString = this.parsePrecision(volumePlace);
const pricePlace = this.safeString(market, 'pricePlace');
const priceEndStep = this.safeString(market, 'priceEndStep');
const pricePrecisionString = Precise.stringMul(this.parsePrecision(pricePlace), priceEndStep);
return this.safeMarketStructure({
'id': marketId,
'symbol': symbol,
'base': base,
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
'active': active,
'type': type,
'subType': subType,
'spot': isSpot,
'margin': isSpot ? false : undefined,
'swap': !isSpot,
'future': false,
'option': false,
'contract': !isSpot,
'settle': settle,
'settleId': settleId,
'contractSize': this.safeNumber(market, 'sizeMultiplier'),
'linear': isLinear,
'inverse': isInverse,
'taker': this.safeNumber(fees, 'taker'),
'maker': this.safeNumber(fees, 'maker'),
'percentage': this.safeBool(fees, 'percentage'),
'tierBased': this.safeBool(fees, 'tierBased'),
'feeSide': this.safeString(fees, 'feeSide'),
'expiry': undefined,
'expiryDatetime': undefined,
'strike': undefined,
'optionType': undefined,
'precision': {
'amount': this.parseNumber(amountPrecisionString),
'price': this.parseNumber(pricePrecisionString),
},
'limits': {
'amount': {
'min': this.safeNumber(market, 'minTradeNum'),
'max': undefined,
},
'price': {
'min': undefined,
'max': undefined,
},
'leverage': {
'min': undefined,
'max': undefined,
},
'cost': {
'min': undefined,
'max': undefined,
},
},
'created': undefined,
'info': market,
});
}
parseSpotMarketId(marketId) {
let baseId = undefined;
let quoteId = undefined;
const currencyIds = this.safeList(this.options, 'currencyIdsListForParseMarket', []);
for (let i = 0; i < currencyIds.length; i++) {
const currencyId = currencyIds[i];
const entryIndex = marketId.indexOf(currencyId);
if (entryIndex > -1) {
const restId = marketId.replace(currencyId, '');
if (entryIndex === 0) {
baseId = currencyId;
quoteId = restId;
}
else {
baseId = restId;
quoteId = currencyId;
}
break;
}
}
const result = {
'baseId': baseId,
'quoteId': quoteId,
};
return result;
}
/**
* @method
* @name coincatch#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://coincatch.github.io/github.io/en/spot/#get-single-ticker
* @see https://coincatch.github.io/github.io/en/mix/#get-single-symbol-ticker
* @param {string} symbol unified symbol of the market to fetch the ticker for
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
async fetchTicker(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
let response = undefined;
if (market['spot']) {
response = await this.publicGetApiSpotV1MarketTicker(this.extend(request, params));
//
// {
// "code": "00000",
// "msg": "success",
// "requestTime": 1725132487751,
// "data": {
// "symbol": "ETHUSDT",
// "high24h": "2533.76",
// "low24h": "2492.72",
// "close": "2499.76",
// "quoteVol": "21457850.7442",
// "baseVol": "8517.1869",
// "usdtVol": "21457850.744163",
// "ts": "1725132487476",
// "buyOne": "2499.75",
// "sellOne": "2499.76",
// "bidSz": "0.5311",
// "askSz": "4.5806",
// "openUtc0": "2525.69",
// "changeUtc": "-0.01027",
// "change": "-0.00772"
// }
// }
//
}
else if (market['swap']) {
response = await this.publicGetApiMixV1MarketTicker(this.extend(request, params));
//
// {
// "code": "00000",
// "msg": "success",
// "requestTime": 1725316687174,
// "data": {
// "symbol": "ETHUSDT_UMCBL",
// "last": "2540.6",
// "bestAsk": "2540.71",
// "bestBid": "2540.38",
// "bidSz": "12.1",
// "askSz": "20",
// "high24h": "2563.91",
// "low24h": "2398.3",
// "timestamp": "1725316687177",
// "priceChangePercent": "0.01134",
// "baseVolume": "706928.96",
// "quoteVolume": "1756401737.8766",
// "usdtVolume": "1756401737.8766",
// "openUtc": "2424.49",
// "chgUtc": "0.04789",
// "indexPrice": "2541.977142",
// "fundingRate": "0.00006",
// "holdingAmount": "144688.49",
// "deliveryStartTime": null,
// "deliveryTime": null,
// "deliveryStatus": "normal"
// }
// }
//
}
else {
throw new NotSupported(this.id + ' ' + 'fetchTicker() is not supported for ' + market['type'] + ' type of markets');
}
const data = this.safeDict(response, 'data', {});
return this.parseTicker(data, market);
}
/**
* @method
* @name coincatch#fetchTickers
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
* @see https://coincatch.github.io/github.io/en/spot/#get-all-tickers
* @see https://coincatch.github.io/github.io/en/mix/#get-all-symbol-ticker
* @param {string[]} [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
* @param {string} [params.type] 'spot' or 'swap' (default 'spot')
* @param {string} [params.productType] 'umcbl' or 'dmcbl' (default 'umcbl') - USDT perpetual contract or Universal margin perpetual contract
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
*/
async fetchTickers(symbols = undefined, params = {}) {
const methodName = 'fetchTickers';
await this.loadMarkets();
symbols = this.marketSymbols(symbols, undefined, true, true);
const market = this.getMarketFromSymbols(symbols);
let marketType = 'spot';
[marketType, params] = this.handleMarketTypeAndParams(methodName, market, params, marketType);
let response = undefined;
if (marketType === 'spot') {
response = await this.publicGetApiSpotV1MarketTickers(params);
//
// {
// "code": "00000",
// "msg": "success",
// "requestTime": 1725114040155,
// "data": [
// {