ccxt
Version:
1,168 lines (1,165 loc) • 126 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/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';
import { ed25519 } from './static_dependencies/noble-curves/ed25519.js';
import { keccak_256 as keccak } from './static_dependencies/noble-hashes/sha3.js';
import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js';
// ---------------------------------------------------------------------------
/**
* @class modetrade
* @augments Exchange
*/
export default class modetrade extends Exchange {
describe() {
return this.deepExtend(super.describe(), {
'id': 'modetrade',
'name': 'Mode Trade',
'countries': ['KY'],
'rateLimit': 100,
'version': 'v1',
'certified': true,
'pro': true,
'dex': true,
'hostname': 'trade.mode.network',
'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/cec2b7f1-3b2b-4502-971b-447ee1937d6b',
'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,
'takeProfitPrice': false,
'attachedStopLossTakeProfit': undefined,
'timeInForce': {
'IOC': true,
'FOK': true,
'PO': true,
'GTD': false,
},
'hedged': false,
'trailing': true,
'leverage': true,
'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,
'-1001': AuthenticationError,
'-1002': AuthenticationError,
'-1003': RateLimitExceeded,
'-1004': BadRequest,
'-1005': BadRequest,
'-1006': InvalidOrder,
'-1007': BadRequest,
'-1008': InvalidOrder,
'-1009': InsufficientFunds,
'-1011': NetworkError,
'-1012': BadRequest,
'-1101': InsufficientFunds,
'-1102': InvalidOrder,
'-1103': InvalidOrder,
'-1104': InvalidOrder,
'-1105': InvalidOrder,
'-1201': BadRequest,
'-1202': BadRequest,
'29': BadRequest,
'9': AuthenticationError,
'3': AuthenticationError,
'2': BadRequest,
'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 {
'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 result = {};
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', []);
for (let i = 0; i < tokenRows.length; i++) {
const token = tokenRows[i];
const currencyId = this.safeString(token, 'token');
const networks = this.safeList(token, '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,
};
}
result[code] = 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(token, 'minimum_withdraw_amount'),
'max': undefined,
},
},
'info': token,
});
}
return result;
}
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['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 = {}) {
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 = 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);
return {
'info': fundingRate,
'symbol': market['symbol'],
'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 = {}) {
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 = {}) {
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 = {}) {
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);
}
/**
* @method
* @name modetrade#fetchTradingFees
* @description fetch the trading fees for multiple markets
* @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-account-information
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
*/
async fetchTradingFees(params = {}) {
await this.loadMarkets();
const response = await this.v1PrivateGetClientInfo(params);
//
// {
// "success": true,
// "timestamp": 1702989203989,
// "data": {
// "account_id": "<string>",
// "email": "test@test.com",
// "account_mode": "FUTURES",
// "max_leverage": 20,
// "taker_fee_rate": 123,
// "maker_fee_rate": 123,
// "futures_taker_fee_rate": 123,
// "futures_maker_fee_rate": 123,
// "maintenance_cancel_orders": true,
// "imr_factor": {
// "PERP_BTC_USDC": 123,
// "PERP_ETH_USDC": 123,
// "PERP_NEAR_USDC": 123
// },
// "max_notional": {
// "PERP_BTC_USDC": 123,
// "PERP_ETH_USDC": 123,
// "PERP_NEAR_USDC": 123
// }
// }
// }
//
const data = this.safeDict(response, 'data', {});
const maker = this.safeString(data, 'futures_maker_fee_rate');
const taker = this.safeString(data, 'futures_taker_fee_rate');
const result = {};
for (let i = 0; i < this.symbols.length; i++) {
const symbol = this.symbols[i];
result[symbol] = {
'info': response,
'symbol': symbol,
'maker': this.parseNumber(Precise.stringDiv(maker, '10000')),
'taker': this.parseNumber(Precise.stringDiv(taker, '10000')),
'percentage': true,
'tierBased': true,
};
}
return result;
}
/**
* @method
* @name modetrade#fetchOrderBook
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/orderbook-snapshot
* @param {string} symbol unified symbol of the market to fetch the order book for
* @param {int} [limit] the maximum amount of order book entries to return
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
*/
async fetchOrderBook(symbol, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
limit = Math.min(limit, 1000);
request['max_level'] = limit;
}
const response = await this.v1PrivateGetOrderbookSymbol(this.extend(request, params));
//
// {
// "success": true,
// "timestamp": 1702989203989,
// "data": {
// "asks": [{
// "price": 10669.4,
// "quantity": 1.56263218
// }],
// "bids": [{
// "price": 10669.4,
// "quantity": 1.56263218
// }],
// "timestamp": 123
// }
// }
//
const data = this.safeDict(response, 'data', {});
const timestamp = this.safeInteger(data, 'timestamp');
return this.parseOrderBook(data, symbol, timestamp, 'bids', 'asks', 'price', 'quantity');
}
parseOHLCV(ohlcv, market = undefined) {
return [
this.safeInteger(ohlcv, 'start_timestamp'),
this.safeNumber(ohlcv, 'open'),
this.safeNumber(ohlcv, 'high'),
this.safeNumber(ohlcv, 'low'),
this.safeNumber(ohlcv, 'close'),
this.safeNumber(ohlcv, 'volume'),
];
}
/**
* @method
* @name modetrade#fetchOHLCV
* @see https://orderly.network/docs/build-on-evm/evm-api/restful-api/private/get-kline
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @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] max=1000, max=100 when since is defined and is less than (now - (999 * (timeframe in ms)))
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {int[][]} 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 market = this.market(symbol);
const request = {
'symbol': market['id'],
'type': this.safeString(this.timeframes, timeframe, timeframe),
};
if (limit !== undefined) {
request['limit'] = Math.min(limit, 1000);
}
const response = await this.v1PrivateGetKline(this.extend(request, params));