UNPKG

ccxt

Version:

A cryptocurrency trading API with more than 100 exchanges in JavaScript / TypeScript / Python / C# / PHP / Go

1,125 lines (1,122 loc) • 135 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 { ed25519 } from '@noble/curves/ed25519.js'; import { keccak_256 as keccak } from '@noble/hashes/sha3.js'; import { secp256k1 } from '@noble/curves/secp256k1.js'; import Exchange from './abstract/modetrade.js'; import { AuthenticationError, RateLimitExceeded, BadRequest, ExchangeError, InvalidOrder, InsufficientFunds, ArgumentsRequired, NetworkError, NotSupported } from './base/errors.js'; import { TICK_SIZE } from './base/functions/number.js'; import { Precise } from './base/Precise.js'; import { ecdsa, eddsa } from './base/functions/crypto.js'; // --------------------------------------------------------------------------- /** * @class modetrade * @augments Exchange */ export default class modetrade extends Exchange { describe() { return this.deepExtend(super.describe(), { 'id': 'modetrade', 'name': 'Mode Trade', 'countries': ['KY'], // Cayman Islands 'rateLimit': 100, 'version': 'v1', 'certified': false, 'pro': true, 'dex': true, 'has': { 'CORS': undefined, 'spot': false, 'margin': false, 'swap': true, 'future': false, 'option': false, 'addMargin': false, 'cancelAllOrders': true, 'cancelOrder': true, 'cancelOrders': true, 'cancelWithdraw': false, 'closeAllPositions': false, 'closePosition': false, 'createConvertTrade': false, 'createDepositAddress': false, 'createMarketBuyOrderWithCost': false, 'createMarketOrder': true, 'createMarketOrderWithCost': false, 'createMarketSellOrderWithCost': false, 'createOrder': true, 'createOrderWithTakeProfitAndStopLoss': true, 'createReduceOnlyOrder': true, 'createStopLimitOrder': true, 'createStopLossOrder': true, 'createStopMarketOrder': true, 'createStopOrder': true, 'createTakeProfitOrder': true, 'createTrailingAmountOrder': false, 'createTrailingPercentOrder': false, 'createTriggerOrder': true, 'fetchAccounts': false, 'fetchBalance': true, 'fetchCanceledOrders': false, 'fetchClosedOrder': false, 'fetchClosedOrders': true, 'fetchConvertCurrencies': false, 'fetchConvertQuote': false, 'fetchCurrencies': true, 'fetchDepositAddress': false, 'fetchDeposits': true, 'fetchDepositsWithdrawals': true, 'fetchFundingHistory': true, 'fetchFundingInterval': true, 'fetchFundingIntervals': false, 'fetchFundingRate': true, 'fetchFundingRateHistory': true, 'fetchFundingRates': true, 'fetchIndexOHLCV': false, 'fetchLedger': true, 'fetchLeverage': true, 'fetchMarginAdjustmentHistory': false, 'fetchMarginMode': false, 'fetchMarkets': true, 'fetchMarkOHLCV': false, 'fetchMyTrades': true, 'fetchOHLCV': true, 'fetchOpenInterestHistory': false, 'fetchOpenOrder': false, 'fetchOpenOrders': true, 'fetchOrder': true, 'fetchOrderBook': true, 'fetchOrders': true, 'fetchOrderTrades': true, 'fetchPosition': true, 'fetchPositionMode': false, 'fetchPositions': true, 'fetchPremiumIndexOHLCV': false, 'fetchStatus': true, 'fetchTicker': false, 'fetchTickers': false, 'fetchTime': true, 'fetchTrades': true, 'fetchTradingFee': false, 'fetchTradingFees': true, 'fetchTransactions': 'emulated', 'fetchTransfers': false, 'fetchWithdrawals': true, 'reduceMargin': false, 'setLeverage': true, 'setMargin': false, 'setPositionMode': false, 'transfer': false, 'withdraw': true, // exchange have that endpoint disabled atm, but was once implemented in ccxt per old docs: https://kronosresearch.github.io/wootrade-documents/#token-withdraw }, 'timeframes': { '1m': '1m', '5m': '5m', '15m': '15m', '30m': '30m', '1h': '1h', '4h': '4h', '12h': '12h', '1d': '1d', '1w': '1w', '1M': '1mon', '1y': '1y', }, 'urls': { 'logo': 'https://github.com/user-attachments/assets/bbde7d00-6e40-404f-8f34-8fb15893eb24', 'api': { 'public': 'https://api-evm.orderly.org', 'private': 'https://api-evm.orderly.org', }, 'test': { 'public': 'https://testnet-api-evm.orderly.org', 'private': 'https://testnet-api-evm.orderly.org', }, 'www': 'https://trade.mode.network', 'referral': { 'url': 'https://trade.mode.network?ref=MODETRADE', 'discount': 0.2, }, }, 'api': { 'v1': { 'public': { 'get': { 'public/volume/stats': 1, 'public/broker/name': 1, 'public/chain_info/{broker_id}': 1, 'public/system_info': 1, 'public/vault_balance': 1, 'public/insurancefund': 1, 'public/chain_info': 1, 'faucet/usdc': 1, 'public/account': 1, 'get_account': 1, 'registration_nonce': 1, 'get_orderly_key': 1, 'public/liquidation': 1, 'public/liquidated_positions': 1, 'public/config': 1, 'public/campaign/ranking': 10, 'public/campaign/stats': 10, 'public/campaign/user': 10, 'public/campaign/stats/details': 10, 'public/campaigns': 10, 'public/points/leaderboard': 1, 'client/points': 1, 'public/points/epoch': 1, 'public/points/epoch_dates': 1, 'public/referral/check_ref_code': 1, 'public/referral/verify_ref_code': 1, 'referral/admin_info': 1, 'referral/info': 1, 'referral/referee_info': 1, 'referral/referee_rebate_summary': 1, 'referral/referee_history': 1, 'referral/referral_history': 1, 'referral/rebate_summary': 1, 'client/distribution_history': 1, 'tv/config': 1, 'tv/history': 1, 'tv/symbol_info': 1, 'public/funding_rate_history': 1, 'public/funding_rate/{symbol}': 0.33, 'public/funding_rates': 1, 'public/info': 1, 'public/info/{symbol}': 1, 'public/market_trades': 1, 'public/token': 1, 'public/futures': 1, 'public/futures/{symbol}': 1, }, 'post': { 'register_account': 1, }, }, 'private': { 'get': { 'client/key_info': 6, 'client/orderly_key_ip_restriction': 6, 'order/{oid}': 1, 'client/order/{client_order_id}': 1, 'algo/order/{oid}': 1, 'algo/client/order/{client_order_id}': 1, 'orders': 1, 'algo/orders': 1, 'trade/{tid}': 1, 'trades': 1, 'order/{oid}/trades': 1, 'client/liquidator_liquidations': 1, 'liquidations': 1, 'asset/history': 60, 'client/holding': 1, 'withdraw_nonce': 1, 'settle_nonce': 1, 'pnl_settlement/history': 1, 'volume/user/daily': 60, 'volume/user/stats': 60, 'client/statistics': 60, 'client/info': 60, 'client/statistics/daily': 60, 'positions': 3.33, 'position/{symbol}': 3.33, 'funding_fee/history': 30, 'notification/inbox/notifications': 60, 'notification/inbox/unread': 60, 'volume/broker/daily': 60, 'broker/fee_rate/default': 10, 'broker/user_info': 10, 'orderbook/{symbol}': 1, 'kline': 1, }, 'post': { 'orderly_key': 1, 'client/set_orderly_key_ip_restriction': 6, 'client/reset_orderly_key_ip_restriction': 6, 'order': 1, 'batch-order': 10, 'algo/order': 1, 'liquidation': 1, 'claim_insurance_fund': 1, 'withdraw_request': 1, 'settle_pnl': 1, 'notification/inbox/mark_read': 60, 'notification/inbox/mark_read_all': 60, 'client/leverage': 120, 'client/maintenance_config': 60, 'delegate_signer': 10, 'delegate_orderly_key': 10, 'delegate_settle_pnl': 10, 'delegate_withdraw_request': 10, 'broker/fee_rate/set': 10, 'broker/fee_rate/set_default': 10, 'broker/fee_rate/default': 10, 'referral/create': 10, 'referral/update': 10, 'referral/bind': 10, 'referral/edit_split': 10, }, 'put': { 'order': 1, 'algo/order': 1, }, 'delete': { 'order': 1, 'algo/order': 1, 'client/order': 1, 'algo/client/order': 1, 'algo/orders': 1, 'orders': 1, 'batch-order': 1, 'client/batch-order': 1, }, }, }, }, 'requiredCredentials': { 'apiKey': true, 'secret': true, 'accountId': true, 'privateKey': false, }, 'fees': { 'trading': { 'tierBased': true, 'percentage': true, 'maker': this.parseNumber('0.0002'), 'taker': this.parseNumber('0.0005'), }, }, 'options': { 'sandboxMode': false, 'brokerId': 'CCXTMODE', 'verifyingContractAddress': '0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203', }, 'features': { 'default': { 'sandbox': true, 'createOrder': { 'marginMode': false, 'triggerPrice': true, 'triggerPriceType': undefined, 'triggerDirection': false, 'stopLossPrice': false, // todo by triggerPrice 'takeProfitPrice': false, // todo by triggerPrice 'attachedStopLossTakeProfit': undefined, 'timeInForce': { 'IOC': true, 'FOK': true, 'PO': true, 'GTD': false, }, 'hedged': false, 'trailing': true, 'leverage': true, // todo implement 'marketBuyByCost': false, 'marketBuyRequiresPrice': false, 'selfTradePrevention': false, 'iceberg': true, // todo implement }, 'createOrders': { 'max': 10, }, 'fetchMyTrades': { 'marginMode': false, 'limit': 500, 'daysBack': undefined, 'untilDays': 100000, 'symbolRequired': false, }, 'fetchOrder': { 'marginMode': false, 'trigger': true, 'trailing': false, 'symbolRequired': false, }, 'fetchOpenOrders': { 'marginMode': false, 'limit': 500, 'trigger': true, 'trailing': false, 'symbolRequired': false, }, 'fetchOrders': undefined, 'fetchClosedOrders': { 'marginMode': false, 'limit': 500, 'daysBack': undefined, 'daysBackCanceled': undefined, 'untilDays': 100000, 'trigger': true, 'trailing': false, 'symbolRequired': false, }, 'fetchOHLCV': { 'limit': 1000, }, }, 'spot': { 'extends': 'default', }, 'forDerivatives': { 'extends': 'default', 'createOrder': { // todo: implementation needs unification 'triggerPriceType': undefined, 'attachedStopLossTakeProfit': { // todo: implementation needs unification 'triggerPriceType': undefined, 'price': false, }, }, }, 'swap': { 'linear': { 'extends': 'forDerivatives', }, 'inverse': undefined, }, 'future': { 'linear': undefined, 'inverse': undefined, }, }, 'commonCurrencies': {}, 'exceptions': { 'exact': { '-1000': ExchangeError, // UNKNOWN The data does not exist '-1001': AuthenticationError, // INVALID_SIGNATURE The api key or secret is in wrong format. '-1002': AuthenticationError, // UNAUTHORIZED API key or secret is invalid, it may because key have insufficient permission or the key is expired/revoked. '-1003': RateLimitExceeded, // TOO_MANY_REQUEST Rate limit exceed. '-1004': BadRequest, // UNKNOWN_PARAM An unknown parameter was sent. '-1005': BadRequest, // INVALID_PARAM Some parameters are in wrong format for api. '-1006': InvalidOrder, // RESOURCE_NOT_FOUND The data is not found in server. For example, when client try canceling a CANCELLED order, will raise this error. '-1007': BadRequest, // DUPLICATE_REQUEST The data is already exists or your request is duplicated. '-1008': InvalidOrder, // QUANTITY_TOO_HIGH The quantity of settlement is too high than you can request. '-1009': InsufficientFunds, // CAN_NOT_WITHDRAWAL Can not request withdrawal settlement, you need to deposit other arrears first. '-1011': NetworkError, // RPC_NOT_CONNECT Can not place/cancel orders, it may because internal network error. Please try again in a few seconds. '-1012': BadRequest, // RPC_REJECT The place/cancel order request is rejected by internal module, it may because the account is in liquidation or other internal errors. Please try again in a few seconds. '-1101': InsufficientFunds, // RISK_TOO_HIGH The risk exposure for client is too high, it may cause by sending too big order or the leverage is too low. please refer to client info to check the current exposure. '-1102': InvalidOrder, // MIN_NOTIONAL The order value (price * size) is too small. '-1103': InvalidOrder, // PRICE_FILTER The order price is not following the tick size rule for the symbol. '-1104': InvalidOrder, // SIZE_FILTER The order quantity is not following the step size rule for the symbol. '-1105': InvalidOrder, // PERCENTAGE_FILTER Price is X% too high or X% too low from the mid price. '-1201': BadRequest, // LIQUIDATION_REQUEST_RATIO_TOO_SMALL total notional < 10000, least req ratio should = 1 '-1202': BadRequest, // LIQUIDATION_STATUS_ERROR No need to liquidation because user margin is enough. '29': BadRequest, // {"success":false,"code":29,"message":"Verify contract is invalid"} '9': AuthenticationError, // {"success":false,"code":9,"message":"Address and signature do not match"} '3': AuthenticationError, // {"success":false,"code":3,"message":"Signature error"} '2': BadRequest, // {"success":false,"code":2,"message":"Timestamp expired"} '15': BadRequest, // {"success":false,"code":15,"message":"BrokerId is not exist"} }, 'broad': {}, }, 'precisionMode': TICK_SIZE, }); } setSandboxMode(enable) { super.setSandboxMode(enable); this.options['sandboxMode'] = enable; } /** * @method * @name modetrade#fetchStatus * @description the latest known information on the availability of the exchange API * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-system-maintenance-status * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [status structure]{@link https://docs.ccxt.com/?id=exchange-status-structure} */ async fetchStatus(params = {}) { const response = await this.v1PublicGetPublicSystemInfo(params); // // { // "success": true, // "data": { // "status": 0, // "msg": "System is functioning properly." // }, // "timestamp": "1709274106602" // } // const data = this.safeDict(response, 'data', {}); let status = this.safeString(data, 'status'); if (status === undefined) { status = 'error'; } else if (status === '0') { status = 'ok'; } else { status = 'maintenance'; } return { 'status': status, 'updated': undefined, 'eta': undefined, 'url': undefined, 'info': response, }; } /** * @method * @name modetrade#fetchTime * @description fetches the current integer timestamp in milliseconds from the exchange server * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-system-maintenance-status * @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.v1PublicGetPublicSystemInfo(params); // // { // "success": true, // "data": { // "status": 0, // "msg": "System is functioning properly." // }, // "timestamp": "1709274106602" // } // return this.safeInteger(response, 'timestamp'); } parseMarket(market) { // // { // "symbol": "PERP_BTC_USDC", // "quote_min": 123, // "quote_max": 100000, // "quote_tick": 0.1, // "base_min": 0.00001, // "base_max": 20, // "base_tick": 0.00001, // "min_notional": 1, // "price_range": 0.02, // "price_scope": 0.4, // "std_liquidation_fee": 0.03, // "liquidator_fee": 0.015, // "claim_insurance_fund_discount": 0.0075, // "funding_period": 8, // "cap_funding": 0.000375, // "floor_funding": -0.000375, // "interest_rate": 0.0001, // "created_time": 1684140107326, // "updated_time": 1685345968053, // "base_mmr": 0.05, // "base_imr": 0.1, // "imr_factor": 0.0002512, // "liquidation_tier": "1" // } // const marketId = this.safeString(market, 'symbol', ''); const parts = marketId.split('_'); const marketType = 'swap'; const baseId = this.safeString(parts, 1); const quoteId = this.safeString(parts, 2); const base = this.safeCurrencyCode(baseId); const quote = this.safeCurrencyCode(quoteId); const settleId = this.safeString(parts, 2); const settle = this.safeCurrencyCode(settleId); const symbol = base + '/' + quote + ':' + settle; return this.safeMarketStructure({ 'id': marketId, 'symbol': symbol, 'base': base, 'quote': quote, 'settle': settle, 'baseId': baseId, 'quoteId': quoteId, 'settleId': settleId, 'type': marketType, 'spot': false, 'margin': false, 'swap': true, 'future': false, 'option': false, 'active': undefined, 'contract': true, 'linear': true, 'inverse': false, 'contractSize': this.parseNumber('1'), 'expiry': undefined, 'expiryDatetime': undefined, 'strike': undefined, 'optionType': undefined, 'precision': { 'amount': this.safeNumber(market, 'base_tick'), 'price': this.safeNumber(market, 'quote_tick'), }, 'limits': { 'leverage': { 'min': undefined, 'max': undefined, }, 'amount': { 'min': this.safeNumber(market, 'base_min'), 'max': this.safeNumber(market, 'base_max'), }, 'price': { 'min': this.safeNumber(market, 'quote_min'), 'max': this.safeNumber(market, 'quote_max'), }, 'cost': { 'min': this.safeNumber(market, 'min_notional'), 'max': undefined, }, }, 'created': this.safeInteger(market, 'created_time'), 'info': market, }); } /** * @method * @name modetrade#fetchMarkets * @description retrieves data on all markets for modetrade * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-available-symbols * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of objects representing market data */ async fetchMarkets(params = {}) { const response = await this.v1PublicGetPublicInfo(params); // // { // "success": true, // "timestamp": 1702989203989, // "data": { // "rows": [ // { // "symbol": "PERP_BTC_USDC", // "quote_min": 123, // "quote_max": 100000, // "quote_tick": 0.1, // "base_min": 0.00001, // "base_max": 20, // "base_tick": 0.00001, // "min_notional": 1, // "price_range": 0.02, // "price_scope": 0.4, // "std_liquidation_fee": 0.03, // "liquidator_fee": 0.015, // "claim_insurance_fund_discount": 0.0075, // "funding_period": 8, // "cap_funding": 0.000375, // "floor_funding": -0.000375, // "interest_rate": 0.0001, // "created_time": 1684140107326, // "updated_time": 1685345968053, // "base_mmr": 0.05, // "base_imr": 0.1, // "imr_factor": 0.0002512, // "liquidation_tier": "1" // } // ] // } // } // const data = this.safeDict(response, 'data', {}); const rows = this.safeList(data, 'rows', []); return this.parseMarkets(rows); } /** * @method * @name modetrade#fetchCurrencies * @description fetches all available currencies on an exchange * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-token-info * @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.v1PublicGetPublicToken(params); // // { // "success": true, // "timestamp": 1702989203989, // "data": { // "rows": [{ // "token": "USDC", // "decimals": 6, // "minimum_withdraw_amount": 0.000001, // "token_hash": "0xd6aca1be9729c13d677335161321649cccae6a591554772516700f986f942eaa", // "chain_details": [{ // "chain_id": 43113, // "contract_address": "0x5d64c9cfb0197775b4b3ad9be4d3c7976e0d8dc3", // "cross_chain_withdrawal_fee": 123, // "decimals": 6, // "withdraw_fee": 2 // }] // } // ] // } // } // const data = this.safeDict(response, 'data', {}); const tokenRows = this.safeList(data, 'rows', []); return this.parseCurrencies(tokenRows); } parseCurrency(rawCurrency) { const currencyId = this.safeString(rawCurrency, 'token'); const networks = this.safeList(rawCurrency, 'chain_details', []); const code = this.safeCurrencyCode(currencyId); let minPrecision = undefined; const resultingNetworks = {}; for (let j = 0; j < networks.length; j++) { const network = networks[j]; // TODO: transform chain id to human readable name const networkId = this.safeString(network, 'chain_id', ''); const precision = this.parsePrecision(this.safeString(network, 'decimals')); if (precision !== undefined) { minPrecision = (minPrecision === undefined) ? precision : Precise.stringMin(precision, minPrecision); } resultingNetworks[networkId] = { 'id': networkId, 'network': networkId, 'limits': { 'withdraw': { 'min': undefined, 'max': undefined, }, 'deposit': { 'min': undefined, 'max': undefined, }, }, 'active': undefined, 'deposit': undefined, 'withdraw': undefined, 'fee': this.safeNumber(network, 'withdrawal_fee'), 'precision': this.parseNumber(precision), 'info': network, }; } return this.safeCurrencyStructure({ 'id': currencyId, 'name': currencyId, 'code': code, 'precision': this.parseNumber(minPrecision), 'active': undefined, 'fee': undefined, 'networks': resultingNetworks, 'deposit': undefined, 'withdraw': undefined, 'limits': { 'deposit': { 'min': undefined, 'max': undefined, }, 'withdraw': { 'min': this.safeNumber(rawCurrency, 'minimum_withdraw_amount'), 'max': undefined, }, }, 'info': rawCurrency, }); } parseTokenAndFeeTemp(item, feeTokenKey, feeAmountKey) { const feeCost = this.safeString(item, feeAmountKey); let fee = undefined; if (feeCost !== undefined) { const feeCurrencyId = this.safeString(item, feeTokenKey); const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId); fee = { 'cost': feeCost, 'currency': feeCurrencyCode, }; } return fee; } parseTrade(trade, market = undefined) { // // public/market_trades // // { // "symbol": "PERP_ETH_USDC", // "side": "SELL", // "executed_price": 46222.35, // "executed_quantity": 0.0012, // "executed_timestamp": "1683878609166" // } // // fetchOrderTrades, fetchOrder // // { // "id": "99119876", // "symbol": "PERP_BTC_USDC", // "fee": "0.0024", // "side": "BUY", // "executed_timestamp": "1641481113084", // "order_id": "87001234", // "order_tag": "default", <-- this param only in "fetchOrderTrades" // "executed_price": "1", // "executed_quantity": "12", // "fee_asset": "BTC", // "is_maker": "1" // } // const isFromFetchOrder = ('id' in trade); const timestamp = this.safeInteger(trade, 'executed_timestamp'); const marketId = this.safeString(trade, 'symbol'); market = this.safeMarket(marketId, market); const symbol = market['symbol']; const price = this.safeString(trade, 'executed_price'); const amount = this.safeString(trade, 'executed_quantity'); const order_id = this.safeString(trade, 'order_id'); const fee = this.parseTokenAndFeeTemp(trade, 'fee_asset', 'fee'); const feeCost = this.safeString(fee, 'cost'); if ((feeCost !== undefined) && (fee !== undefined)) { fee['cost'] = feeCost; } const cost = Precise.stringMul(price, amount); const side = this.safeStringLower(trade, 'side'); const id = this.safeString(trade, 'id'); let takerOrMaker = undefined; if (isFromFetchOrder) { const isMaker = this.safeString(trade, 'is_maker') === '1'; takerOrMaker = isMaker ? 'maker' : 'taker'; } return this.safeTrade({ 'id': id, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'symbol': symbol, 'side': side, 'price': price, 'amount': amount, 'cost': cost, 'order': order_id, 'takerOrMaker': takerOrMaker, 'type': undefined, 'fee': fee, 'info': trade, }, market); } /** * @method * @name modetrade#fetchTrades * @description get the list of most recent trades for a particular symbol * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-market-trades * @param {string} symbol unified symbol of the market to fetch trades for * @param {int} [since] timestamp in ms of the earliest trade to fetch * @param {int} [limit] the maximum amount of trades to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades} */ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } const market = this.market(symbol); const request = { 'symbol': market['id'], }; if (limit !== undefined) { request['limit'] = limit; } const response = await this.v1PublicGetPublicMarketTrades(this.extend(request, params)); // // { // "success": true, // "timestamp": 1702989203989, // "data": { // "rows": [{ // "symbol": "PERP_ETH_USDC", // "side": "BUY", // "executed_price": 2050, // "executed_quantity": 1, // "executed_timestamp": 1683878609166 // }] // } // } // const data = this.safeDict(response, 'data', {}); const rows = this.safeList(data, 'rows', []); return this.parseTrades(rows, market, since, limit); } parseFundingRate(fundingRate, market = undefined) { // // { // "symbol":"PERP_AAVE_USDT", // "est_funding_rate":-0.00003447, // "est_funding_rate_timestamp":1653633959001, // "last_funding_rate":-0.00002094, // "last_funding_rate_timestamp":1653631200000, // "next_funding_time":1653634800000, // "sum_unitary_funding": 521.367 // } // const symbol = this.safeString(fundingRate, 'symbol'); market = (symbol === undefined) ? market : this.market(symbol); const nextFundingTimestamp = this.safeInteger(fundingRate, 'next_funding_time'); const estFundingRateTimestamp = this.safeInteger(fundingRate, 'est_funding_rate_timestamp'); const lastFundingRateTimestamp = this.safeInteger(fundingRate, 'last_funding_rate_timestamp'); const fundingTimeString = this.safeString(fundingRate, 'last_funding_rate_timestamp'); const nextFundingTimeString = this.safeString(fundingRate, 'next_funding_time'); const millisecondsInterval = Precise.stringSub(nextFundingTimeString, fundingTimeString); const fundingSymbol = (market !== undefined) ? market['symbol'] : undefined; return { 'info': fundingRate, 'symbol': fundingSymbol, 'markPrice': undefined, 'indexPrice': undefined, 'interestRate': this.parseNumber('0'), 'estimatedSettlePrice': undefined, 'timestamp': estFundingRateTimestamp, 'datetime': this.iso8601(estFundingRateTimestamp), 'fundingRate': this.safeNumber(fundingRate, 'est_funding_rate'), 'fundingTimestamp': nextFundingTimestamp, 'fundingDatetime': this.iso8601(nextFundingTimestamp), 'nextFundingRate': undefined, 'nextFundingTimestamp': undefined, 'nextFundingDatetime': undefined, 'previousFundingRate': this.safeNumber(fundingRate, 'last_funding_rate'), 'previousFundingTimestamp': lastFundingRateTimestamp, 'previousFundingDatetime': this.iso8601(lastFundingRateTimestamp), 'interval': this.parseFundingInterval(millisecondsInterval), }; } parseFundingInterval(interval) { const intervals = { '3600000': '1h', '14400000': '4h', '28800000': '8h', '57600000': '16h', '86400000': '24h', }; return this.safeString(intervals, interval, interval); } /** * @method * @name modetrade#fetchFundingInterval * @description fetch the current funding rate interval * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-predicted-funding-rate-for-one-market * @param {string} symbol unified market symbol * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/?id=funding-rate-structure} */ async fetchFundingInterval(symbol, params = {}) { return await this.fetchFundingRate(symbol, params); } /** * @method * @name modetrade#fetchFundingRate * @description fetch the current funding rate * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-predicted-funding-rate-for-one-market * @param {string} symbol unified market symbol * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/?id=funding-rate-structure} */ async fetchFundingRate(symbol, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } const market = this.market(symbol); const request = { 'symbol': market['id'], }; const response = await this.v1PublicGetPublicFundingRateSymbol(this.extend(request, params)); // // { // "success": true, // "timestamp": 1702989203989, // "data": { // "symbol": "PERP_ETH_USDC", // "est_funding_rate": 123, // "est_funding_rate_timestamp": 1683880020000, // "last_funding_rate": 0.0001, // "last_funding_rate_timestamp": 1683878400000, // "next_funding_time": 1683907200000, // "sum_unitary_funding": 521.367 // } // } // const data = this.safeDict(response, 'data', {}); return this.parseFundingRate(data, market); } /** * @method * @name modetrade#fetchFundingRates * @description fetch the current funding rate for multiple markets * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-predicted-funding-rates-for-all-markets * @param {string[]} symbols unified market symbols * @param {object} [params] extra parameters specific to the exchange API endpoint * @returns {object[]} an array of [funding rate structures]{@link https://docs.ccxt.com/?id=funding-rate-structure} */ async fetchFundingRates(symbols = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } symbols = this.marketSymbols(symbols); const response = await this.v1PublicGetPublicFundingRates(params); // // { // "success": true, // "timestamp": 1702989203989, // "data": { // "rows": [{ // "symbol": "PERP_ETH_USDC", // "est_funding_rate": 123, // "est_funding_rate_timestamp": 1683880020000, // "last_funding_rate": 0.0001, // "last_funding_rate_timestamp": 1683878400000, // "next_funding_time": 1683907200000, // "sum_unitary_funding": 521.367 // }] // } // } // const data = this.safeDict(response, 'data', {}); const rows = this.safeList(data, 'rows', []); return this.parseFundingRates(rows, symbols); } /** * @method * @name modetrade#fetchFundingRateHistory * @description fetches historical funding rate prices * @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/public/get-funding-rate-history-for-one-market * @param {string} symbol unified symbol of the market to fetch the funding rate history for * @param {int} [since] timestamp in ms of the earliest funding rate to fetch * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/?id=funding-rate-history-structure} to fetch * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {int} [params.until] timestamp in ms of the latest funding rate * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/?id=funding-rate-history-structure} */ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingRateHistory', 'paginate'); if (paginate) { return await this.fetchPaginatedCallIncremental('fetchFundingRateHistory', symbol, since, limit, params, 'page', 25); } let request = {}; if (symbol !== undefined) { const market = this.market(symbol); symbol = market['symbol']; request['symbol'] = market['id']; } if (since !== undefined) { request['start_t'] = since; } [request, params] = this.handleUntilOption('end_t', request, params, 0.001); const response = await this.v1PublicGetPublicFundingRateHistory(this.extend(request, params)); // // { // "success": true, // "timestamp": 1702989203989, // "data": { // "rows": [{ // "symbol": "PERP_ETH_USDC", // "funding_rate": 0.0001, // "funding_rate_timestamp": 1684224000000, // "next_funding_time": 1684252800000 // }], // "meta": { // "total": 9, // "records_per_page": 25, // "current_page": 1 // } // } // } // const data = this.safeDict(response, 'data', {}); const result = this.safeList(data, 'rows', []); const rates = []; for (let i = 0; i < result.length; i++) { const entry = result[i]; const marketId = this.safeString(entry, 'symbol'); const timestamp = this.safeInteger(entry, 'funding_rate_timestamp'); rates.push({ 'info': entry, 'symbol': this.safeSymbol(marketId), 'fundingRate': this.safeNumber(entry, 'funding_rate'), 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), }); } const sorted = this.sortBy(rates, 'timestamp'); return this.filterBySymbolSinceLimit(sorted, symbol, since, limit); } parseIncome(income, market = undefined) { // // { // "symbol": "PERP_ETH_USDC", // "funding_rate": 0.00046875, // "mark_price": 2100, // "funding_fee": 0.000016, // "payment_type": "Pay", // "status": "Accrued", // "created_time": 1682235722003, // "updated_time": 1682235722003 // } // const marketId = this.safeString(income, 'symbol'); const symbol = this.safeSymbol(marketId, market); let amount = this.safeString(income, 'funding_fee'); const code = this.safeCurrencyCode('USDC'); const timestamp = this.safeInteger(income, 'updated_time'); const rate = this.safeNumber(income, 'funding_rate'); const paymentType = this.safeString(income, 'payment_type'); amount = (paymentType === 'Pay') ? Precise.stringNeg(amount) : amount; return { 'info': income, 'symbol': symbol, 'code': code, 'timestamp': timestamp, 'datetime': this.iso8601(timestamp), 'id': undefined, 'amount': this.parseNumber(amount), 'rate': rate, }; } /** * @method * @name modetrade#fetchFundingHistory * @description fetch the history of funding payments paid and received on this account * @see https://orderly.network/docs/build-on-omnichain/evm-api/restful-api/private/get-funding-fee-history * @param {string} [symbol] unified market symbol * @param {int} [since] the earliest time in ms to fetch funding history for * @param {int} [limit] the maximum number of funding history structures to retrieve * @param {object} [params] extra parameters specific to the exchange API endpoint * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params) * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/?id=funding-history-structure} */ async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) { if (this.markets === undefined) { await this.loadMarkets(); } let paginate = false; [paginate, params] = this.handleOptionAndParams(params, 'fetchFundingHistory', 'paginate'); if (paginate) { return await this.fetchPaginatedCallIncremental('fetchFundingHistory', symbol, since, limit, params, 'page', 500); } const request = {}; let market = undefined; if (symbol !== undefined) { market = this.market(symbol); request['symbol'] = market['id']; } if (since !== undefined) { request['start_t'] = since; } const until = this.safeInteger(params, 'until'); // unified in milliseconds params = this.omit(params, ['until']); if (until !== undefined) { request['end_t'] = until; } if (limit !== undefined) { request['size'] = Math.min(limit, 500); } const response = await this.v1PrivateGetFundingFeeHistory(this.extend(request, params)); // // { // "success": true, // "timestamp": 1702989203989, // "data": { // "meta": { // "total": 9, // "records_per_page": 25, // "current_page": 1 // },