ccxt
Version:
1,122 lines (1,120 loc) • 137 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 { 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/woofipro.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 woofipro
* @augments Exchange
*/
export default class woofipro extends Exchange {
describe() {
return this.deepExtend(super.describe(), {
'id': 'woofipro',
'name': 'WOOFI PRO',
'countries': ['KY'], // Cayman Islands
'rateLimit': 100,
'version': 'v1',
'certified': true,
'pro': true,
'dex': true,
'has': {
'CORS': undefined,
'spot': false,
'margin': false,
'swap': true,
'future': false,
'option': false,
'addMargin': false,
'borrowCrossMargin': false,
'borrowIsolatedMargin': false,
'borrowMargin': false,
'cancelAllOrders': true,
'cancelOrder': true,
'cancelOrders': true,
'cancelWithdraw': false,
'closeAllPositions': false,
'closePosition': false,
'createConvertTrade': false,
'createDepositAddress': false,
'createMarketBuyOrderWithCost': false,
'createMarketOrder': false,
'createMarketOrderWithCost': false,
'createMarketSellOrderWithCost': false,
'createOrder': true,
'createOrderWithTakeProfitAndStopLoss': true,
'createReduceOnlyOrder': true,
'createStopLimitOrder': false,
'createStopLossOrder': true,
'createStopMarketOrder': false,
'createStopOrder': false,
'createTakeProfitOrder': true,
'createTrailingAmountOrder': false,
'createTrailingPercentOrder': false,
'createTriggerOrder': true,
'fetchAccounts': false,
'fetchAllGreeks': false,
'fetchBalance': true,
'fetchBorrowInterest': false,
'fetchBorrowRate': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchBorrowRates': false,
'fetchBorrowRatesPerSymbol': false,
'fetchCanceledOrders': false,
'fetchClosedOrder': false,
'fetchClosedOrders': true,
'fetchConvertCurrencies': false,
'fetchConvertQuote': false,
'fetchCrossBorrowRate': false,
'fetchCrossBorrowRates': false,
'fetchCurrencies': true,
'fetchDepositAddress': false,
'fetchDeposits': true,
'fetchDepositsWithdrawals': true,
'fetchFundingHistory': true,
'fetchFundingInterval': true,
'fetchFundingIntervals': false,
'fetchFundingRate': true,
'fetchFundingRateHistory': true,
'fetchFundingRates': true,
'fetchGreeks': false,
'fetchIndexOHLCV': false,
'fetchIsolatedBorrowRate': false,
'fetchIsolatedBorrowRates': false,
'fetchLedger': true,
'fetchLeverage': true,
'fetchMarginAdjustmentHistory': false,
'fetchMarginMode': false,
'fetchMarkets': true,
'fetchMarkOHLCV': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterestHistory': false,
'fetchOpenOrder': false,
'fetchOpenOrders': true,
'fetchOption': false,
'fetchOptionChain': false,
'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,
'fetchVolatilityHistory': false,
'fetchWithdrawals': true,
'reduceMargin': false,
'repayCrossMargin': false,
'repayIsolatedMargin': 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/9ba21b8a-a9c7-4770-b7f1-ce3bcbde68c1',
'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://dex.woo.org',
'doc': [
'https://orderly.network/docs/build-on-omnichain/building-on-evm',
],
'fees': [
'https://dex.woo.org/en/orderly',
],
'referral': {
'url': 'https://dex.woo.org/en/trade?ref=CCXT',
'discount': 0.05,
},
},
'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': 'CCXT',
'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 woofipro#fetchStatus
* @description the latest known information on the availability of the exchange API
* @see https://orderly.network/docs/build-on-omnichain/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 woofipro#fetchTime
* @description fetches the current integer timestamp in milliseconds from the exchange server
* @see https://orderly.network/docs/build-on-omnichain/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');
if (marketId === undefined) {
throw new ExchangeError(this.id + ' parseMarket() missing marketId');
}
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 woofipro#fetchMarkets
* @description retrieves data on all markets for woofipro
* @see https://orderly.network/docs/build-on-omnichain/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 woofipro#fetchCurrencies
* @description fetches all available currencies on an exchange
* @see https://orderly.network/docs/build-on-omnichain/evm-api/restful-api/public/get-supported-collateral-info#get-supported-collateral-info
* @see https://orderly.network/docs/build-on-omnichain/evm-api/restful-api/public/get-supported-chains-per-builder#get-supported-chains-per-builder
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an associative dictionary of currencies
*/
async fetchCurrencies(params = {}) {
const result = {};
const tokenPromise = 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 chainPromise = this.v1PublicGetPublicChainInfo(params);
const [tokenResponse, chainResponse] = await Promise.all([tokenPromise, chainPromise]);
const tokenData = this.safeDict(tokenResponse, 'data', {});
const tokenRows = this.safeList(tokenData, 'rows', []);
const chainData = this.safeDict(chainResponse, 'data', {});
const chainRows = this.safeList(chainData, 'rows', []);
const indexedChains = this.indexBy(chainRows, 'chain_id');
for (let i = 0; i < tokenRows.length; i++) {
const token = tokenRows[i];
const parsed = this.parseCurrency({ '_token': token, '_indexedChains': indexedChains });
if (parsed === undefined) {
throw new ExchangeError(this.id + ' fetchCurrencies() could not resolve parsed');
}
result[parsed['code']] = parsed;
}
return result;
}
parseCurrency(rawCurrency) {
const token = this.safeDict(rawCurrency, '_token', {});
const currencyId = this.safeString(token, 'token');
const networks = this.safeList(token, 'chain_details', []);
const code = this.safeCurrencyCode(currencyId);
const indexedChains = this.safeDict(rawCurrency, '_indexedChains', {});
const resultingNetworks = {};
for (let j = 0; j < networks.length; j++) {
const networkEntry = networks[j];
const networkId = this.safeString(networkEntry, 'chain_id');
const networkRow = this.safeDict(indexedChains, networkId);
const networkName = this.safeString(networkRow, 'name', networkId);
const networkCode = this.networkIdToCode(networkName, code);
if (networkCode !== undefined) {
resultingNetworks[networkCode] = {
'id': networkId,
'network': networkCode,
'limits': {
'withdraw': {
'min': undefined,
'max': undefined,
},
'deposit': {
'min': undefined,
'max': undefined,
},
},
'active': undefined,
'deposit': undefined,
'withdraw': undefined,
'fee': this.safeNumber(networkEntry, 'withdrawal_fee'),
'precision': this.parseNumber(this.parsePrecision(this.safeString(networkEntry, 'decimals'))),
'info': { 'network': networkEntry, 'networkRow': networkRow },
};
}
}
return this.safeCurrencyStructure({
'id': currencyId,
'name': undefined,
'code': code,
'precision': undefined,
'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,
});
}
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": "SPOT_BTC_USDT",
// "side": "SELL",
// "executed_price": 46222.35,
// "executed_quantity": 0.0012,
// "executed_timestamp": "1683878609166"
// }
//
// fetchOrderTrades, fetchOrder
//
// {
// "id": "99119876",
// "symbol": "SPOT_WOO_USDT",
// "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": "WOO",
// "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 ((fee !== undefined) && (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 woofipro#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://orderly.network/docs/build-on-omnichain/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 = 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 woofipro#fetchFundingInterval
* @description fetch the current funding rate interval
* @see https://orderly.network/docs/build-on-omnichain/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 woofipro#fetchFundingRate
* @description fetch the current funding rate
* @see https://orderly.network/docs/build-on-omnichain/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 woofipro#fetchFundingRates
* @description fetch the current funding rate for multiple markets
* @see https://orderly.network/docs/build-on-omnichain/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 woofipro#fetchFundingRateHistory
* @description fetches historical funding rate prices
* @see https://orderly.network/docs/build-on-omnichain/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 woofipro#fetch