astro-perp-ccxt-dev
Version:
5,184 lines • 229 kB
JavaScript
'use strict';
var xt$1 = require('./abstract/xt.js');
var Precise = require('./base/Precise.js');
var number = require('./base/functions/number.js');
var errors = require('./base/errors.js');
var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
// ----------------------------------------------------------------------------
// ---------------------------------------------------------------------------
/**
* @class xt
* @augments Exchange
*/
class xt extends xt$1 {
describe() {
return this.deepExtend(super.describe(), {
'id': 'xt',
'name': 'XT',
'countries': ['SC'],
// spot api ratelimits are undefined, 10/s/ip, 50/s/ip, 100/s/ip or 200/s/ip
// futures 3 requests per second => 1000ms / (100 * 3.33) = 3.003 (get assets -> fetchMarkets & fetchCurrencies)
// futures 10 requests per second => 1000ms / (100 * 1) = 10 (all other)
// futures 1000 times per minute for each single IP -> Otherwise account locked for 10min
'rateLimit': 100,
'version': 'v4',
'certified': false,
'pro': true,
'has': {
'CORS': false,
'spot': true,
'margin': true,
'swap': true,
'future': true,
'option': false,
'addMargin': true,
'borrowMargin': false,
'cancelAllOrders': true,
'cancelOrder': true,
'cancelOrders': true,
'createDepositAddress': false,
'createMarketBuyOrderWithCost': true,
'createMarketSellOrderWithCost': false,
'createOrder': true,
'createPostOnlyOrder': false,
'createReduceOnlyOrder': true,
'editOrder': true,
'fetchAccounts': false,
'fetchBalance': true,
'fetchBidsAsks': true,
'fetchBorrowInterest': false,
'fetchBorrowRate': false,
'fetchBorrowRateHistories': false,
'fetchBorrowRateHistory': false,
'fetchBorrowRatesPerSymbol': false,
'fetchCanceledOrders': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDeposit': false,
'fetchDepositAddress': true,
'fetchDepositAddresses': false,
'fetchDepositAddressesByNetwork': false,
'fetchDeposits': true,
'fetchDepositWithdrawals': false,
'fetchDepositWithdrawFee': false,
'fetchDepositWithdrawFees': false,
'fetchFundingHistory': true,
'fetchFundingInterval': true,
'fetchFundingIntervals': false,
'fetchFundingRate': true,
'fetchFundingRateHistory': true,
'fetchFundingRates': false,
'fetchIndexOHLCV': false,
'fetchL3OrderBook': false,
'fetchLedger': true,
'fetchLedgerEntry': false,
'fetchLeverage': false,
'fetchLeverageTiers': true,
'fetchMarketLeverageTiers': true,
'fetchMarkets': true,
'fetchMarkOHLCV': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenInterest': false,
'fetchOpenInterestHistory': false,
'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrderBook': true,
'fetchOrderBooks': false,
'fetchOrders': true,
'fetchOrdersByStatus': true,
'fetchOrderTrades': false,
'fetchPosition': true,
'fetchPositions': true,
'fetchPremiumIndexOHLCV': false,
'fetchSettlementHistory': false,
'fetchStatus': false,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
'fetchTrades': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
'fetchTradingLimits': false,
'fetchTransactionFee': false,
'fetchTransactionFees': false,
'fetchTransactions': false,
'fetchTransfer': false,
'fetchTransfers': false,
'fetchWithdrawal': false,
'fetchWithdrawals': true,
'fetchWithdrawalWhitelist': false,
'reduceMargin': true,
'repayMargin': false,
'setLeverage': true,
'setMargin': false,
'setMarginMode': true,
'setPositionMode': false,
'signIn': false,
'transfer': true,
'withdraw': true,
},
'precisionMode': number.TICK_SIZE,
'urls': {
'logo': 'https://user-images.githubusercontent.com/14319357/232636712-466df2fc-560a-4ca4-aab2-b1d954a58e24.jpg',
'api': {
'spot': 'https://sapi.xt.com',
'linear': 'https://fapi.xt.com',
'inverse': 'https://dapi.xt.com',
'user': 'https://api.xt.com',
},
'www': 'https://xt.com',
'referral': 'https://www.xt.com/en/accounts/register?ref=9PTM9VW',
'doc': [
'https://doc.xt.com/',
'https://github.com/xtpub/api-doc',
],
'fees': 'https://www.xt.com/en/rate',
},
'api': {
'public': {
'spot': {
'get': {
'currencies': 1,
'depth': 10,
'kline': 1,
'symbol': 1,
'ticker': 1,
'ticker/book': 1,
'ticker/price': 1,
'ticker/24h': 1,
'time': 1,
'trade/history': 1,
'trade/recent': 1,
'wallet/support/currency': 1,
},
},
'linear': {
'get': {
'future/market/v1/public/contract/risk-balance': 1,
'future/market/v1/public/contract/open-interest': 1,
'future/market/v1/public/leverage/bracket/detail': 1,
'future/market/v1/public/leverage/bracket/list': 1,
'future/market/v1/public/q/agg-ticker': 1,
'future/market/v1/public/q/agg-tickers': 1,
'future/market/v1/public/q/deal': 1,
'future/market/v1/public/q/depth': 1,
'future/market/v1/public/q/funding-rate': 1,
'future/market/v1/public/q/funding-rate-record': 1,
'future/market/v1/public/q/index-price': 1,
'future/market/v1/public/q/kline': 1,
'future/market/v1/public/q/mark-price': 1,
'future/market/v1/public/q/symbol-index-price': 1,
'future/market/v1/public/q/symbol-mark-price': 1,
'future/market/v1/public/q/ticker': 1,
'future/market/v1/public/q/tickers': 1,
'future/market/v1/public/symbol/coins': 3.33,
'future/market/v1/public/symbol/detail': 3.33,
'future/market/v1/public/symbol/list': 1,
},
},
'inverse': {
'get': {
'future/market/v1/public/contract/risk-balance': 1,
'future/market/v1/public/contract/open-interest': 1,
'future/market/v1/public/leverage/bracket/detail': 1,
'future/market/v1/public/leverage/bracket/list': 1,
'future/market/v1/public/q/agg-ticker': 1,
'future/market/v1/public/q/agg-tickers': 1,
'future/market/v1/public/q/deal': 1,
'future/market/v1/public/q/depth': 1,
'future/market/v1/public/q/funding-rate': 1,
'future/market/v1/public/q/funding-rate-record': 1,
'future/market/v1/public/q/index-price': 1,
'future/market/v1/public/q/kline': 1,
'future/market/v1/public/q/mark-price': 1,
'future/market/v1/public/q/symbol-index-price': 1,
'future/market/v1/public/q/symbol-mark-price': 1,
'future/market/v1/public/q/ticker': 1,
'future/market/v1/public/q/tickers': 1,
'future/market/v1/public/symbol/coins': 3.33,
'future/market/v1/public/symbol/detail': 3.33,
'future/market/v1/public/symbol/list': 1,
},
},
},
'private': {
'spot': {
'get': {
'balance': 1,
'balances': 1,
'batch-order': 1,
'deposit/address': 1,
'deposit/history': 1,
'history-order': 1,
'open-order': 1,
'order': 1,
'order/{orderId}': 1,
'trade': 1,
'withdraw/history': 1,
},
'post': {
'order': 0.2,
'withdraw': 10,
'balance/transfer': 1,
'balance/account/transfer': 1,
'ws-token': 1,
},
'delete': {
'batch-order': 1,
'open-order': 1,
'order/{orderId}': 1,
},
'put': {
'order/{orderId}': 1,
},
},
'linear': {
'get': {
'future/trade/v1/entrust/plan-detail': 1,
'future/trade/v1/entrust/plan-list': 1,
'future/trade/v1/entrust/plan-list-history': 1,
'future/trade/v1/entrust/profit-detail': 1,
'future/trade/v1/entrust/profit-list': 1,
'future/trade/v1/order/detail': 1,
'future/trade/v1/order/list': 1,
'future/trade/v1/order/list-history': 1,
'future/trade/v1/order/trade-list': 1,
'future/user/v1/account/info': 1,
'future/user/v1/balance/bills': 1,
'future/user/v1/balance/detail': 1,
'future/user/v1/balance/funding-rate-list': 1,
'future/user/v1/balance/list': 1,
'future/user/v1/position/adl': 1,
'future/user/v1/position/list': 1,
'future/user/v1/user/collection/list': 1,
'future/user/v1/user/listen-key': 1,
},
'post': {
'future/trade/v1/entrust/cancel-all-plan': 1,
'future/trade/v1/entrust/cancel-all-profit-stop': 1,
'future/trade/v1/entrust/cancel-plan': 1,
'future/trade/v1/entrust/cancel-profit-stop': 1,
'future/trade/v1/entrust/create-plan': 1,
'future/trade/v1/entrust/create-profit': 1,
'future/trade/v1/entrust/update-profit-stop': 1,
'future/trade/v1/order/cancel': 1,
'future/trade/v1/order/cancel-all': 1,
'future/trade/v1/order/create': 1,
'future/trade/v1/order/create-batch': 1,
'future/trade/v1/order/update': 1,
'future/user/v1/account/open': 1,
'future/user/v1/position/adjust-leverage': 1,
'future/user/v1/position/auto-margin': 1,
'future/user/v1/position/close-all': 1,
'future/user/v1/position/margin': 1,
'future/user/v1/user/collection/add': 1,
'future/user/v1/user/collection/cancel': 1,
'future/user/v1/position/change-type': 1,
},
},
'inverse': {
'get': {
'future/trade/v1/entrust/plan-detail': 1,
'future/trade/v1/entrust/plan-list': 1,
'future/trade/v1/entrust/plan-list-history': 1,
'future/trade/v1/entrust/profit-detail': 1,
'future/trade/v1/entrust/profit-list': 1,
'future/trade/v1/order/detail': 1,
'future/trade/v1/order/list': 1,
'future/trade/v1/order/list-history': 1,
'future/trade/v1/order/trade-list': 1,
'future/user/v1/account/info': 1,
'future/user/v1/balance/bills': 1,
'future/user/v1/balance/detail': 1,
'future/user/v1/balance/funding-rate-list': 1,
'future/user/v1/balance/list': 1,
'future/user/v1/position/adl': 1,
'future/user/v1/position/list': 1,
'future/user/v1/user/collection/list': 1,
'future/user/v1/user/listen-key': 1,
},
'post': {
'future/trade/v1/entrust/cancel-all-plan': 1,
'future/trade/v1/entrust/cancel-all-profit-stop': 1,
'future/trade/v1/entrust/cancel-plan': 1,
'future/trade/v1/entrust/cancel-profit-stop': 1,
'future/trade/v1/entrust/create-plan': 1,
'future/trade/v1/entrust/create-profit': 1,
'future/trade/v1/entrust/update-profit-stop': 1,
'future/trade/v1/order/cancel': 1,
'future/trade/v1/order/cancel-all': 1,
'future/trade/v1/order/create': 1,
'future/trade/v1/order/create-batch': 1,
'future/trade/v1/order/update': 1,
'future/user/v1/account/open': 1,
'future/user/v1/position/adjust-leverage': 1,
'future/user/v1/position/auto-margin': 1,
'future/user/v1/position/close-all': 1,
'future/user/v1/position/margin': 1,
'future/user/v1/user/collection/add': 1,
'future/user/v1/user/collection/cancel': 1,
},
},
'user': {
'get': {
'user/account': 1,
'user/account/api-key': 1,
},
'post': {
'user/account': 1,
'user/account/api-key': 1,
},
'put': {
'user/account/api-key': 1,
},
'delete': {
'user/account/{apikeyId}': 1,
},
},
},
},
'fees': {
'spot': {
'tierBased': true,
'percentage': true,
'maker': this.parseNumber('0.002'),
'taker': this.parseNumber('0.002'),
'tiers': {
'maker': [
[this.parseNumber('0'), this.parseNumber('0.002')],
[this.parseNumber('5000'), this.parseNumber('0.0018')],
[this.parseNumber('10000'), this.parseNumber('0.0016')],
[this.parseNumber('20000'), this.parseNumber('0.0014')],
[this.parseNumber('50000'), this.parseNumber('0.0012')],
[this.parseNumber('150000'), this.parseNumber('0.0010')],
[this.parseNumber('300000'), this.parseNumber('0.0008')],
[this.parseNumber('600000'), this.parseNumber('0.0007')],
[this.parseNumber('1200000'), this.parseNumber('0.0006')],
[this.parseNumber('2500000'), this.parseNumber('0.0005')],
[this.parseNumber('6000000'), this.parseNumber('0.0004')],
[this.parseNumber('15000000'), this.parseNumber('0.0003')],
[this.parseNumber('30000000'), this.parseNumber('0.0002')],
],
'taker': [
[this.parseNumber('0'), this.parseNumber('0.002')],
[this.parseNumber('5000'), this.parseNumber('0.0018')],
[this.parseNumber('10000'), this.parseNumber('0.0016')],
[this.parseNumber('20000'), this.parseNumber('0.0014')],
[this.parseNumber('50000'), this.parseNumber('0.0012')],
[this.parseNumber('150000'), this.parseNumber('0.0010')],
[this.parseNumber('300000'), this.parseNumber('0.0008')],
[this.parseNumber('600000'), this.parseNumber('0.0007')],
[this.parseNumber('1200000'), this.parseNumber('0.0006')],
[this.parseNumber('2500000'), this.parseNumber('0.0005')],
[this.parseNumber('6000000'), this.parseNumber('0.0004')],
[this.parseNumber('15000000'), this.parseNumber('0.0003')],
[this.parseNumber('30000000'), this.parseNumber('0.0002')],
],
},
},
'contract': {
'tierBased': true,
'percentage': true,
'maker': this.parseNumber('0.0004'),
'taker': this.parseNumber('0.0006'),
'tiers': {
'maker': [
[this.parseNumber('0'), this.parseNumber('0.0004')],
[this.parseNumber('200000'), this.parseNumber('0.00038')],
[this.parseNumber('1000000'), this.parseNumber('0.00036')],
[this.parseNumber('5000000'), this.parseNumber('0.00034')],
[this.parseNumber('10000000'), this.parseNumber('0.00032')],
[this.parseNumber('15000000'), this.parseNumber('0.00028')],
[this.parseNumber('30000000'), this.parseNumber('0.00024')],
[this.parseNumber('50000000'), this.parseNumber('0.0002')],
[this.parseNumber('100000000'), this.parseNumber('0.00016')],
[this.parseNumber('300000000'), this.parseNumber('0.00012')],
[this.parseNumber('500000000'), this.parseNumber('0.00008')],
],
'taker': [
[this.parseNumber('0'), this.parseNumber('0.0006')],
[this.parseNumber('200000'), this.parseNumber('0.000588')],
[this.parseNumber('1000000'), this.parseNumber('0.00057')],
[this.parseNumber('5000000'), this.parseNumber('0.00054')],
[this.parseNumber('10000000'), this.parseNumber('0.00051')],
[this.parseNumber('15000000'), this.parseNumber('0.00048')],
[this.parseNumber('30000000'), this.parseNumber('0.00045')],
[this.parseNumber('50000000'), this.parseNumber('0.00045')],
[this.parseNumber('100000000'), this.parseNumber('0.00036')],
[this.parseNumber('300000000'), this.parseNumber('0.00033')],
[this.parseNumber('500000000'), this.parseNumber('0.0003')],
],
},
},
},
'exceptions': {
'exact': {
'400': errors.NetworkError,
'404': errors.ExchangeError,
'429': errors.RateLimitExceeded,
'500': errors.ExchangeError,
'502': errors.ExchangeError,
'503': errors.OnMaintenance,
'AUTH_001': errors.AuthenticationError,
'AUTH_002': errors.AuthenticationError,
'AUTH_003': errors.AuthenticationError,
'AUTH_004': errors.AuthenticationError,
'AUTH_005': errors.AuthenticationError,
'AUTH_006': errors.AuthenticationError,
'AUTH_007': errors.AuthenticationError,
'AUTH_101': errors.AuthenticationError,
'AUTH_102': errors.AuthenticationError,
'AUTH_103': errors.AuthenticationError,
'AUTH_104': errors.AuthenticationError,
'AUTH_105': errors.AuthenticationError,
'AUTH_106': errors.PermissionDenied,
'SYMBOL_001': errors.BadSymbol,
'SYMBOL_002': errors.BadSymbol,
'SYMBOL_003': errors.BadSymbol,
'SYMBOL_004': errors.BadSymbol,
'SYMBOL_005': errors.BadSymbol,
'ORDER_001': errors.InvalidOrder,
'ORDER_002': errors.InsufficientFunds,
'ORDER_003': errors.InvalidOrder,
'ORDER_004': errors.InvalidOrder,
'ORDER_005': errors.InvalidOrder,
'ORDER_006': errors.InvalidOrder,
'ORDER_007': errors.PermissionDenied,
'ORDER_F0101': errors.InvalidOrder,
'ORDER_F0102': errors.InvalidOrder,
'ORDER_F0103': errors.InvalidOrder,
'ORDER_F0201': errors.InvalidOrder,
'ORDER_F0202': errors.InvalidOrder,
'ORDER_F0203': errors.InvalidOrder,
'ORDER_F0301': errors.InvalidOrder,
'ORDER_F0401': errors.InvalidOrder,
'ORDER_F0501': errors.InvalidOrder,
'ORDER_F0502': errors.InvalidOrder,
'ORDER_F0601': errors.InvalidOrder,
'COMMON_001': errors.ExchangeError,
'COMMON_002': errors.ExchangeError,
'COMMON_003': errors.BadRequest,
'CURRENCY_001': errors.BadRequest,
'DEPOSIT_001': errors.BadRequest,
'DEPOSIT_002': errors.PermissionDenied,
'DEPOSIT_003': errors.BadRequest,
'DEPOSIT_004': errors.BadRequest,
'DEPOSIT_005': errors.BadRequest,
'DEPOSIT_006': errors.BadRequest,
'DEPOSIT_007': errors.BadRequest,
'DEPOSIT_008': errors.BadRequest,
'WITHDRAW_001': errors.BadRequest,
'WITHDRAW_002': errors.BadRequest,
'WITHDRAW_003': errors.PermissionDenied,
'WITHDRAW_004': errors.BadRequest,
'WITHDRAW_005': errors.BadRequest,
'WITHDRAW_006': errors.BadRequest,
'WITHDRAW_008': errors.PermissionDenied,
'WITHDRAW_009': errors.PermissionDenied,
'WITHDRAW_010': errors.BadRequest,
'WITHDRAW_011': errors.InsufficientFunds,
'WITHDRAW_012': errors.PermissionDenied,
'WITHDRAW_013': errors.PermissionDenied,
'WITHDRAW_014': errors.BadRequest,
'WITHDRAW_015': errors.BadRequest,
'WITHDRAW_016': errors.BadRequest,
'WITHDRAW_017': errors.BadRequest,
'WITHDRAW_018': errors.BadRequest,
'WITHDRAW_019': errors.BadRequest,
'WITHDRAW_020': errors.PermissionDenied,
'WITHDRAW_021': errors.PermissionDenied,
'WITHDRAW_022': errors.BadRequest,
'WITHDRAW_023': errors.BadRequest,
'WITHDRAW_024': errors.BadRequest,
'WITHDRAW_025': errors.BadRequest,
'FUND_001': errors.BadRequest,
'FUND_002': errors.InsufficientFunds,
'FUND_003': errors.BadRequest,
'FUND_004': errors.ExchangeError,
'FUND_005': errors.PermissionDenied,
'FUND_014': errors.BadRequest,
'FUND_015': errors.BadRequest,
'FUND_016': errors.BadRequest,
'FUND_017': errors.BadRequest,
'FUND_018': errors.BadRequest,
'FUND_019': errors.BadRequest,
'FUND_020': errors.BadRequest,
'FUND_021': errors.BadRequest,
'FUND_022': errors.BadRequest,
'FUND_044': errors.BadRequest,
'TRANSFER_001': errors.BadRequest,
'TRANSFER_002': errors.InsufficientFunds,
'TRANSFER_003': errors.BadRequest,
'TRANSFER_004': errors.PermissionDenied,
'TRANSFER_005': errors.PermissionDenied,
'TRANSFER_006': errors.PermissionDenied,
'TRANSFER_007': errors.RequestTimeout,
'TRANSFER_008': errors.BadRequest,
'TRANSFER_009': errors.BadRequest,
'TRANSFER_010': errors.PermissionDenied,
'TRANSFER_011': errors.PermissionDenied,
'TRANSFER_012': errors.PermissionDenied,
'symbol_not_support_trading_via_api': errors.BadSymbol,
'open_order_min_nominal_value_limit': errors.InvalidOrder,
'insufficient_balance': errors.InsufficientFunds,
},
'broad': {
'The symbol does not support trading via API': errors.BadSymbol,
'Exceeds the minimum notional value of a single order': errors.InvalidOrder,
'insufficient balance': errors.InsufficientFunds,
},
},
'timeframes': {
'1m': '1m',
'5m': '5m',
'15m': '15m',
'30m': '30m',
'1h': '1h',
'2h': '2h',
'4h': '4h',
'6h': '6h',
'8h': '8h',
'1d': '1d',
'3d': '3d',
'1w': '1w',
'1M': '1M', // spot only
},
'commonCurrencies': {},
'options': {
'adjustForTimeDifference': false,
'timeDifference': 0,
'accountsById': {
'spot': 'SPOT',
'leverage': 'LEVER',
'finance': 'FINANCE',
'swap': 'FUTURES_U',
'future': 'FUTURES_U',
'linear': 'FUTURES_U',
'inverse': 'FUTURES_C',
},
'networks': {
'ERC20': 'Ethereum',
'TRC20': 'Tron',
'BEP20': 'BNB Smart Chain',
'BEP2': 'BNB-BEP2',
'ETH': 'Ethereum',
'TRON': 'Tron',
'BNB': 'BNB Smart Chain',
'AVAX': 'AVAX C-Chain',
'GAL': 'GAL(FT)',
'ALEO': 'ALEO(IOU)',
'BTC': 'Bitcoin',
'XT': 'XT Smart Chain',
'ETC': 'Ethereum Classic',
'MATIC': 'Polygon',
'LTC': 'Litecoin',
'BTS': 'BitShares',
'XRP': 'Ripple',
'XLM': 'Stellar Network',
'ADA': 'Cardano',
'XWC': 'XWC-XWC',
'DOGE': 'dogecoin',
'DCR': 'Decred',
'SC': 'Siacoin',
'XTZ': 'Tezos',
'ZEC': 'Zcash',
'XMR': 'Monero',
'LSK': 'Lisk',
'ATOM': 'Cosmos',
'ONT': 'Ontology',
'ALGO': 'Algorand',
'SOL': 'SOL-SOL',
'DOT': 'Polkadot',
'ZEN': 'Horizen',
'FIL': 'Filecoin',
'CHZ': 'chz',
'ICP': 'Internet Computer',
'KSM': 'Kusama',
'LUNA': 'Terra',
'THETA': 'Theta Token',
'FTM': 'Fantom',
'VET': 'VeChain',
'NEAR': 'NEAR Protocol',
'ONE': 'Harmony',
'KLAY': 'Klaytn',
'AR': 'Arweave',
'CELT': 'OKT',
'EGLD': 'Elrond eGold',
'CRO': 'CRO-CRONOS',
'BCH': 'Bitcoin Cash',
'GLMR': 'Moonbeam',
'LOOP': 'LOOP-LRC',
'REI': 'REI Network',
'ASTR': 'Astar Network',
'OP': 'OPT',
'MMT': 'MMT-MMT',
'TBC': 'TBC-TBC',
'OMAX': 'OMAX-OMAX CHAIN',
'GMMT': 'GMMT chain',
'ZIL': 'Zilliqa',
},
'networksById': {
'Ethereum': 'ERC20',
'Tron': 'TRC20',
'BNB Smart Chain': 'BEP20',
'BNB-BEP2': 'BEP2',
'Bitcoin': 'BTC',
'XT Smart Chain': 'XT',
'Ethereum Classic': 'ETC',
'Polygon': 'MATIC',
'Litecoin': 'LTC',
'BitShares': 'BTS',
'Ripple': 'XRP',
'Stellar Network': 'XLM',
'Cardano': 'ADA',
'XWC-XWC': 'XWC',
'dogecoin': 'DOGE',
'Decred': 'DCR',
'Siacoin': 'SC',
'Tezos': 'XTZ',
'Zcash': 'ZEC',
'Monero': 'XMR',
'Lisk': 'LSK',
'Cosmos': 'ATOM',
'Ontology': 'ONT',
'Algorand': 'ALGO',
'SOL-SOL': 'SOL',
'Polkadot': 'DOT',
'Horizen': 'ZEN',
'Filecoin': 'FIL',
'chz': 'CHZ',
'Internet Computer': 'ICP',
'Kusama': 'KSM',
'Terra': 'LUNA',
'Theta Token': 'THETA',
'Fantom': 'FTM',
'VeChain': 'VET',
'AVAX C-Chain': 'AVAX',
'NEAR Protocol': 'NEAR',
'Harmony': 'ONE',
'Klaytn': 'KLAY',
'Arweave': 'AR',
'OKT': 'CELT',
'Elrond eGold': 'EGLD',
'CRO-CRONOS': 'CRO',
'Bitcoin Cash': 'BCH',
'Moonbeam': 'GLMR',
'LOOP-LRC': 'LOOP',
'REI Network': 'REI',
'Astar Network': 'ASTR',
'GAL(FT)': 'GAL',
'ALEO(IOU)': 'ALEO',
'OPT': 'OP',
'MMT-MMT': 'MMT',
'TBC-TBC': 'TBC',
'OMAX-OMAX CHAIN': 'OMAX',
'GMMT chain': 'GMMT',
'Zilliqa': 'ZIL',
},
'createMarketBuyOrderRequiresPrice': true,
'recvWindow': '5000', // in milliseconds, spot only
},
'features': {
'default': {
'sandbox': false,
'createOrder': {
'marginMode': false,
'triggerPrice': false,
'triggerDirection': false,
'triggerPriceType': undefined,
'stopLossPrice': false,
'takeProfitPrice': false,
'attachedStopLossTakeProfit': undefined,
'timeInForce': {
'IOC': true,
'FOK': true,
'PO': true,
'GTD': false,
},
'hedged': false,
'trailing': false,
'leverage': false,
'marketBuyByCost': true,
'marketBuyRequiresPrice': false,
'selfTradePrevention': false,
'iceberg': false,
},
'createOrders': undefined,
'fetchMyTrades': {
'marginMode': true,
'limit': 100,
'daysBack': 100000,
'untilDays': 100000,
'marketType': true,
'subType': true,
'symbolRequired': false,
},
'fetchOrder': {
'marginMode': false,
'trigger': true,
'trailing': false,
'marketType': true,
'subType': true,
'symbolRequired': false,
},
'fetchOpenOrders': {
'marginMode': true,
'limit': 100,
'trigger': true,
'trailing': false,
'marketType': true,
'subType': true,
'symbolRequired': false,
},
'fetchOrders': {
'marginMode': true,
'limit': 100,
'daysBack': 100000,
'untilDays': 100000,
'trigger': true,
'trailing': false,
'marketType': true,
'subType': true,
'symbolRequired': false,
},
'fetchClosedOrders': {
'marginMode': true,
'limit': 100,
'daysBack': 100000,
'daysBackCanceled': 1,
'untilDays': 100000,
'trigger': true,
'trailing': false,
'marketType': true,
'subType': true,
'symbolRequired': false,
},
'fetchOHLCV': {
'limit': 1000, // todo for derivatives
},
},
'spot': {
'extends': 'default',
},
'forDerivatives': {
'extends': 'default',
'createOrder': {
'triggerPrice': true,
// todo
'triggerPriceType': {
'last': true,
'mark': true,
'index': true,
},
'stopLossPrice': true,
'takeProfitPrice': true,
},
'fetchMyTrades': {
'daysBack': undefined,
'untilDays': undefined,
},
},
'swap': {
'linear': {
'extends': 'forDerivatives',
},
'inverse': {
'extends': 'forDerivatives',
},
},
'future': {
'linear': {
'extends': 'forDerivatives',
},
'inverse': {
'extends': 'forDerivatives',
},
},
},
});
}
nonce() {
return this.milliseconds() - this.options['timeDifference'];
}
/**
* @method
* @name xt#fetchTime
* @description fetches the current integer timestamp in milliseconds from the xt server
* @see https://doc.xt.com/#market1serverInfo
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {int} the current integer timestamp in milliseconds from the xt server
*/
async fetchTime(params = {}) {
const response = await this.publicSpotGetTime(params);
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "serverTime": 1677823301643
// }
// }
//
const data = this.safeValue(response, 'result');
return this.safeInteger(data, 'serverTime');
}
/**
* @method
* @name xt#fetchCurrencies
* @description fetches all available currencies on an exchange
* @see https://doc.xt.com/#deposit_withdrawalsupportedCurrenciesGet
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} an associative dictionary of currencies
*/
async fetchCurrencies(params = {}) {
const promisesRaw = [this.publicSpotGetWalletSupportCurrency(params), this.publicSpotGetCurrencies(params)];
const [chainsResponse, currenciesResponse] = await Promise.all(promisesRaw);
//
// currencies
//
// {
// "time": "1686626116145",
// "version": "5dbbb2f2527c22b2b2e3b47187ef13d1",
// "currencies": [
// {
// "id": "2",
// "currency": "btc",
// "fullName": "Bitcoin",
// "logo": "https://a.static-global.com/1/currency/btc.png",
// "cmcLink": "https://coinmarketcap.com/currencies/bitcoin/",
// "weight": "99999",
// "maxPrecision": "10",
// "depositStatus": "1",
// "withdrawStatus": "1",
// "convertEnabled": "1",
// "transferEnabled": "1",
// "isChainExist": "1",
// "plates": [152]
// },
// ],
// }
//
//
// chains
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": [
// {
// "currency": "btc",
// "supportChains": [
// {
// "chain": "Bitcoin",
// "depositEnabled": true,
// "withdrawEnabled": true,
// "withdrawFeeAmount": 0.0009,
// "withdrawMinAmount": 0.0005,
// "depositFeeRate": 0
// },
// ]
// },
// ]
// }
//
// note: individual network's full data is available on per-currency endpoint: https://www.xt.com/sapi/v4/balance/public/currency/11
//
const chainsData = this.safeValue(chainsResponse, 'result', []);
const currenciesResult = this.safeValue(currenciesResponse, 'result', []);
const currenciesData = this.safeValue(currenciesResult, 'currencies', []);
const chainsDataIndexed = this.indexBy(chainsData, 'currency');
const result = {};
for (let i = 0; i < currenciesData.length; i++) {
const entry = currenciesData[i];
const currencyId = this.safeString(entry, 'currency');
const code = this.safeCurrencyCode(currencyId);
const networkEntry = this.safeValue(chainsDataIndexed, currencyId, {});
const rawNetworks = this.safeValue(networkEntry, 'supportChains', []);
const networks = {};
for (let j = 0; j < rawNetworks.length; j++) {
const rawNetwork = rawNetworks[j];
const networkId = this.safeString(rawNetwork, 'chain');
const networkCode = this.networkIdToCode(networkId, code);
networks[networkCode] = {
'info': rawNetwork,
'id': networkId,
'network': networkCode,
'name': undefined,
'active': undefined,
'fee': this.safeNumber(rawNetwork, 'withdrawFeeAmount'),
'precision': undefined,
'deposit': this.safeBool(rawNetwork, 'depositEnabled'),
'withdraw': this.safeBool(rawNetwork, 'withdrawEnabled'),
'limits': {
'amount': {
'min': undefined,
'max': undefined,
},
'withdraw': {
'min': this.safeNumber(rawNetwork, 'withdrawMinAmount'),
'max': undefined,
},
'deposit': {
'min': undefined,
'max': undefined,
},
},
};
}
const typeRaw = this.safeString(entry, 'type');
let type = undefined;
if (typeRaw === 'FT') {
type = 'crypto';
}
else {
type = 'other';
}
result[code] = this.safeCurrencyStructure({
'info': entry,
'id': currencyId,
'code': code,
'name': this.safeString(entry, 'fullName'),
'active': undefined,
'fee': undefined,
'precision': this.parseNumber(this.parsePrecision(this.safeString(entry, 'maxPrecision'))),
'deposit': this.safeString(entry, 'depositStatus') === '1',
'withdraw': this.safeString(entry, 'withdrawStatus') === '1',
'networks': networks,
'type': type,
'limits': {
'amount': {
'min': undefined,
'max': undefined,
},
'withdraw': {
'min': undefined,
'max': undefined,
},
'deposit': {
'min': undefined,
'max': undefined,
},
},
});
}
return result;
}
/**
* @method
* @name xt#fetchMarkets
* @description retrieves data on all markets for xt
* @see https://doc.xt.com/#market2symbol
* @see https://doc.xt.com/#futures_quotesgetSymbols
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object[]} an array of objects representing market data
*/
async fetchMarkets(params = {}) {
if (this.options['adjustForTimeDifference']) {
await this.loadTimeDifference();
}
const promisesUnresolved = [
this.fetchSpotMarkets(params),
this.fetchSwapAndFutureMarkets(params),
];
const promises = await Promise.all(promisesUnresolved);
const spotMarkets = promises[0];
const swapAndFutureMarkets = promises[1];
return this.arrayConcat(spotMarkets, swapAndFutureMarkets);
}
async fetchSpotMarkets(params = {}) {
const response = await this.publicSpotGetSymbol(params);
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "time": 1677881368812,
// "version": "abb101d1543e54bee40687b135411ba0",
// "symbols": [
// {
// "id": 640,
// "symbol": "xt_usdt",
// "state": "ONLINE",
// "stateTime": 1554048000000,
// "tradingEnabled": true,
// "openapiEnabled": true,
// "nextStateTime": null,
// "nextState": null,
// "depthMergePrecision": 5,
// "baseCurrency": "xt",
// "baseCurrencyPrecision": 8,
// "baseCurrencyId": 128,
// "quoteCurrency": "usdt",
// "quoteCurrencyPrecision": 8,
// "quoteCurrencyId": 11,
// "pricePrecision": 4,
// "quantityPrecision": 2,
// "orderTypes": ["LIMIT","MARKET"],
// "timeInForces": ["GTC","IOC"],
// "displayWeight": 10002,
// "displayLevel": "FULL",
// "plates": [],
// "filters":[
// {
// "filter": "QUOTE_QTY",
// "min": "1"
// },
// {
// "filter": "PROTECTION_LIMIT",
// "buyMaxDeviation": "0.8",
// "sellMaxDeviation": "4"
// },
// {
// "filter": "PROTECTION_MARKET",
// "maxDeviation": "0.02"
// }
// ]
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
const symbols = this.safeValue(data, 'symbols', []);
return this.parseMarkets(symbols);
}
async fetchSwapAndFutureMarkets(params = {}) {
const markets = await Promise.all([this.publicLinearGetFutureMarketV1PublicSymbolList(params), this.publicInverseGetFutureMarketV1PublicSymbolList(params)]);
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "id": 52,
// "symbolGroupId": 71,
// "symbol": "xt_usdt",
// "pair": "xt_usdt",
// "contractType": "PERPETUAL",
// "productType": "perpetual",
// "predictEventType": null,
// "underlyingType": "U_BASED",
// "contractSize": "1",
// "tradeSwitch": true,
// "isDisplay": true,
// "isOpenApi": false,
// "state": 0,
// "initLeverage": 20,
// "initPositionType": "CROSSED",
// "baseCoin": "xt",
// "quoteCoin": "usdt",
// "baseCoinPrecision": 8,
// "baseCoinDisplayPrecision": 4,
// "quoteCoinPrecision": 8,
// "quoteCoinDisplayPrecision": 4,
// "quantityPrecision": 0,
// "pricePrecision": 4,
// "supportOrderType": "LIMIT,MARKET",
// "supportTimeInForce": "GTC,FOK,IOC,GTX",
// "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
// "supportPositionType": "CROSSED,ISOLATED",
// "minQty": "1",
// "minNotional": "5",
// "maxNotional": "20000000",
// "multiplierDown": "0.1",
// "multiplierUp": "0.1",
// "maxOpenOrders": 200,
// "maxEntrusts": 200,
// "makerFee": "0.0004",
// "takerFee": "0.0006",
// "liquidationFee": "0.01",
// "marketTakeBound": "0.1",
// "depthPrecisionMerge": 5,
// "labels": ["HOT"],
// "onboardDate": 1657101601000,
// "enName": "XTUSDT ",
// "cnName": "XTUSDT",
// "minStepPrice": "0.0001",
// "minPrice": null,
// "maxPrice": null,
// "deliveryDate": 1669879634000,
// "deliveryPrice": null,
// "deliveryCompletion": false,
// "cnDesc": null,
// "enDesc": null
// },
// ]
// }
//
const swapAndFutureMarkets = this.arrayConcat(this.safeValue(markets[0], 'result', []), this.safeValue(markets[1], 'result', []));
return this.parseMarkets(swapAndFutureMarkets);
}
parseMarkets(markets) {
const result = [];
for (let i = 0; i < markets.length; i++) {
result.push(this.parseMarket(markets[i]));
}
return result;
}
parseMarket(market) {
//
// spot
//
// {
// "id": 640,
// "symbol": "xt_usdt",
// "state": "ONLINE",
// "stateTime": 1554048000000,
// "tradingEnabled": true,
// "openapiEnabled": true,
// "nextStateTime": null,
// "nextState": null,
// "depthMergePrecision": 5,
// "baseCurrency": "xt",
// "baseCurrencyPrecision": 8,
// "baseCurrencyId": 128,
// "quoteCurrency": "usdt",
// "quoteCurrencyPrecision": 8,
// "quoteCurrencyId": 11,
// "pricePrecision": 4,
// "quantityPrecision": 2,
// "orderTypes": ["LIMIT","MARKET"],
// "timeInForces": ["GTC","IOC"],
// "displayWeight": 10002,
// "displayLevel": "FULL",
// "plates": [],
// "filters":[
// {
// "filter": "QUOTE_QTY",
// "min": "1"
// },
// {
// "filter": "PRICE",
// "min": null,
// "max": null,
// "tickSize": null
// },
// {
// "filter": "QUANTITY",
// "min": null,
// "max": null,
// "tickSize": null
// },
// {
// "filter": "PROTECTION_LIMIT",
// "buyMaxDeviation": "0.8",
// "sellMaxDeviation": "4"
// },
// {
// "filter": "PROTECTION_MARKET",
// "maxDeviation": "0.02"
// },
// {
// "filter": "PROTECTION_ONLINE",
// "durationSeconds": "300",
// "maxPriceMultiple": "5"
// },
// ]
// }
//
// swap and future
//
// {
// "id": 52,
// "symbolGroupId": 71,
// "symbol": "xt_usdt",
// "pair": "xt_usdt",
// "contractType": "PERPETUAL",
// "productType": "perpetual",
// "predictEventType": null,
// "underlyingType": "U_BASED",
// "contractSize": "1",
// "tradeSwitch": true,
// "isDisplay": true,
// "isOpenApi": false,
// "state": 0,
// "initLeverage": 20,
// "initPositionType": "CROSSED",
// "baseCoin": "xt",
// "quoteCoin": "usdt",
// "baseCoinPrecision": 8,
// "baseCoinDisplayPrecision": 4,
// "quoteCoinPrecision": 8,
// "quoteCoinDisplayPrecision": 4,
// "quantityPrecision": 0,
// "pricePrecision": 4,
// "supportOrderType": "LIMIT,MARKET",
// "supportTimeInForce": "GTC,FOK,IOC,GTX",
// "supportEntrustType": "TAKE_PROFIT,STOP,TAKE_PROFIT_MARKET,STOP_MARKET,TRAILING_STOP_MARKET",
// "supportPositionType": "CROSSED,ISOLATED",
// "minQty": "1",
// "minNotional": "5",
// "maxNotional": "20000000",
// "multiplierDown": "0.1",
// "multiplierUp": "0.1",
// "maxOpenOrders": 200,
// "maxEntrusts": 200,
// "makerFee": "0.0004",
// "takerFee": "0.0006",
// "liquidationFee": "0.01",
// "marketTakeBound": "0.1",
// "depthPrecisionMerge": 5,
// "labels": ["HOT"],
// "onboardDate": 1657101601000,
// "enName": "XTUSDT ",
// "cnName": "XTUSDT",
// "minStepPrice": "0.0001",
// "minPrice": null,
// "maxPrice": null,
// "deliveryDate": 1669879634000,
// "deliveryPrice": null,
// "deliveryCompletion": false,
// "cnDesc": null,
// "enDesc": null
// }
//
const id = this.safeString(market, 'symbol');
const baseId = this.safeString2(market, 'baseCurrency', 'baseCoin');
const quoteId = this.safeString2(market, 'quoteCurrency', 'quoteCoin');
const base = this.safeCurrencyCode(baseId);
const quote = this.safeCurrencyCode(quoteId);
const state = this.safeString(market, 'state');
let symbol = base + '/' + quote;
const filters = this.safeValue(market, 'filters', []);
let minAmount = undefined;
let maxAmount = undefined;
let minCost = undefined;
let maxCost = undefined;
let minPrice = undefined;
let maxPrice = undefined;
let amountPrecision = undefined;
for (let i = 0; i < filters.length; i++) {
const entry = filters[i];
const filter = this.safeString(entry, 'filter');
if (filter === 'QUANTITY') {
minAmount = this.safeNumber(entry, 'min');
maxAmount = this.safeNumber(entry, 'max');
amountPrecision = this.safeNumber(entry, 'tickSize');
}
if (filter === 'QUOTE_QTY') {
minCost = this.safeNumber(entry, 'min');
}
if (filter === 'PRICE') {
minPrice = this.safeNumber(entry, 'min');
maxPrice = this.safeNumber(entry, 'max');
}
}
if (amountPrecision === undefined) {
amountPrecision = this.parseNumber(this.parsePrecision(this.safeString(market, 'quantityPrecision')));
}
const underlyingType = this.safeString(market, 'underlyingType');
let linear = undefined;
let inverse = undefined;
let settleId = undefined;
let settle = undefined;
let expiry = undefined;
let future = false;
let swap = false;
let contract = false;
let spot = true;
let type = 'spot';
if (underlyingType === 'U_BASED') {
symbol = symbol + ':' + quote;
settleId = baseId;
settle = quote;
linear = true;
inverse = false;
}
else if (underlyingType === 'COIN_BASED') {
symbol = symbol + ':' + base;
settleId = baseId;
settle = base;
linear = false;
inverse = true;
}
if (underlyingType !== undefined) {
expiry = this.safeInteger(market, 'deliveryDate');
const productType = this.safeString(market, 'productType');
if (productType !== 'perpetual') {
symbol = symbol + '-' + this.yymmdd(expiry);
type = 'future';
future = true;
}
else {
type = 'swap';
swap = true;
}
minAmount = this.safeNumber(market, 'minQty');
minCost = this.safeNumber(market, 'minNotional');
maxCost = this.safeNumber(market, 'maxNotional');
minPrice = this.safeNumber(market, 'minPrice');
maxPrice = this.safeNumber(market, 'maxPrice');
contract = true;
spot = false;
}
let isActive = false;
if (contract) {
isActive = this.safeValue(market, 'isOpenApi', false);
}
else {
if ((state === 'ONLINE') && (this.safeValue(market, 'tradingEnabled')) && (this.safeValue(market, 'openapiEnabled'))) {
isActive = true;
}
}
return this.safeMarketStructure({
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
'settle': settle,
'baseId': baseId,
'quoteId': quoteId,
'settleId': settleId,
'type': type,
'spot': spot,
'margin': undefined,
'swap': swap,
'future': future,
'option': false,
'active': isActive,
'contract': contract,
'linear': linear,
'inverse': inverse,
'taker': this.safeNumber(market, 'takerFee'),
'maker': this.safeNumber(market, 'makerFee'),
'contractSize': this.safeNumber(market, 'contractSize'),
'expiry': expiry,
'expiryDatetime': this.iso8601(expiry),
'strike': undefined,
'optionType': undefined,
'precision': {
'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))),
'amount': amountPrecision,
'base': this.parseNumber(this.parsePrecision(this.safeString(market, 'baseCoinPrecision'))),
'quote': this.parseNumber(this.parsePrecision(this.safeString(market, 'quoteCoinPrecision'))),
},
'limits': {
'leverage': {
'min': this.parseNumber('1'),
'max': undefined,
},
'amount': {
'min': minAmount,
'max': maxAmount,
},
'price': {
'min': minPrice,
'max': maxPrice,
},
'cost': {
'min': minCost,
'max': maxCost,
},
},
'info': market,
});
}
/**
* @method
* @name xt#fetchOHLCV
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
* @see https://doc.xt.com/#market4kline
* @see https://doc.xt.com/#futures_quotesgetKLine
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
* @param {string} timeframe the length of time each candle represents
* @param {int} [since] timestamp in ms of the earliest candle to fetch
* @param {int} [limit] the maximum amount of candles to fetch
* @param {object} params extra parameters specific to the xt api endpoint
* @param {int} [params.until] timestamp in ms of the latest candle to fetch
* @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
* @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();
let paginate = false;
[paginate, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'paginate', false);
if (paginate) {
return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000);
}
const market = this.market(symbol);
const request = {
'symbol': market['id'],
'interval': this.safeString(this.timeframes, timeframe, timeframe),
};
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
else {
request['limit'] = 1000;
}
const until = this.safeInteger(params, 'until');
params = this.omit(params, ['until']);
if (until !== undefined) {
request['endTime'] = until;
}
let response = undefined;
if (market['linear']) {
response = await this.publicLinearGetFutureMarketV1PublicQKline(this.extend(request, params));
}
else if (market['inverse']) {
response = await this.publicInverseGetFutureMarketV1PublicQKline(this.extend(request, params));
}
else {
response = await this.publicSpotGetKline(this.extend(request, params));
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": [
// {
// "t": 1678167720000,
// "o": "22467.85",
// "c": "22465.87",
// "h": "22468.86",
// "l": "22465.21",
// "q": "1.316656",
// "v": "29582.73018498"
// },
// ]
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "s": "btc_usdt",
// "p": "btc_usdt",
// "t": 1678168020000,
// "o": "22450.0",
// "c": "22441.5",
// "h": "22450.0",
// "l": "22441.5",
// "a": "312931",
// "v": "702461.58895"
// },
// ]
// }
//
const ohlcvs = this.safeValue(response, 'result', []);
return this.parseOHLCVs(ohlcvs, market, timeframe, since, limit);
}
parseOHLCV(ohlcv, market = undefined) {
//
// spot
//
// {
// "t": 1678167720000,
// "o": "22467.85",
// "c": "22465.87",
// "h": "22468.86",
// "l": "22465.21",
// "q": "1.316656",
// "v": "29582.73018498"
// }
//
// swap and future
//
// {
// "s": "btc_usdt",
// "p": "btc_usdt",
// "t": 1678168020000,
// "o": "22450.0",
// "c": "22441.5",
// "h": "22450.0",
// "l": "22441.5",
// "a": "312931",
// "v": "702461.58895"
// }
//
const volumeIndex = (market['inverse']) ? 'v' : 'a';
return [
this.safeInteger(ohlcv, 't'),
this.safeNumber(ohlcv, 'o'),
this.safeNumber(ohlcv, 'h'),
this.safeNumber(ohlcv, 'l'),
this.safeNumber(ohlcv, 'c'),
this.safeNumber2(ohlcv, 'q', volumeIndex),
];
}
/**
* @method
* @name xt#fetchOrderBook
* @see https://doc.xt.com/#market3depth
* @see https://doc.xt.com/#futures_quotesgetDepth
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
* @param {string} symbol unified market symbol 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 xt api endpoint
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/en/latest/manual.html#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'],
};
let response = undefined;
if (market['spot']) {
if (limit !== undefined) {
request['limit'] = Math.min(limit, 500);
}
response = await this.publicSpotGetDepth(this.extend(request, params));
}
else {
if (limit !== undefined) {
request['level'] = Math.min(limit, 50);
}
else {
request['level'] = 50;
}
if (market['linear']) {
response = await this.publicLinearGetFutureMarketV1PublicQDepth(this.extend(request, params));
}
else if (market['inverse']) {
response = await this.publicInverseGetFutureMarketV1PublicQDepth(this.extend(request, params));
}
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "timestamp": 1678169975184,
// "lastUpdateId": 1675333221812,
// "bids": [
// ["22444.51", "0.129887"],
// ["22444.49", "0.114245"],
// ["22444.30", "0.225956"]
// ],
// "asks": [
// ["22446.19", "0.095330"],
// ["22446.24", "0.224413"],
// ["22446.28", "0.329095"]
// ]
// }
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "t": 1678170311005,
// "s": "btc_usdt",
// "u": 471694545627,
// "b": [
// ["22426", "198623"],
// ["22423.5", "80295"],
// ["22423", "163580"]
// ],
// "a": [
// ["22427", "3417"],
// ["22428.5", "43532"],
// ["22429", "119"]
// ]
// }
// }
//
const orderBook = this.safeValue(response, 'result', {});
const timestamp = this.safeInteger2(orderBook, 'timestamp', 't');
if (market['spot']) {
const ob = this.parseOrderBook(orderBook, symbol, timestamp);
ob['nonce'] = this.safeInteger(orderBook, 'lastUpdateId');
return ob;
}
const swapOb = this.parseOrderBook(orderBook, symbol, timestamp, 'b', 'a');
swapOb['nonce'] = this.safeInteger2(orderBook, 'u', 'lastUpdateId');
return swapOb;
}
/**
* @method
* @name xt#fetchTicker
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
* @see https://doc.xt.com/#market10ticker24h
* @see https://doc.xt.com/#futures_quotesgetAggTicker
* @param {string} symbol unified market symbol to fetch the ticker for
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
async fetchTicker(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
let response = undefined;
if (market['linear']) {
response = await this.publicLinearGetFutureMarketV1PublicQAggTicker(this.extend(request, params));
}
else if (market['inverse']) {
response = await this.publicInverseGetFutureMarketV1PublicQAggTicker(this.extend(request, params));
}
else {
response = await this.publicSpotGetTicker24h(this.extend(request, params));
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": [
// {
// "s": "btc_usdt",
// "t": 1678172693931,
// "cv": "34.00",
// "cr": "0.0015",
// "o": "22398.05",
// "l": "22323.72",
// "h": "22600.50",
// "c": "22432.05",
// "q": "7962.256931",
// "v": "178675209.47416856"
// }
// ]
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "t": 1678172848572,
// "s": "btc_usdt",
// "c": "22415.5",
// "h": "22590.0",
// "l": "22310.0",
// "a": "623654031",
// "v": "1399166074.31675",
// "o": "22381.5",
// "r": "0.0015",
// "i": "22424.5",
// "m": "22416.5",
// "bp": "22415",
// "ap": "22415.5"
// }
// }
//
const ticker = this.safeValue(response, 'result');
if (market['spot']) {
return this.parseTicker(ticker[0], market);
}
return this.parseTicker(ticker, market);
}
/**
* @method
* @name xt#fetchTickers
* @description fetches price tickers for multiple markets, statistical calculations with the information calculated over the past 24 hours each market
* @see https://doc.xt.com/#market10ticker24h
* @see https://doc.xt.com/#futures_quotesgetAggTickers
* @param {string} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
async fetchTickers(symbols = undefined, params = {}) {
await this.loadMarkets();
let market = undefined;
if (symbols !== undefined) {
symbols = this.marketSymbols(symbols);
market = this.market(symbols[0]);
}
const request = {};
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
[subType, params] = this.handleSubTypeAndParams('fetchTickers', market, params);
if (subType === 'inverse') {
response = await this.publicInverseGetFutureMarketV1PublicQAggTickers(this.extend(request, params));
}
else if ((subType === 'linear') || (type === 'swap') || (type === 'future')) {
response = await this.publicLinearGetFutureMarketV1PublicQAggTickers(this.extend(request, params));
}
else {
response = await this.publicSpotGetTicker24h(this.extend(request, params));
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": [
// {
// "s": "btc_usdt",
// "t": 1678172693931,
// "cv": "34.00",
// "cr": "0.0015",
// "o": "22398.05",
// "l": "22323.72",
// "h": "22600.50",
// "c": "22432.05",
// "q": "7962.256931",
// "v": "178675209.47416856"
// }
// ]
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "t": 1680738775108,
// "s": "badger_usdt",
// "c": "2.7176",
// "h": "2.7917",
// "l": "2.6818",
// "a": "88332",
// "v": "242286.3520",
// "o": "2.7422",
// "r": "-0.0089",
// "i": "2.7155",
// "m": "2.7161",
// "bp": "2.7152",
// "ap": "2.7176"
// },
// ]
// }
//
const tickers = this.safeValue(response, 'result', []);
const result = {};
for (let i = 0; i < tickers.length; i++) {
const ticker = this.parseTicker(tickers[i], market);
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
return this.filterByArray(result, 'symbol', symbols);
}
/**
* @method
* @name xt#fetchBidsAsks
* @description fetches the bid and ask price and volume for multiple markets
* @see https://doc.xt.com/#market9tickerBook
* @param {string} [symbols] unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/en/latest/manual.html#ticker-structure}
*/
async fetchBidsAsks(symbols = undefined, params = {}) {
await this.loadMarkets();
symbols = this.marketSymbols(symbols);
const request = {};
let market = undefined;
if (symbols !== undefined) {
market = this.market(symbols[0]);
}
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchBidsAsks', market, params);
if (subType !== undefined) {
throw new errors.NotSupported(this.id + ' fetchBidsAsks() is not available for swap and future markets, only spot markets are supported');
}
const response = await this.publicSpotGetTickerBook(this.extend(request, params));
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": [
// {
// "s": "kas_usdt",
// "t": 1679539891853,
// "ap": "0.016298",
// "aq": "5119.09",
// "bp": "0.016290",
// "bq": "135.37"
// },
// ]
// }
//
const tickers = this.safeValue(response, 'result', []);
return this.parseTickers(tickers, symbols);
}
parseTicker(ticker, market = undefined) {
//
// spot: fetchTicker, fetchTickers
//
// {
// "s": "btc_usdt",
// "t": 1678172693931,
// "cv": "34.00",
// "cr": "0.0015",
// "o": "22398.05",
// "l": "22323.72",
// "h": "22600.50",
// "c": "22432.05",
// "q": "7962.256931",
// "v": "178675209.47416856"
// }
//
// swap and future: fetchTicker, fetchTickers
//
// {
// "t": 1678172848572,
// "s": "btc_usdt",
// "c": "22415.5",
// "h": "22590.0",
// "l": "22310.0",
// "a": "623654031",
// "v": "1399166074.31675",
// "o": "22381.5",
// "r": "0.0015",
// "i": "22424.5",
// "m": "22416.5",
// "bp": "22415",
// "ap": "22415.5"
// }
//
// fetchBidsAsks
//
// {
// "s": "kas_usdt",
// "t": 1679539891853,
// "ap": "0.016298",
// "aq": "5119.09",
// "bp": "0.016290",
// "bq": "135.37"
// }
//
const marketId = this.safeString(ticker, 's');
let marketType = (market !== undefined) ? market['type'] : undefined;
const hasSpotKeys = ('cv' in ticker) || ('aq' in ticker);
if (marketType === undefined) {
marketType = hasSpotKeys ? 'spot' : 'contract';
}
market = this.safeMarket(marketId, market, '_', marketType);
const symbol = market['symbol'];
const timestamp = this.safeInteger(ticker, 't');
let percentage = this.safeString2(ticker, 'cr', 'r');
if (percentage !== undefined) {
percentage = Precise["default"].stringMul(percentage, '100');
}
return this.safeTicker({
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'high': this.safeNumber(ticker, 'h'),
'low': this.safeNumber(ticker, 'l'),
'bid': this.safeNumber(ticker, 'bp'),
'bidVolume': this.safeNumber(ticker, 'bq'),
'ask': this.safeNumber(ticker, 'ap'),
'askVolume': this.safeNumber(ticker, 'aq'),
'vwap': undefined,
'open': this.safeString(ticker, 'o'),
'close': this.safeString(ticker, 'c'),
'last': this.safeString(ticker, 'c'),
'previousClose': undefined,
'change': this.safeNumber(ticker, 'cv'),
'percentage': this.parseNumber(percentage),
'average': undefined,
'baseVolume': undefined,
'quoteVolume': this.safeNumber2(ticker, 'a', 'v'),
'info': ticker,
}, market);
}
/**
* @method
* @name xt#fetchTrades
* @description get the list of most recent trades for a particular symbol
* @see https://doc.xt.com/#market5tradeRecent
* @see https://doc.xt.com/#futures_quotesgetDeal
* @param {string} symbol unified market symbol 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 xt api endpoint
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
let response = undefined;
if (market['spot']) {
if (limit !== undefined) {
request['limit'] = limit;
}
response = await this.publicSpotGetTradeRecent(this.extend(request, params));
}
else {
if (limit !== undefined) {
request['num'] = limit;
}
if (market['linear']) {
response = await this.publicLinearGetFutureMarketV1PublicQDeal(this.extend(request, params));
}
else if (market['inverse']) {
response = await this.publicInverseGetFutureMarketV1PublicQDeal(this.extend(request, params));
}
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": [
// {
// "i": 203530723141917063,
// "t": 1678227505815,
// "p": "22038.81",
// "q": "0.000978",
// "v": "21.55395618",
// "b": true
// },
// ]
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "t": 1678227683897,
// "s": "btc_usdt",
// "p": "22031",
// "a": "1067",
// "m": "BID"
// },
// ]
// }
//
const trades = this.safeValue(response, 'result', []);
return this.parseTrades(trades, market);
}
/**
* @method
* @name xt#fetchMyTrades
* @description fetch all trades made by the user
* @see https://doc.xt.com/#tradetradeGet
* @see https://doc.xt.com/#futures_ordergetTrades
* @param {string} [symbol] unified market symbol 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 xt api endpoint
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/en/latest/manual.html?#public-trades}
*/
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const request = {};
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
request['symbol'] = market['id'];
}
if (since !== undefined) {
request['startTime'] = since;
}
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('fetchMyTrades', market, params);
[subType, params] = this.handleSubTypeAndParams('fetchMyTrades', market, params);
if ((subType !== undefined) || (type === 'swap') || (type === 'future')) {
if (limit !== undefined) {
request['size'] = limit;
}
if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1OrderTradeList(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureTradeV1OrderTradeList(this.extend(request, params));
}
}
else {
let marginMode = undefined;
[marginMode, params] = this.handleMarginModeAndParams('fetchMyTrades', params);
const marginOrSpotRequest = (marginMode !== undefined) ? 'LEVER' : 'SPOT';
request['bizType'] = marginOrSpotRequest;
if (limit !== undefined) {
request['limit'] = limit;
}
response = await this.privateSpotGetTrade(this.extend(request, params));
}
//
// spot and margin
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "hasPrev": false,
// "hasNext": false,
// "items": [
// {
// "symbol": "btc_usdt",
// "tradeId": "206906233569974658",
// "orderId": "206906233178463488",
// "orderSide": "SELL",
// "orderType": "MARKET",
// "bizType": "SPOT",
// "time": 1679032290215,
// "price": "25703.46",
// "quantity": "0.000099",
// "quoteQty": "2.54464254",
// "baseCurrency": "btc",
// "quoteCurrency": "usdt",
// "fee": "0.00508929",
// "feeCurrency": "usdt",
// "takerMaker": "TAKER"
// },
// ]
// }
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "page": 1,
// "ps": 10,
// "total": 2,
// "items": [
// {
// "orderId": "207260566170987200",
// "execId": "207260566790603265",
// "symbol": "btc_usdt",
// "quantity": "13",
// "price": "27368",
// "fee": "0.02134704",
// "feeCoin": "usdt",
// "timestamp": 1679116769838,
// "takerMaker": "TAKER"
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
const trades = this.safeValue(data, 'items', []);
return this.parseTrades(trades, market, since, limit);
}
parseTrade(trade, market = undefined) {
//
// spot: fetchTrades
//
// {
// "i": 203530723141917063,
// "t": 1678227505815,
// "p": "22038.81",
// "q": "0.000978",
// "v": "21.55395618",
// "b": true
// }
//
// spot: watchTrades
//
// {
// s: 'btc_usdt',
// i: '228825383103928709',
// t: 1684258222702,
// p: '27003.65',
// q: '0.000796',
// b: true
// }
//
// spot: watchMyTrades
//
// {
// "s": "btc_usdt", // symbol
// "t": 1656043204763, // time
// "i": "6316559590087251233", // tradeId
// "oi": "6216559590087220004", // orderId
// "p": "30000", // trade price
// "q": "3", // qty quantity
// "v": "90000" // volume trade amount
// }
//
// swap and future: fetchTrades
//
// {
// "t": 1678227683897,
// "s": "btc_usdt",
// "p": "22031",
// "a": "1067",
// "m": "BID"
// }
//
// spot: fetchMyTrades
//
// {
// "symbol": "btc_usdt",
// "tradeId": "206906233569974658",
// "orderId": "206906233178463488",
// "orderSide": "SELL",
// "orderType": "MARKET",
// "bizType": "SPOT",
// "time": 1679032290215,
// "price": "25703.46",
// "quantity": "0.000099",
// "quoteQty": "2.54464254",
// "baseCurrency": "btc",
// "quoteCurrency": "usdt",
// "fee": "0.00508929",
// "feeCurrency": "usdt",
// "takerMaker": "TAKER"
// }
//
// swap and future: fetchMyTrades
//
// {
// "orderId": "207260566170987200",
// "execId": "207260566790603265",
// "symbol": "btc_usdt",
// "quantity": "13",
// "price": "27368",
// "fee": "0.02134704",
// "feeCoin": "usdt",
// "timestamp": 1679116769838,
// "takerMaker": "TAKER"
// }
//
// contract watchMyTrades
//
// {
// "symbol": 'btc_usdt',
// "orderSide": 'SELL',
// "positionSide": 'LONG',
// "orderId": '231485367663419328',
// "price": '27152.7',
// "quantity": '33',
// "marginUnfrozen": '2.85318000',
// "timestamp": 1684892412565
// }
//
// watchMyTrades (ws, swap)
//
// {
// 'fee': '0.04080840',
// 'isMaker': False,
// 'marginUnfrozen': '0.75711984',
// 'orderId': '376172779053188416',
// 'orderSide': 'BUY',
// 'positionSide': 'LONG',
// 'price': '3400.70',
// 'quantity': '2',
// 'symbol': 'eth_usdt',
// 'timestamp': 1719388579622
// }
//
const marketId = this.safeString2(trade, 's', 'symbol');
let marketType = (market !== undefined) ? market['type'] : undefined;
const hasSpotKeys = ('b' in trade) || ('bizType' in trade) || ('oi' in trade);
if (marketType === undefined) {
marketType = hasSpotKeys ? 'spot' : 'contract';
}
market = this.safeMarket(marketId, market, '_', marketType);
let side = undefined;
let takerOrMaker = undefined;
const isBuyerMaker = this.safeBool(trade, 'b');
if (isBuyerMaker !== undefined) {
side = isBuyerMaker ? 'sell' : 'buy';
takerOrMaker = 'taker'; // public trades always taker
}
else {
const takerMaker = this.safeStringLower(trade, 'takerMaker');
if (takerMaker !== undefined) {
takerOrMaker = takerMaker;
}
else {
const isMaker = this.safeBool(trade, 'isMaker');
if (isMaker !== undefined) {
takerOrMaker = isMaker ? 'maker' : 'taker';
}
}
const orderSide = this.safeStringLower(trade, 'orderSide');
if (orderSide !== undefined) {
side = orderSide;
}
else {
const bidOrAsk = this.safeString(trade, 'm');
if (bidOrAsk !== undefined) {
side = (bidOrAsk === 'BID') ? 'buy' : 'sell';
}
}
}
const timestamp = this.safeIntegerN(trade, ['t', 'time', 'timestamp']);
const quantity = this.safeString2(trade, 'q', 'quantity');
let amount = undefined;
if (marketType === 'spot') {
amount = quantity;
}
else {
if (quantity === undefined) {
amount = Precise["default"].stringMul(this.safeString(trade, 'a'), this.numberToString(market['contractSize']));
}
else {
amount = Precise["default"].stringMul(quantity, this.numberToString(market['contractSize']));
}
}
return this.safeTrade({
'info': trade,
'id': this.safeStringN(trade, ['i', 'tradeId', 'execId']),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'symbol': market['symbol'],
'order': this.safeString2(trade, 'orderId', 'oi'),
'type': this.safeStringLower(trade, 'orderType'),
'side': side,
'takerOrMaker': takerOrMaker,
'price': this.safeString2(trade, 'p', 'price'),
'amount': amount,
'cost': undefined,
'fee': {
'currency': this.safeCurrencyCode(this.safeString2(trade, 'feeCurrency', 'feeCoin')),
'cost': this.safeString(trade, 'fee'),
},
}, market);
}
/**
* @method
* @name xt#fetchBalance
* @description query for balance and get the amount of funds available for trading or funds locked in orders
* @see https://doc.xt.com/#balancebalancesGet
* @see https://doc.xt.com/#futures_usergetBalances
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/en/latest/manual.html?#balance-structure}
*/
async fetchBalance(params = {}) {
await this.loadMarkets();
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
[subType, params] = this.handleSubTypeAndParams('fetchBalance', undefined, params);
const isContractWallet = ((type === 'swap') || (type === 'future'));
if (subType === 'inverse') {
response = await this.privateInverseGetFutureUserV1BalanceList(params);
}
else if ((subType === 'linear') || isContractWallet) {
response = await this.privateLinearGetFutureUserV1BalanceList(params);
}
else {
response = await this.privateSpotGetBalances(params);
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "totalUsdtAmount": "31.75931133",
// "totalBtcAmount": "0.00115951",
// "assets": [
// {
// "currency": "usdt",
// "currencyId": 11,
// "frozenAmount": "0.03834082",
// "availableAmount": "31.70995965",
// "totalAmount": "31.74830047",
// "convertBtcAmount": "0.00115911",
// "convertUsdtAmount": "31.74830047"
// },
// ]
// }
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "coin": "usdt",
// "walletBalance": "19.29849875",
// "openOrderMarginFrozen": "0",
// "isolatedMargin": "0.709475",
// "crossedMargin": "0",
// "availableBalance": "18.58902375",
// "bonus": "0",
// "coupon":"0"
// }
// ]
// }
//
let balances = undefined;
if ((subType !== undefined) || isContractWallet) {
balances = this.safeValue(response, 'result', []);
}
else {
const data = this.safeValue(response, 'result', {});
balances = this.safeValue(data, 'assets', []);
}
return this.parseBalance(balances);
}
parseBalance(response) {
//
// spot
//
// {
// "currency": "usdt",
// "currencyId": 11,
// "frozenAmount": "0.03834082",
// "availableAmount": "31.70995965",
// "totalAmount": "31.74830047",
// "convertBtcAmount": "0.00115911",
// "convertUsdtAmount": "31.74830047"
// }
//
// swap and future
//
// {
// "coin": "usdt",
// "walletBalance": "19.29849875",
// "openOrderMarginFrozen": "0",
// "isolatedMargin": "0.709475",
// "crossedMargin": "0",
// "availableBalance": "18.58902375",
// "bonus": "0",
// "coupon":"0"
// }
//
const result = { 'info': response };
for (let i = 0; i < response.length; i++) {
const balance = response[i];
const currencyId = this.safeString2(balance, 'currency', 'coin');
const code = this.safeCurrencyCode(currencyId);
const account = this.account();
const free = this.safeString2(balance, 'availableAmount', 'availableBalance');
let used = this.safeString(balance, 'frozenAmount');
const total = this.safeString2(balance, 'totalAmount', 'walletBalance');
if (used === undefined) {
const crossedAndIsolatedMargin = Precise["default"].stringAdd(this.safeString(balance, 'crossedMargin'), this.safeString(balance, 'isolatedMargin'));
used = Precise["default"].stringAdd(this.safeString(balance, 'openOrderMarginFrozen'), crossedAndIsolatedMargin);
}
account['free'] = free;
account['used'] = used;
account['total'] = total;
result[code] = account;
}
return this.safeBalance(result);
}
/**
* @method
* @name xt#createMarketBuyOrderWithCost
* @see https://doc.xt.com/#orderorderPost
* @description create a market buy order by providing the symbol and cost
* @param {string} symbol unified symbol of the market to create an order in
* @param {float} cost how much you want to trade in units of the quote currency
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
if (!market['spot']) {
throw new errors.NotSupported(this.id + ' createMarketBuyOrderWithCost() supports spot orders only');
}
return await this.createOrder(symbol, 'market', 'buy', cost, 1, params);
}
/**
* @method
* @name xt#createOrder
* @description create a trade order
* @see https://doc.xt.com/#orderorderPost
* @see https://doc.xt.com/#futures_ordercreate
* @see https://doc.xt.com/#futures_entrustcreatePlan
* @see https://doc.xt.com/#futures_entrustcreateProfit
* @param {string} symbol unified symbol of the market to create an order in
* @param {string} type 'market' or 'limit'
* @param {string} side 'buy' or 'sell'
* @param {float} amount how much you want to trade in units of the base currency
* @param {float} [price] the price to fulfill the order, in units of the quote currency, can be ignored in market orders
* @param {object} params extra parameters specific to the xt api endpoint
* @param {string} [params.timeInForce] 'GTC', 'IOC', 'FOK' or 'GTX'
* @param {string} [params.entrustType] 'TAKE_PROFIT', 'STOP', 'TAKE_PROFIT_MARKET', 'STOP_MARKET', 'TRAILING_STOP_MARKET', required if stopPrice is defined, currently isn't functioning on xt's side
* @param {string} [params.triggerPriceType] 'INDEX_PRICE', 'MARK_PRICE', 'LATEST_PRICE', required if stopPrice is defined
* @param {float} [params.triggerPrice] price to trigger a stop order
* @param {float} [params.stopPrice] alias for triggerPrice
* @param {float} [params.stopLoss] price to set a stop-loss on an open position
* @param {float} [params.takeProfit] price to set a take-profit on an open position
* @returns {object} an [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
symbol = market['symbol'];
if (market['spot']) {
return await this.createSpotOrder(symbol, type, side, amount, price, params);
}
else {
return await this.createContractOrder(symbol, type, side, amount, price, params);
}
}
async createSpotOrder(symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
'side': side.toUpperCase(),
'type': type.toUpperCase(),
};
let timeInForce = undefined;
let marginMode = undefined;
[marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
const marginOrSpotRequest = (marginMode !== undefined) ? 'LEVER' : 'SPOT';
request['bizType'] = marginOrSpotRequest;
if (type === 'market') {
timeInForce = this.safeStringUpper(params, 'timeInForce', 'FOK');
if (side === 'buy') {
const cost = this.safeString(params, 'cost');
params = this.omit(params, 'cost');
const createMarketBuyOrderRequiresPrice = this.safeBool(this.options, 'createMarketBuyOrderRequiresPrice', true);
if (createMarketBuyOrderRequiresPrice) {
if (price === undefined && (cost === undefined)) {
throw new errors.InvalidOrder(this.id + ' createOrder() requires a price argument or cost in params for market buy orders on spot markets to calculate the total amount to spend (amount * price), alternatively set the createMarketBuyOrderRequiresPrice option to false and pass in the cost to spend into the amount parameter');
}
else {
const amountString = this.numberToString(amount);
const priceString = this.numberToString(price);
let costCalculated = undefined;
if (price !== undefined) {
costCalculated = Precise["default"].stringMul(amountString, priceString);
}
else {
costCalculated = cost;
}
request['quoteQty'] = this.costToPrecision(symbol, costCalculated);
}
}
else {
const amountCost = (cost !== undefined) ? cost : amount;
request['quoteQty'] = this.costToPrecision(symbol, amountCost);
}
}
}
else {
timeInForce = this.safeStringUpper(params, 'timeInForce', 'GTC');
request['price'] = this.priceToPrecision(symbol, price);
}
if ((side === 'sell') || (type === 'limit')) {
request['quantity'] = this.amountToPrecision(symbol, amount);
}
request['timeInForce'] = timeInForce;
const response = await this.privateSpotPostOrder(this.extend(request, params));
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "orderId": "204371980095156544"
// }
// }
//
const order = this.safeValue(response, 'result', {});
return this.parseOrder(order, market);
}
async createContractOrder(symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
'origQty': this.amountToPrecision(symbol, amount),
};
const timeInForce = this.safeStringUpper(params, 'timeInForce');
if (timeInForce !== undefined) {
request['timeInForce'] = timeInForce;
}
const reduceOnly = this.safeValue(params, 'reduceOnly', false);
if (side === 'buy') {
const requestType = (reduceOnly) ? 'SHORT' : 'LONG';
request['positionSide'] = requestType;
}
else {
const requestType = (reduceOnly) ? 'LONG' : 'SHORT';
request['positionSide'] = requestType;
}
let response = undefined;
const triggerPrice = this.safeNumber2(params, 'triggerPrice', 'stopPrice');
const stopLoss = this.safeNumber2(params, 'stopLoss', 'triggerStopPrice');
const takeProfit = this.safeNumber2(params, 'takeProfit', 'triggerProfitPrice');
const isTrigger = (triggerPrice !== undefined);
const isStopLoss = (stopLoss !== undefined);
const isTakeProfit = (takeProfit !== undefined);
if (price !== undefined) {
if (!(isStopLoss) && !(isTakeProfit)) {
request['price'] = this.priceToPrecision(symbol, price);
}
}
if (isTrigger) {
request['timeInForce'] = this.safeStringUpper(params, 'timeInForce', 'GTC');
request['triggerPriceType'] = this.safeString(params, 'triggerPriceType', 'LATEST_PRICE');
request['orderSide'] = side.toUpperCase();
request['stopPrice'] = this.priceToPrecision(symbol, triggerPrice);
const entrustType = (type === 'market') ? 'STOP_MARKET' : 'STOP';
request['entrustType'] = entrustType;
params = this.omit(params, 'triggerPrice');
if (market['linear']) {
response = await this.privateLinearPostFutureTradeV1EntrustCreatePlan(this.extend(request, params));
}
else if (market['inverse']) {
response = await this.privateInversePostFutureTradeV1EntrustCreatePlan(this.extend(request, params));
}
}
else if (isStopLoss || isTakeProfit) {
if (isStopLoss) {
request['triggerStopPrice'] = this.priceToPrecision(symbol, stopLoss);
}
else {
request['triggerProfitPrice'] = this.priceToPrecision(symbol, takeProfit);
}
params = this.omit(params, ['stopLoss', 'takeProfit']);
if (market['linear']) {
response = await this.privateLinearPostFutureTradeV1EntrustCreateProfit(this.extend(request, params));
}
else if (market['inverse']) {
response = await this.privateInversePostFutureTradeV1EntrustCreateProfit(this.extend(request, params));
}
}
else {
request['orderSide'] = side.toUpperCase();
request['orderType'] = type.toUpperCase();
if (market['linear']) {
response = await this.privateLinearPostFutureTradeV1OrderCreate(this.extend(request, params));
}
else if (market['inverse']) {
response = await this.privateInversePostFutureTradeV1OrderCreate(this.extend(request, params));
}
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": "206410760006650176"
// }
//
return this.parseOrder(response, market);
}
/**
* @method
* @name xt#fetchOrder
* @description fetches information on an order made by the user
* @see https://doc.xt.com/#orderorderGet
* @see https://doc.xt.com/#futures_ordergetById
* @see https://doc.xt.com/#futures_entrustgetPlanById
* @see https://doc.xt.com/#futures_entrustgetProfitById
* @param {string} id order id
* @param {string} [symbol] unified symbol of the market the order was made in
* @param {object} params extra parameters specific to the xt api endpoint
* @param {bool} [params.trigger] if the order is a trigger order or not
* @param {bool} [params.stopLossTakeProfit] if the order is a stop-loss or take-profit order
* @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async fetchOrder(id, symbol = undefined, params = {}) {
await this.loadMarkets();
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
}
const request = {};
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('fetchOrder', market, params);
[subType, params] = this.handleSubTypeAndParams('fetchOrder', market, params);
const trigger = this.safeValue(params, 'stop');
const stopLossTakeProfit = this.safeValue(params, 'stopLossTakeProfit');
if (trigger) {
request['entrustId'] = id;
}
else if (stopLossTakeProfit) {
request['profitId'] = id;
}
else {
request['orderId'] = id;
}
if (trigger) {
params = this.omit(params, 'stop');
if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1EntrustPlanDetail(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureTradeV1EntrustPlanDetail(this.extend(request, params));
}
}
else if (stopLossTakeProfit) {
params = this.omit(params, 'stopLossTakeProfit');
if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1EntrustProfitDetail(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureTradeV1EntrustProfitDetail(this.extend(request, params));
}
}
else if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1OrderDetail(this.extend(request, params));
}
else if ((subType === 'linear') || (type === 'swap') || (type === 'future')) {
response = await this.privateLinearGetFutureTradeV1OrderDetail(this.extend(request, params));
}
else {
response = await this.privateSpotGetOrderOrderId(this.extend(request, params));
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "symbol": "btc_usdt",
// "orderId": "207505997850909952",
// "clientOrderId": null,
// "baseCurrency": "btc",
// "quoteCurrency": "usdt",
// "side": "BUY",
// "type": "LIMIT",
// "timeInForce": "GTC",
// "price": "20000.00",
// "origQty": "0.001000",
// "origQuoteQty": "20.00",
// "executedQty": "0.000000",
// "leavingQty": "0.001000",
// "tradeBase": "0.000000",
// "tradeQuote": "0.00",
// "avgPrice": null,
// "fee": null,
// "feeCurrency": null,
// "closed": false,
// "state": "NEW",
// "time": 1679175285162,
// "updatedTime": 1679175285255
// }
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "orderId": "211451874783183936",
// "clientOrderId": null,
// "symbol": "btc_usdt",
// "orderType": "LIMIT",
// "orderSide": "BUY",
// "positionSide": "LONG",
// "timeInForce": "GTC",
// "closePosition": false,
// "price": "20000",
// "origQty": "10",
// "avgPrice": "0",
// "executedQty": "0",
// "marginFrozen": "1.34533334",
// "remark": null,
// "triggerProfitPrice": null,
// "triggerStopPrice": null,
// "sourceId": null,
// "sourceType": "DEFAULT",
// "forceClose": false,
// "closeProfit": null,
// "state": "NEW",
// "createdTime": 1680116055693,
// "updatedTime": 1680116055693
// }
// }
//
// trigger
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "entrustId": "216300248132756992",
// "symbol": "btc_usdt",
// "entrustType": "STOP",
// "orderSide": "SELL",
// "positionSide": "SHORT",
// "timeInForce": "GTC",
// "closePosition": null,
// "price": "20000",
// "origQty": "1",
// "stopPrice": "19000",
// "triggerPriceType": "LATEST_PRICE",
// "state": "NOT_TRIGGERED",
// "marketOrderLevel": null,
// "createdTime": 1681271998064,
// "updatedTime": 1681271998064,
// "ordinary": false
// }
// }
//
// stop-loss and take-profit
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "profitId": "216306213226230400",
// "symbol": "btc_usdt",
// "positionSide": "LONG",
// "origQty": "1",
// "triggerPriceType": "LATEST_PRICE",
// "triggerProfitPrice": null,
// "triggerStopPrice": "20000",
// "entryPrice": null,
// "positionSize": null,
// "isolatedMargin": null,
// "executedQty": null,
// "avgPrice": null,
// "positionType": "ISOLATED",
// "state": "NOT_TRIGGERED",
// "createdTime": 1681273420039
// }
// }
//
const order = this.safeValue(response, 'result', {});
return this.parseOrder(order, market);
}
/**
* @method
* @name xt#fetchOrders
* @description fetches information on multiple orders made by the user
* @see https://doc.xt.com/#orderhistoryOrderGet
* @see https://doc.xt.com/#futures_ordergetHistory
* @see https://doc.xt.com/#futures_entrustgetPlanHistory
* @param {string} [symbol] unified market symbol of the market the orders were made in
* @param {int} [since] timestamp in ms of the earliest order
* @param {int} [limit] the maximum number of order structures to retrieve
* @param {object} params extra parameters specific to the xt api endpoint
* @param {bool} [params.trigger] if the order is a trigger order or not
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const request = {};
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
request['symbol'] = market['id'];
}
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('fetchOrders', market, params);
[subType, params] = this.handleSubTypeAndParams('fetchOrders', market, params);
const trigger = this.safeValue2(params, 'trigger', 'stop');
if (trigger) {
params = this.omit(params, ['trigger', 'stop']);
if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1EntrustPlanListHistory(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureTradeV1EntrustPlanListHistory(this.extend(request, params));
}
}
else if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1OrderListHistory(this.extend(request, params));
}
else if ((subType === 'linear') || (type === 'swap') || (type === 'future')) {
response = await this.privateLinearGetFutureTradeV1OrderListHistory(this.extend(request, params));
}
else {
let marginMode = undefined;
[marginMode, params] = this.handleMarginModeAndParams('fetchOrders', params);
const marginOrSpotRequest = (marginMode !== undefined) ? 'LEVER' : 'SPOT';
request['bizType'] = marginOrSpotRequest;
response = await this.privateSpotGetHistoryOrder(this.extend(request, params));
}
//
// spot and margin
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "hasPrev": false,
// "hasNext": true,
// "items": [
// {
// "symbol": "btc_usdt",
// "orderId": "207505997850909952",
// "clientOrderId": null,
// "baseCurrency": "btc",
// "quoteCurrency": "usdt",
// "side": "BUY",
// "type": "LIMIT",
// "timeInForce": "GTC",
// "price": "20000.00",
// "origQty": "0.001000",
// "origQuoteQty": "20.00",
// "executedQty": "0.000000",
// "leavingQty": "0.000000",
// "tradeBase": "0.000000",
// "tradeQuote": "0.00",
// "avgPrice": null,
// "fee": null,
// "feeCurrency": null,
// "closed": true,
// "state": "CANCELED",
// "time": 1679175285162,
// "updatedTime": 1679175488492
// },
// ]
// }
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "hasPrev": false,
// "hasNext": true,
// "items": [
// {
// "orderId": "207519546930995456",
// "clientOrderId": null,
// "symbol": "btc_usdt",
// "orderType": "LIMIT",
// "orderSide": "BUY",
// "positionSide": "LONG",
// "timeInForce": "GTC",
// "closePosition": false,
// "price": "20000",
// "origQty": "100",
// "avgPrice": "0",
// "executedQty": "0",
// "marginFrozen": "4.12",
// "remark": null,
// "triggerProfitPrice": null,
// "triggerStopPrice": null,
// "sourceId": null,
// "sourceType": "DEFAULT",
// "forceClose": false,
// "closeProfit": null,
// "state": "CANCELED",
// "createdTime": 1679178515689,
// "updatedTime": 1679180096172
// },
// ]
// }
// }
//
// stop
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "hasPrev": false,
// "hasNext": false,
// "items": [
// {
// "entrustId": "216300248132756992",
// "symbol": "btc_usdt",
// "entrustType": "STOP",
// "orderSide": "SELL",
// "positionSide": "SHORT",
// "timeInForce": "GTC",
// "closePosition": null,
// "price": "20000",
// "origQty": "1",
// "stopPrice": "19000",
// "triggerPriceType": "LATEST_PRICE",
// "state": "USER_REVOCATION",
// "marketOrderLevel": null,
// "createdTime": 1681271998064,
// "updatedTime": 1681273188674,
// "ordinary": false
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
const orders = this.safeValue(data, 'items', []);
return this.parseOrders(orders, market, since, limit);
}
async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
let request = {};
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
request['symbol'] = market['id'];
}
if (limit !== undefined) {
request['size'] = limit;
}
if (since !== undefined) {
request['startTime'] = since;
}
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('fetchOrdersByStatus', market, params);
[subType, params] = this.handleSubTypeAndParams('fetchOrdersByStatus', market, params);
const trigger = this.safeBool2(params, 'stop', 'trigger');
const stopLossTakeProfit = this.safeValue(params, 'stopLossTakeProfit');
if (status === 'open') {
if (trigger || stopLossTakeProfit) {
request['state'] = 'NOT_TRIGGERED';
}
else if (type === 'swap') {
request['state'] = 'UNFINISHED'; // NEW & PARTIALLY_FILLED
}
}
else if (status === 'closed') {
if (trigger || stopLossTakeProfit) {
request['state'] = 'TRIGGERED';
}
else {
request['state'] = 'FILLED';
}
}
else if (status === 'canceled') {
if (trigger || stopLossTakeProfit) {
request['state'] = 'USER_REVOCATION';
}
else {
request['state'] = 'CANCELED';
}
}
else {
request['state'] = status;
}
if (trigger || stopLossTakeProfit || (subType !== undefined) || (type === 'swap') || (type === 'future')) {
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['size'] = limit;
}
}
if (trigger) {
params = this.omit(params, ['stop', 'trigger']);
if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1EntrustPlanList(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureTradeV1EntrustPlanList(this.extend(request, params));
}
}
else if (stopLossTakeProfit) {
params = this.omit(params, 'stopLossTakeProfit');
if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1EntrustProfitList(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureTradeV1EntrustProfitList(this.extend(request, params));
}
}
else if ((subType !== undefined) || (type === 'swap') || (type === 'future')) {
if (subType === 'inverse') {
response = await this.privateInverseGetFutureTradeV1OrderList(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureTradeV1OrderList(this.extend(request, params));
}
}
else {
let marginMode = undefined;
[marginMode, params] = this.handleMarginModeAndParams('fetchOrdersByStatus', params);
const marginOrSpotRequest = (marginMode !== undefined) ? 'LEVER' : 'SPOT';
request['bizType'] = marginOrSpotRequest;
if (status !== 'open') {
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request = this.omit(request, 'size');
request['limit'] = limit;
}
response = await this.privateSpotGetHistoryOrder(this.extend(request, params));
}
else {
response = await this.privateSpotGetOpenOrder(this.extend(request, params));
}
}
//
// spot and margin
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "hasPrev": false,
// "hasNext": true,
// "items": [
// {
// "symbol": "btc_usdt",
// "orderId": "207505997850909952",
// "clientOrderId": null,
// "baseCurrency": "btc",
// "quoteCurrency": "usdt",
// "side": "BUY",
// "type": "LIMIT",
// "timeInForce": "GTC",
// "price": "20000.00",
// "origQty": "0.001000",
// "origQuoteQty": "20.00",
// "executedQty": "0.000000",
// "leavingQty": "0.000000",
// "tradeBase": "0.000000",
// "tradeQuote": "0.00",
// "avgPrice": null,
// "fee": null,
// "feeCurrency": null,
// "closed": true,
// "state": "CANCELED",
// "time": 1679175285162,
// "updatedTime": 1679175488492
// },
// ]
// }
// }
//
// spot and margin: fetchOpenOrders
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": [
// {
// "symbol": "eth_usdt",
// "orderId": "208249323222264320",
// "clientOrderId": null,
// "baseCurrency": "eth",
// "quoteCurrency": "usdt",
// "side": "BUY",
// "type": "LIMIT",
// "timeInForce": "GTC",
// "price": "1300.00",
// "origQty": "0.0032",
// "origQuoteQty": "4.16",
// "executedQty": "0.0000",
// "leavingQty": "0.0032",
// "tradeBase": "0.0000",
// "tradeQuote": "0.00",
// "avgPrice": null,
// "fee": null,
// "feeCurrency": null,
// "closed": false,
// "state": "NEW",
// "time": 1679352507741,
// "updatedTime": 1679352507869
// },
// ]
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "page": 1,
// "ps": 10,
// "total": 25,
// "items": [
// {
// "orderId": "207519546930995456",
// "clientOrderId": null,
// "symbol": "btc_usdt",
// "orderType": "LIMIT",
// "orderSide": "BUY",
// "positionSide": "LONG",
// "timeInForce": "GTC",
// "closePosition": false,
// "price": "20000",
// "origQty": "100",
// "avgPrice": "0",
// "executedQty": "0",
// "marginFrozen": "4.12",
// "remark": null,
// "triggerProfitPrice": null,
// "triggerStopPrice": null,
// "sourceId": null,
// "sourceType": "DEFAULT",
// "forceClose": false,
// "closeProfit": null,
// "state": "CANCELED",
// "createdTime": 1679178515689,
// "updatedTime": 1679180096172
// },
// ]
// }
// }
//
// stop
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "page": 1,
// "ps": 3,
// "total": 8,
// "items": [
// {
// "entrustId": "216300248132756992",
// "symbol": "btc_usdt",
// "entrustType": "STOP",
// "orderSide": "SELL",
// "positionSide": "SHORT",
// "timeInForce": "GTC",
// "closePosition": null,
// "price": "20000",
// "origQty": "1",
// "stopPrice": "19000",
// "triggerPriceType": "LATEST_PRICE",
// "state": "USER_REVOCATION",
// "marketOrderLevel": null,
// "createdTime": 1681271998064,
// "updatedTime": 1681273188674,
// "ordinary": false
// },
// ]
// }
// }
//
// stop-loss and take-profit
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "page": 1,
// "ps": 3,
// "total": 2,
// "items": [
// {
// "profitId": "216306213226230400",
// "symbol": "btc_usdt",
// "positionSide": "LONG",
// "origQty": "1",
// "triggerPriceType": "LATEST_PRICE",
// "triggerProfitPrice": null,
// "triggerStopPrice": "20000",
// "entryPrice": "0",
// "positionSize": "0",
// "isolatedMargin": "0",
// "executedQty": "0",
// "avgPrice": null,
// "positionType": "ISOLATED",
// "state": "USER_REVOCATION",
// "createdTime": 1681273420039
// },
// ]
// }
// }
//
let orders = [];
const resultDict = this.safeDict(response, 'result');
if (resultDict !== undefined) {
orders = this.safeList(resultDict, 'items', []);
}
else {
orders = this.safeList(response, 'result');
}
return this.parseOrders(orders, market, since, limit);
}
/**
* @method
* @name xt#fetchOpenOrders
* @description fetch all unfilled currently open orders
* @see https://doc.xt.com/#orderopenOrderGet
* @see https://doc.xt.com/#futures_ordergetOrders
* @see https://doc.xt.com/#futures_entrustgetPlan
* @see https://doc.xt.com/#futures_entrustgetProfit
* @param {string} [symbol] unified market symbol of the market the orders were made in
* @param {int} [since] timestamp in ms of the earliest order
* @param {int} [limit] the maximum number of open order structures to retrieve
* @param {object} params extra parameters specific to the xt api endpoint
* @param {bool} [params.trigger] if the order is a trigger order or not
* @param {bool} [params.stopLossTakeProfit] if the order is a stop-loss or take-profit order
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
return await this.fetchOrdersByStatus('open', symbol, since, limit, params);
}
/**
* @method
* @name xt#fetchClosedOrders
* @description fetches information on multiple closed orders made by the user
* @see https://doc.xt.com/#orderhistoryOrderGet
* @see https://doc.xt.com/#futures_ordergetOrders
* @see https://doc.xt.com/#futures_entrustgetPlan
* @see https://doc.xt.com/#futures_entrustgetProfit
* @param {string} [symbol] unified market symbol of the market the orders were made in
* @param {int} [since] timestamp in ms of the earliest order
* @param {int} [limit] the maximum number of order structures to retrieve
* @param {object} params extra parameters specific to the xt api endpoint
* @param {bool} [params.trigger] if the order is a trigger order or not
* @param {bool} [params.stopLossTakeProfit] if the order is a stop-loss or take-profit order
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
return await this.fetchOrdersByStatus('closed', symbol, since, limit, params);
}
/**
* @method
* @name xt#fetchCanceledOrders
* @description fetches information on multiple canceled orders made by the user
* @see https://doc.xt.com/#orderhistoryOrderGet
* @see https://doc.xt.com/#futures_ordergetOrders
* @see https://doc.xt.com/#futures_entrustgetPlan
* @see https://doc.xt.com/#futures_entrustgetProfit
* @param {string} [symbol] unified market symbol of the market the orders were made in
* @param {int} [since] timestamp in ms of the earliest order
* @param {int} [limit] the maximum number of order structures to retrieve
* @param {object} params extra parameters specific to the xt api endpoint
* @param {bool} [params.trigger] if the order is a trigger order or not
* @param {bool} [params.stopLossTakeProfit] if the order is a stop-loss or take-profit order
* @returns {object} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
return await this.fetchOrdersByStatus('canceled', symbol, since, limit, params);
}
/**
* @method
* @name xt#cancelOrder
* @description cancels an open order
* @see https://doc.xt.com/#orderorderDel
* @see https://doc.xt.com/#futures_ordercancel
* @see https://doc.xt.com/#futures_entrustcancelPlan
* @see https://doc.xt.com/#futures_entrustcancelProfit
* @param {string} id order id
* @param {string} [symbol] unified symbol of the market the order was made in
* @param {object} params extra parameters specific to the xt api endpoint
* @param {bool} [params.trigger] if the order is a trigger order or not
* @param {bool} [params.stopLossTakeProfit] if the order is a stop-loss or take-profit order
* @returns {object} An [order structure]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async cancelOrder(id, symbol = undefined, params = {}) {
await this.loadMarkets();
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
}
const request = {};
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('cancelOrder', market, params);
[subType, params] = this.handleSubTypeAndParams('cancelOrder', market, params);
const trigger = this.safeValue2(params, 'trigger', 'stop');
const stopLossTakeProfit = this.safeValue(params, 'stopLossTakeProfit');
if (trigger) {
request['entrustId'] = id;
}
else if (stopLossTakeProfit) {
request['profitId'] = id;
}
else {
request['orderId'] = id;
}
if (trigger) {
params = this.omit(params, ['trigger', 'stop']);
if (subType === 'inverse') {
response = await this.privateInversePostFutureTradeV1EntrustCancelPlan(this.extend(request, params));
}
else {
response = await this.privateLinearPostFutureTradeV1EntrustCancelPlan(this.extend(request, params));
}
}
else if (stopLossTakeProfit) {
params = this.omit(params, 'stopLossTakeProfit');
if (subType === 'inverse') {
response = await this.privateInversePostFutureTradeV1EntrustCancelProfitStop(this.extend(request, params));
}
else {
response = await this.privateLinearPostFutureTradeV1EntrustCancelProfitStop(this.extend(request, params));
}
}
else if (subType === 'inverse') {
response = await this.privateInversePostFutureTradeV1OrderCancel(this.extend(request, params));
}
else if ((subType === 'linear') || (type === 'swap') || (type === 'future')) {
response = await this.privateLinearPostFutureTradeV1OrderCancel(this.extend(request, params));
}
else {
response = await this.privateSpotDeleteOrderOrderId(this.extend(request, params));
}
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "cancelId": "208322474307982720"
// }
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": "208319789679471616"
// }
//
const isContractResponse = ((subType !== undefined) || (type === 'swap') || (type === 'future'));
const order = isContractResponse ? response : this.safeValue(response, 'result', {});
return this.parseOrder(order, market);
}
/**
* @method
* @name xt#cancelAllOrders
* @description cancel all open orders in a market
* @see https://doc.xt.com/#orderopenOrderDel
* @see https://doc.xt.com/#futures_ordercancelBatch
* @see https://doc.xt.com/#futures_entrustcancelPlanBatch
* @see https://doc.xt.com/#futures_entrustcancelProfitBatch
* @param {string} [symbol] unified market symbol of the market to cancel orders in
* @param {object} params extra parameters specific to the xt api endpoint
* @param {bool} [params.trigger] if the order is a trigger order or not
* @param {bool} [params.stopLossTakeProfit] if the order is a stop-loss or take-profit order
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async cancelAllOrders(symbol = undefined, params = {}) {
await this.loadMarkets();
const request = {};
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
request['symbol'] = market['id'];
}
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('cancelAllOrders', market, params);
[subType, params] = this.handleSubTypeAndParams('cancelAllOrders', market, params);
const trigger = this.safeValue2(params, 'trigger', 'stop');
const stopLossTakeProfit = this.safeValue(params, 'stopLossTakeProfit');
if (trigger) {
params = this.omit(params, ['trigger', 'stop']);
if (subType === 'inverse') {
response = await this.privateInversePostFutureTradeV1EntrustCancelAllPlan(this.extend(request, params));
}
else {
response = await this.privateLinearPostFutureTradeV1EntrustCancelAllPlan(this.extend(request, params));
}
}
else if (stopLossTakeProfit) {
params = this.omit(params, 'stopLossTakeProfit');
if (subType === 'inverse') {
response = await this.privateInversePostFutureTradeV1EntrustCancelAllProfitStop(this.extend(request, params));
}
else {
response = await this.privateLinearPostFutureTradeV1EntrustCancelAllProfitStop(this.extend(request, params));
}
}
else if (subType === 'inverse') {
response = await this.privateInversePostFutureTradeV1OrderCancelAll(this.extend(request, params));
}
else if ((subType === 'linear') || (type === 'swap') || (type === 'future')) {
response = await this.privateLinearPostFutureTradeV1OrderCancelAll(this.extend(request, params));
}
else {
let marginMode = undefined;
[marginMode, params] = this.handleMarginModeAndParams('cancelAllOrders', params);
const marginOrSpotRequest = (marginMode !== undefined) ? 'LEVER' : 'SPOT';
request['bizType'] = marginOrSpotRequest;
response = await this.privateSpotDeleteOpenOrder(this.extend(request, params));
}
//
// spot and margin
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": null
// }
//
// swap and future
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": true
// }
//
return [
this.safeOrder(response),
];
}
/**
* @method
* @name xt#cancelOrders
* @description cancel multiple orders
* @see https://doc.xt.com/#orderbatchOrderDel
* @param {string[]} ids order ids
* @param {string} [symbol] unified market symbol of the market to cancel orders in
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/en/latest/manual.html#order-structure}
*/
async cancelOrders(ids, symbol = undefined, params = {}) {
await this.loadMarkets();
const request = {
'orderIds': ids,
};
let market = undefined;
if (symbol !== undefined) {
market = this.market(symbol);
}
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('cancelOrders', market, params);
if (subType !== undefined) {
throw new errors.NotSupported(this.id + ' cancelOrders() does not support swap and future orders, only spot orders are accepted');
}
const response = await this.privateSpotDeleteBatchOrder(this.extend(request, params));
//
// spot
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": null
// }
//
return [
this.safeOrder(response),
];
}
parseOrder(order, market = undefined) {
//
// spot: createOrder
//
// {
// "orderId": "204371980095156544"
// }
//
// spot: cancelOrder
//
// {
// "cancelId": "208322474307982720"
// }
//
// swap and future: createOrder, cancelOrder, editOrder
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": "206410760006650176"
// }
//
// spot: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
//
// {
// "symbol": "btc_usdt",
// "orderId": "207505997850909952",
// "clientOrderId": null,
// "baseCurrency": "btc",
// "quoteCurrency": "usdt",
// "side": "BUY",
// "type": "LIMIT",
// "timeInForce": "GTC",
// "price": "20000.00",
// "origQty": "0.001000",
// "origQuoteQty": "20.00",
// "executedQty": "0.000000",
// "leavingQty": "0.001000",
// "tradeBase": "0.000000",
// "tradeQuote": "0.00",
// "avgPrice": null,
// "fee": null,
// "feeCurrency": null,
// "closed": false,
// "state": "NEW",
// "time": 1679175285162,
// "updatedTime": 1679175285255
// }
//
// swap and future: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
//
// {
// "orderId": "207519546930995456",
// "clientOrderId": null,
// "symbol": "btc_usdt",
// "orderType": "LIMIT",
// "orderSide": "BUY",
// "positionSide": "LONG",
// "timeInForce": "GTC",
// "closePosition": false,
// "price": "20000",
// "origQty": "100",
// "avgPrice": "0",
// "executedQty": "0",
// "marginFrozen": "4.12",
// "remark": null,
// "triggerProfitPrice": null,
// "triggerStopPrice": null,
// "sourceId": null,
// "sourceType": "DEFAULT",
// "forceClose": false,
// "closeProfit": null,
// "state": "CANCELED",
// "createdTime": 1679178515689,
// "updatedTime": 1679180096172
// }
//
// trigger: fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
//
// {
// "entrustId": "216300248132756992",
// "symbol": "btc_usdt",
// "entrustType": "STOP",
// "orderSide": "SELL",
// "positionSide": "SHORT",
// "timeInForce": "GTC",
// "closePosition": null,
// "price": "20000",
// "origQty": "1",
// "stopPrice": "19000",
// "triggerPriceType": "LATEST_PRICE",
// "state": "NOT_TRIGGERED",
// "marketOrderLevel": null,
// "createdTime": 1681271998064,
// "updatedTime": 1681271998064,
// "ordinary": false
// }
//
// stop-loss and take-profit: fetchOrder, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders, fetchOrdersByStatus
//
// {
// "profitId": "216306213226230400",
// "symbol": "btc_usdt",
// "positionSide": "LONG",
// "origQty": "1",
// "triggerPriceType": "LATEST_PRICE",
// "triggerProfitPrice": null,
// "triggerStopPrice": "20000",
// "entryPrice": null,
// "positionSize": null,
// "isolatedMargin": null,
// "executedQty": null,
// "avgPrice": null,
// "positionType": "ISOLATED",
// "state": "NOT_TRIGGERED",
// "createdTime": 1681273420039
// }
//
// spot editOrder
//
// {
// "orderId": "484203027161892224",
// "modifyId": "484203544105344000",
// "clientModifyId": null
// }
//
const marketId = this.safeString(order, 'symbol');
const marketType = ('result' in order) || ('positionSide' in order) ? 'contract' : 'spot';
market = this.safeMarket(marketId, market, undefined, marketType);
const symbol = this.safeSymbol(marketId, market, undefined, marketType);
const timestamp = this.safeInteger2(order, 'time', 'createdTime');
const quantity = this.safeNumber(order, 'origQty');
const amount = (marketType === 'spot') ? quantity : Precise["default"].stringMul(this.numberToString(quantity), this.numberToString(market['contractSize']));
const filledQuantity = this.safeNumber(order, 'executedQty');
const filled = (marketType === 'spot') ? filledQuantity : Precise["default"].stringMul(this.numberToString(filledQuantity), this.numberToString(market['contractSize']));
const lastUpdatedTimestamp = this.safeInteger(order, 'updatedTime');
return this.safeOrder({
'info': order,
'id': this.safeStringN(order, ['orderId', 'result', 'cancelId', 'entrustId', 'profitId']),
'clientOrderId': this.safeString2(order, 'clientOrderId', 'clientModifyId'),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'lastTradeTimestamp': lastUpdatedTimestamp,
'lastUpdateTimestamp': lastUpdatedTimestamp,
'symbol': symbol,
'type': this.safeStringLower2(order, 'type', 'orderType'),
'timeInForce': this.safeString(order, 'timeInForce'),
'postOnly': undefined,
'side': this.safeStringLower2(order, 'side', 'orderSide'),
'price': this.safeNumber(order, 'price'),
'triggerPrice': this.safeNumber(order, 'stopPrice'),
'stopLoss': this.safeNumber(order, 'triggerStopPrice'),
'takeProfit': this.safeNumber(order, 'triggerProfitPrice'),
'amount': amount,
'filled': filled,
'remaining': this.safeNumber(order, 'leavingQty'),
'cost': undefined,
'average': this.safeNumber(order, 'avgPrice'),
'status': this.parseOrderStatus(this.safeString(order, 'state')),
'fee': {
'currency': this.safeCurrencyCode(this.safeString(order, 'feeCurrency')),
'cost': this.safeNumber(order, 'fee'),
},
'trades': undefined,
}, market);
}
parseOrderStatus(status) {
const statuses = {
'NEW': 'open',
'PARTIALLY_FILLED': 'open',
'FILLED': 'closed',
'CANCELED': 'canceled',
'REJECTED': 'rejected',
'EXPIRED': 'expired',
'UNFINISHED': 'open',
'NOT_TRIGGERED': 'open',
'TRIGGERING': 'open',
'TRIGGERED': 'closed',
'USER_REVOCATION': 'canceled',
'PLATFORM_REVOCATION': 'rejected',
'HISTORY': 'expired',
};
return this.safeString(statuses, status, status);
}
/**
* @method
* @name xt#fetchLedger
* @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
* @see https://doc.xt.com/#futures_usergetBalanceBill
* @param {string} [code] unified currency code
* @param {int} [since] timestamp in ms of the earliest ledger entry
* @param {int} [limit] max number of ledger entries to return
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a [ledger structure]{@link https://docs.ccxt.com/en/latest/manual.html#ledger-structure}
*/
async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const request = {};
let currency = undefined;
if (code !== undefined) {
currency = this.currency(code);
}
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
let type = undefined;
let subType = undefined;
let response = undefined;
[type, params] = this.handleMarketTypeAndParams('fetchLedger', undefined, params);
[subType, params] = this.handleSubTypeAndParams('fetchLedger', undefined, params);
if (subType === 'inverse') {
response = await this.privateInverseGetFutureUserV1BalanceBills(this.extend(request, params));
}
else if ((subType === 'linear') || (type === 'swap') || (type === 'future')) {
response = await this.privateLinearGetFutureUserV1BalanceBills(this.extend(request, params));
}
else {
throw new errors.NotSupported(this.id + ' fetchLedger() does not support spot transactions, only swap and future wallet transactions are supported');
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "hasPrev": false,
// "hasNext": false,
// "items": [
// {
// "id": "207260567109387524",
// "coin": "usdt",
// "symbol": "btc_usdt",
// "type": "FEE",
// "amount": "-0.0213",
// "side": "SUB",
// "afterAmount": null,
// "createdTime": 1679116769914
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
const ledger = this.safeValue(data, 'items', []);
return this.parseLedger(ledger, currency, since, limit);
}
parseLedgerEntry(item, currency = undefined) {
//
// {
// "id": "207260567109387524",
// "coin": "usdt",
// "symbol": "btc_usdt",
// "type": "FEE",
// "amount": "-0.0213",
// "side": "SUB",
// "afterAmount": null,
// "createdTime": 1679116769914
// }
//
const side = this.safeString(item, 'side');
const direction = (side === 'ADD') ? 'in' : 'out';
const currencyId = this.safeString(item, 'coin');
currency = this.safeCurrency(currencyId, currency);
const timestamp = this.safeInteger(item, 'createdTime');
return this.safeLedgerEntry({
'info': item,
'id': this.safeString(item, 'id'),
'direction': direction,
'account': undefined,
'referenceId': undefined,
'referenceAccount': undefined,
'type': this.parseLedgerEntryType(this.safeString(item, 'type')),
'currency': this.safeCurrencyCode(currencyId, currency),
'amount': this.safeNumber(item, 'amount'),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'before': undefined,
'after': this.safeNumber(item, 'afterAmount'),
'status': undefined,
'fee': {
'currency': undefined,
'cost': undefined,
},
}, currency);
}
parseLedgerEntryType(type) {
const ledgerType = {
'EXCHANGE': 'transfer',
'CLOSE_POSITION': 'trade',
'TAKE_OVER': 'trade',
'MERGE': 'trade',
'QIANG_PING_MANAGER': 'fee',
'FUND': 'fee',
'FEE': 'fee',
'ADL': 'auto-deleveraging',
};
return this.safeString(ledgerType, type, type);
}
/**
* @method
* @name xt#fetchDepositAddress
* @description fetch the deposit address for a currency associated with this account
* @see https://doc.xt.com/#deposit_withdrawaldepositAddressGet
* @param {string} code unified currency code
* @param {object} params extra parameters specific to the xt api endpoint
* @param {string} params.network required network id
* @returns {object} an [address structure]{@link https://docs.ccxt.com/en/latest/manual.html#address-structure}
*/
async fetchDepositAddress(code, params = {}) {
await this.loadMarkets();
let networkCode = undefined;
[networkCode, params] = this.handleNetworkCodeAndParams(params);
const currency = this.currency(code);
const networkId = this.networkCodeToId(networkCode, code);
this.checkRequiredArgument('fetchDepositAddress', networkId, 'network');
const request = {
'currency': currency['id'],
'chain': networkId,
};
const response = await this.privateSpotGetDepositAddress(this.extend(request, params));
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
// "memo": ""
// }
// }
//
const result = this.safeValue(response, 'result', {});
return this.parseDepositAddress(result, currency);
}
parseDepositAddress(depositAddress, currency = undefined) {
//
// {
// "address": "0x7f7173cf29d3846d20ca5a3aec1120b93dbd157a",
// "memo": ""
// }
//
const address = this.safeString(depositAddress, 'address');
this.checkAddress(address);
return {
'info': depositAddress,
'currency': this.safeCurrencyCode(undefined, currency),
'network': undefined,
'address': address,
'tag': this.safeString(depositAddress, 'memo'),
};
}
/**
* @method
* @name xt#fetchDeposits
* @description fetch all deposits made to an account
* @see https://doc.xt.com/#deposit_withdrawalhistoryDepositGet
* @param {string} [code] unified currency code
* @param {int} [since] the earliest time in ms to fetch deposits for
* @param {int} [limit] the maximum number of transaction structures to retrieve
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/en/latest/manual.html#transaction-structure}
*/
async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const request = {};
let currency = undefined;
if (code !== undefined) {
currency = this.currency(code);
request['currency'] = currency['id'];
}
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit; // default 10, max 200
}
const response = await this.privateSpotGetDepositHistory(this.extend(request, params));
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "hasPrev": false,
// "hasNext": false,
// "items": [
// {
// "id": 170368702,
// "currency": "usdt",
// "chain": "Ethereum",
// "memo": "",
// "status": "SUCCESS",
// "amount": "31.792528",
// "confirmations": 12,
// "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
// "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
// "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
// "createdTime": 1678491442000
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
const deposits = this.safeValue(data, 'items', []);
return this.parseTransactions(deposits, currency, since, limit, params);
}
/**
* @method
* @name xt#fetchWithdrawals
* @description fetch all withdrawals made from an account
* @see https://doc.xt.com/#deposit_withdrawalwithdrawHistory
* @param {string} [code] unified currency code
* @param {int} [since] the earliest time in ms to fetch withdrawals for
* @param {int} [limit] the maximum number of transaction structures to retrieve
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/en/latest/manual.html#transaction-structure}
*/
async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const request = {};
let currency = undefined;
if (code !== undefined) {
currency = this.currency(code);
request['currency'] = currency['id'];
}
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit; // default 10, max 200
}
const response = await this.privateSpotGetWithdrawHistory(this.extend(request, params));
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "hasPrev": false,
// "hasNext": false,
// "items": [
// {
// "id": 950898,
// "currency": "usdt",
// "chain": "Tron",
// "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
// "memo": "",
// "status": "SUCCESS",
// "amount": "5",
// "fee": "2",
// "confirmations": 6,
// "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
// "createdTime": 1680049062000
// }
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
const withdrawals = this.safeValue(data, 'items', []);
return this.parseTransactions(withdrawals, currency, since, limit, params);
}
/**
* @method
* @name xt#withdraw
* @description make a withdrawal
* @see https://doc.xt.com/#deposit_withdrawalwithdraw
* @param {string} code unified currency code
* @param {float} amount the amount to withdraw
* @param {string} address the address to withdraw to
* @param {string} [tag]
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a [transaction structure]{@link https://docs.ccxt.com/en/latest/manual.html#transaction-structure}
*/
async withdraw(code, amount, address, tag = undefined, params = {}) {
this.checkAddress(address);
await this.loadMarkets();
const currency = this.currency(code);
[tag, params] = this.handleWithdrawTagAndParams(tag, params);
let networkCode = undefined;
[networkCode, params] = this.handleNetworkCodeAndParams(params);
const networkIdsByCodes = this.safeValue(this.options, 'networks', {});
const networkId = this.safeString2(networkIdsByCodes, networkCode, code, code);
const request = {
'currency': currency['id'],
'chain': networkId,
'amount': this.currencyToPrecision(code, amount),
'address': address,
};
if (tag !== undefined) {
request['memo'] = tag;
}
const response = await this.privateSpotPostWithdraw(this.extend(request, params));
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "id": 950898
// }
// }
//
const result = this.safeValue(response, 'result', {});
return this.parseTransaction(result, currency);
}
parseTransaction(transaction, currency = undefined) {
//
// fetchDeposits
//
// {
// "id": 170368702,
// "currency": "usdt",
// "chain": "Ethereum",
// "memo": "",
// "status": "SUCCESS",
// "amount": "31.792528",
// "confirmations": 12,
// "transactionId": "0x90b8487c258b81b85e15e461b1839c49d4d8e6e9de4c1adb658cd47d4f5c5321",
// "address": "0x7f7172cf29d3846d30ca5a3aec1120b92dbd150b",
// "fromAddr": "0x7830c87c02e56aff27fa9ab1241711331fa86f58",
// "createdTime": 1678491442000
// }
//
// fetchWithdrawals
//
// {
// "id": 950898,
// "currency": "usdt",
// "chain": "Tron",
// "address": "TGB2vxTjiqraVZBy7YHXF8V3CSMVhQKcaf",
// "memo": "",
// "status": "SUCCESS",
// "amount": "5",
// "fee": "2",
// "confirmations": 6,
// "transactionId": "c36e230b879842b1d7afd19d15ee1a866e26eaa0626e367d6f545d2932a15156",
// "createdTime": 1680049062000
// }
//
// withdraw
//
// {
// "id": 950898
// }
//
const type = ('fromAddr' in transaction) ? 'deposit' : 'withdraw';
const timestamp = this.safeInteger(transaction, 'createdTime');
const address = this.safeString(transaction, 'address');
const memo = this.safeString(transaction, 'memo');
const currencyCode = this.safeCurrencyCode(this.safeString(transaction, 'currency'), currency);
const fee = this.safeNumber(transaction, 'fee');
const feeCurrency = (fee !== undefined) ? currencyCode : undefined;
const networkId = this.safeString(transaction, 'chain');
return {
'info': transaction,
'id': this.safeString(transaction, 'id'),
'txid': this.safeString(transaction, 'transactionId'),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'updated': undefined,
'addressFrom': this.safeString(transaction, 'fromAddr'),
'addressTo': address,
'address': address,
'tagFrom': undefined,
'tagTo': undefined,
'tag': memo,
'type': type,
'amount': this.safeNumber(transaction, 'amount'),
'currency': currencyCode,
'network': this.networkIdToCode(networkId, currencyCode),
'status': this.parseTransactionStatus(this.safeString(transaction, 'status')),
'comment': memo,
'fee': {
'currency': feeCurrency,
'cost': fee,
'rate': undefined,
},
'internal': undefined,
};
}
parseTransactionStatus(status) {
const statuses = {
'SUBMIT': 'pending',
'REVIEW': 'pending',
'AUDITED': 'pending',
'PENDING': 'pending',
'CANCEL': 'canceled',
'FAIL': 'failed',
'SUCCESS': 'ok',
};
return this.safeString(statuses, status, status);
}
/**
* @method
* @name xt#setLeverage
* @description set the level of leverage for a market
* @see https://doc.xt.com/#futures_useradjustLeverage
* @param {float} leverage the rate of leverage
* @param {string} symbol unified market symbol
* @param {object} params extra parameters specific to the xt api endpoint
* @param {string} params.positionSide 'LONG' or 'SHORT'
* @returns {object} response from the exchange
*/
async setLeverage(leverage, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
}
const positionSide = this.safeString(params, 'positionSide');
this.checkRequiredArgument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT']);
if ((leverage < 1) || (leverage > 125)) {
throw new errors.BadRequest(this.id + ' setLeverage() leverage should be between 1 and 125');
}
await this.loadMarkets();
const market = this.market(symbol);
if (!(market['contract'])) {
throw new errors.BadSymbol(this.id + ' setLeverage() supports contract markets only');
}
const request = {
'symbol': market['id'],
'positionSide': positionSide,
'leverage': leverage,
};
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('setLeverage', market, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.privateInversePostFutureUserV1PositionAdjustLeverage(this.extend(request, params));
}
else {
response = await this.privateLinearPostFutureUserV1PositionAdjustLeverage(this.extend(request, params));
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": null
// }
//
return response;
}
/**
* @method
* @name xt#addMargin
* @description add margin to a position
* @see https://doc.xt.com/#futures_useradjustMargin
* @param {string} symbol unified market symbol
* @param {float} amount amount of margin to add
* @param {object} params extra parameters specific to the xt api endpoint
* @param {string} params.positionSide 'LONG' or 'SHORT'
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
*/
async addMargin(symbol, amount, params = {}) {
return await this.modifyMarginHelper(symbol, amount, 'ADD', params);
}
/**
* @method
* @name xt#reduceMargin
* @description remove margin from a position
* @see https://doc.xt.com/#futures_useradjustMargin
* @param {string} symbol unified market symbol
* @param {float} amount the amount of margin to remove
* @param {object} params extra parameters specific to the xt api endpoint
* @param {string} params.positionSide 'LONG' or 'SHORT'
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=reduce-margin-structure}
*/
async reduceMargin(symbol, amount, params = {}) {
return await this.modifyMarginHelper(symbol, amount, 'SUB', params);
}
async modifyMarginHelper(symbol, amount, addOrReduce, params = {}) {
const positionSide = this.safeString(params, 'positionSide');
this.checkRequiredArgument('setLeverage', positionSide, 'positionSide', ['LONG', 'SHORT']);
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
'margin': amount,
'type': addOrReduce,
'positionSide': positionSide,
};
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('modifyMarginHelper', market, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.privateInversePostFutureUserV1PositionMargin(this.extend(request, params));
}
else {
response = await this.privateLinearPostFutureUserV1PositionMargin(this.extend(request, params));
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": null
// }
//
return this.parseMarginModification(response, market);
}
parseMarginModification(data, market = undefined) {
return {
'info': data,
'type': undefined,
'amount': undefined,
'code': undefined,
'symbol': this.safeSymbol(undefined, market),
'status': undefined,
'marginMode': undefined,
'total': undefined,
'timestamp': undefined,
'datetime': undefined,
};
}
/**
* @method
* @name xt#fetchLeverageTiers
* @description retrieve information on the maximum leverage for different trade sizes
* @see https://doc.xt.com/#futures_quotesgetLeverageBrackets
* @param {string} [symbols] a list of unified market symbols
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a dictionary of [leverage tiers structures]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}
*/
async fetchLeverageTiers(symbols = undefined, params = {}) {
await this.loadMarkets();
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchLeverageTiers', undefined, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.publicInverseGetFutureMarketV1PublicLeverageBracketList(params);
}
else {
response = await this.publicLinearGetFutureMarketV1PublicLeverageBracketList(params);
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "symbol": "rad_usdt",
// "leverageBrackets": [
// {
// "symbol": "rad_usdt",
// "bracket": 1,
// "maxNominalValue": "5000",
// "maintMarginRate": "0.025",
// "startMarginRate": "0.05",
// "maxStartMarginRate": null,
// "maxLeverage": "20",
// "minLeverage": "1"
// },
// ]
// },
// ]
// }
//
const data = this.safeValue(response, 'result', []);
symbols = this.marketSymbols(symbols);
return this.parseLeverageTiers(data, symbols, 'symbol');
}
parseLeverageTiers(response, symbols = undefined, marketIdKey = undefined) {
//
// {
// "symbol": "rad_usdt",
// "leverageBrackets": [
// {
// "symbol": "rad_usdt",
// "bracket": 1,
// "maxNominalValue": "5000",
// "maintMarginRate": "0.025",
// "startMarginRate": "0.05",
// "maxStartMarginRate": null,
// "maxLeverage": "20",
// "minLeverage": "1"
// },
// ]
// }
//
const result = {};
for (let i = 0; i < response.length; i++) {
const entry = response[i];
const marketId = this.safeString(entry, 'symbol');
const market = this.safeMarket(marketId, undefined, '_', 'contract');
const symbol = this.safeSymbol(marketId, market);
if (symbols !== undefined) {
if (this.inArray(symbol, symbols)) {
result[symbol] = this.parseMarketLeverageTiers(entry, market);
}
}
else {
result[symbol] = this.parseMarketLeverageTiers(response[i], market);
}
}
return result;
}
/**
* @method
* @name xt#fetchMarketLeverageTiers
* @description retrieve information on the maximum leverage for different trade sizes of a single market
* @see https://doc.xt.com/#futures_quotesgetLeverageBracket
* @param {string} symbol unified market symbol
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a [leverage tiers structure]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}
*/
async fetchMarketLeverageTiers(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchMarketLeverageTiers', market, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.publicInverseGetFutureMarketV1PublicLeverageBracketDetail(this.extend(request, params));
}
else {
response = await this.publicLinearGetFutureMarketV1PublicLeverageBracketDetail(this.extend(request, params));
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "symbol": "btc_usdt",
// "leverageBrackets": [
// {
// "symbol": "btc_usdt",
// "bracket": 1,
// "maxNominalValue": "500000",
// "maintMarginRate": "0.004",
// "startMarginRate": "0.008",
// "maxStartMarginRate": null,
// "maxLeverage": "125",
// "minLeverage": "1"
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
return this.parseMarketLeverageTiers(data, market);
}
parseMarketLeverageTiers(info, market = undefined) {
//
// {
// "symbol": "rad_usdt",
// "leverageBrackets": [
// {
// "symbol": "rad_usdt",
// "bracket": 1,
// "maxNominalValue": "5000",
// "maintMarginRate": "0.025",
// "startMarginRate": "0.05",
// "maxStartMarginRate": null,
// "maxLeverage": "20",
// "minLeverage": "1"
// },
// ]
// }
//
const tiers = [];
const brackets = this.safeValue(info, 'leverageBrackets', []);
for (let i = 0; i < brackets.length; i++) {
const tier = brackets[i];
const marketId = this.safeString(info, 'symbol');
market = this.safeMarket(marketId, market, '_', 'contract');
tiers.push({
'tier': this.safeInteger(tier, 'bracket'),
'symbol': this.safeSymbol(marketId, market, '_', 'contract'),
'currency': market['settle'],
'minNotional': this.safeNumber(brackets[i - 1], 'maxNominalValue', 0),
'maxNotional': this.safeNumber(tier, 'maxNominalValue'),
'maintenanceMarginRate': this.safeNumber(tier, 'maintMarginRate'),
'maxLeverage': this.safeNumber(tier, 'maxLeverage'),
'info': tier,
});
}
return tiers;
}
/**
* @method
* @name xt#fetchFundingRateHistory
* @description fetches historical funding rates
* @see https://doc.xt.com/#futures_quotesgetFundingRateRecord
* @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] to fetch
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/en/latest/manual.html?#funding-rate-history-structure}
*/
async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
}
await this.loadMarkets();
const market = this.market(symbol);
if (!market['swap']) {
throw new errors.BadSymbol(this.id + ' fetchFundingRateHistory() supports swap contracts only');
}
const request = {
'symbol': market['id'],
};
if (limit !== undefined) {
request['limit'] = limit;
}
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchFundingRateHistory', market, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.publicInverseGetFutureMarketV1PublicQFundingRateRecord(this.extend(request, params));
}
else {
response = await this.publicLinearGetFutureMarketV1PublicQFundingRateRecord(this.extend(request, params));
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "hasPrev": false,
// "hasNext": true,
// "items": [
// {
// "id": "210441653482221888",
// "symbol": "btc_usdt",
// "fundingRate": "0.000057",
// "createdTime": 1679875200000,
// "collectionInternal": 28800
// },
// ]
// }
// }
//
const result = this.safeValue(response, 'result', {});
const items = this.safeValue(result, 'items', []);
const rates = [];
for (let i = 0; i < items.length; i++) {
const entry = items[i];
const marketId = this.safeString(entry, 'symbol');
const symbolInner = this.safeSymbol(marketId, market);
const timestamp = this.safeInteger(entry, 'createdTime');
rates.push({
'info': entry,
'symbol': symbolInner,
'fundingRate': this.safeNumber(entry, 'fundingRate'),
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
});
}
const sorted = this.sortBy(rates, 'timestamp');
return this.filterBySymbolSinceLimit(sorted, market['symbol'], since, limit);
}
/**
* @method
* @name xt#fetchFundingInterval
* @description fetch the current funding rate interval
* @see https://doc.xt.com/#futures_quotesgetFundingRate
* @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 xt#fetchFundingRate
* @description fetch the current funding rate
* @see https://doc.xt.com/#futures_quotesgetFundingRate
* @param {string} symbol unified market symbol
* @param {object} params extra parameters specific to the xt 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);
if (!market['swap']) {
throw new errors.BadSymbol(this.id + ' fetchFundingRate() supports swap contracts only');
}
const request = {
'symbol': market['id'],
};
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchFundingRate', market, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.publicInverseGetFutureMarketV1PublicQFundingRate(this.extend(request, params));
}
else {
response = await this.publicLinearGetFutureMarketV1PublicQFundingRate(this.extend(request, params));
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "symbol": "btc_usdt",
// "fundingRate": "0.000086",
// "nextCollectionTime": 1680307200000,
// "collectionInternal": 8
// }
// }
//
const result = this.safeValue(response, 'result', {});
return this.parseFundingRate(result, market);
}
parseFundingRate(contract, market = undefined) {
//
// {
// "symbol": "btc_usdt",
// "fundingRate": "0.000086",
// "nextCollectionTime": 1680307200000,
// "collectionInternal": 8
// }
//
const marketId = this.safeString(contract, 'symbol');
const symbol = this.safeSymbol(marketId, market, '_', 'swap');
const timestamp = this.safeInteger(contract, 'nextCollectionTime');
let interval = this.safeString(contract, 'collectionInternal');
if (interval !== undefined) {
interval = interval + 'h';
}
return {
'info': contract,
'symbol': symbol,
'markPrice': undefined,
'indexPrice': undefined,
'interestRate': undefined,
'estimatedSettlePrice': undefined,
'timestamp': undefined,
'datetime': undefined,
'fundingRate': this.safeNumber(contract, 'fundingRate'),
'fundingTimestamp': timestamp,
'fundingDatetime': this.iso8601(timestamp),
'nextFundingRate': undefined,
'nextFundingTimestamp': undefined,
'nextFundingDatetime': undefined,
'previousFundingRate': undefined,
'previousFundingTimestamp': undefined,
'previousFundingDatetime': undefined,
'interval': interval,
};
}
/**
* @method
* @name xt#fetchFundingHistory
* @description fetch the funding history
* @see https://doc.xt.com/#futures_usergetFunding
* @param {string} symbol unified market symbol
* @param {int} [since] the starting timestamp in milliseconds
* @param {int} [limit] the number of entries to return
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object[]} a list of [funding history structures]{@link https://docs.ccxt.com/#/?id=funding-history-structure}
*/
async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
if (!market['swap']) {
throw new errors.BadSymbol(this.id + ' fetchFundingHistory() supports swap contracts only');
}
const request = {
'symbol': market['id'],
};
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
request['limit'] = limit;
}
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchFundingHistory', market, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.privateInverseGetFutureUserV1BalanceFundingRateList(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureUserV1BalanceFundingRateList(this.extend(request, params));
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": {
// "hasPrev": false,
// "hasNext": false,
// "items": [
// {
// "id": "210804044057280512",
// "symbol": "btc_usdt",
// "cast": "-0.0013",
// "coin": "usdt",
// "positionSide": "SHORT",
// "createdTime": 1679961600653
// },
// ]
// }
// }
//
const data = this.safeValue(response, 'result', {});
const items = this.safeValue(data, 'items', []);
const result = [];
for (let i = 0; i < items.length; i++) {
const entry = items[i];
result.push(this.parseFundingHistory(entry, market));
}
const sorted = this.sortBy(result, 'timestamp');
return this.filterBySinceLimit(sorted, since, limit);
}
parseFundingHistory(contract, market = undefined) {
//
// {
// "id": "210804044057280512",
// "symbol": "btc_usdt",
// "cast": "-0.0013",
// "coin": "usdt",
// "positionSide": "SHORT",
// "createdTime": 1679961600653
// }
//
const marketId = this.safeString(contract, 'symbol');
const symbol = this.safeSymbol(marketId, market, '_', 'swap');
const currencyId = this.safeString(contract, 'coin');
const code = this.safeCurrencyCode(currencyId);
const timestamp = this.safeInteger(contract, 'createdTime');
return {
'info': contract,
'symbol': symbol,
'code': code,
'timestamp': timestamp,
'datetime': this.iso8601(timestamp),
'id': this.safeString(contract, 'id'),
'amount': this.safeNumber(contract, 'cast'),
};
}
/**
* @method
* @name xt#fetchPosition
* @description fetch data on a single open contract trade position
* @see https://doc.xt.com/#futures_usergetPosition
* @param {string} symbol unified market symbol of the market the position is held in
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
*/
async fetchPosition(symbol, params = {}) {
await this.loadMarkets();
const market = this.market(symbol);
const request = {
'symbol': market['id'],
};
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchPosition', market, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.privateInverseGetFutureUserV1PositionList(this.extend(request, params));
}
else {
response = await this.privateLinearGetFutureUserV1PositionList(this.extend(request, params));
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "symbol": "btc_usdt",
// "positionType": "ISOLATED",
// "positionSide": "SHORT",
// "contractType": "PERPETUAL",
// "positionSize": "10",
// "closeOrderSize": "0",
// "availableCloseSize": "10",
// "entryPrice": "27060",
// "openOrderSize": "0",
// "isolatedMargin": "1.0824",
// "openOrderMarginFrozen": "0",
// "realizedProfit": "-0.00130138",
// "autoMargin": false,
// "leverage": 25
// },
// ]
// }
//
const positions = this.safeValue(response, 'result', []);
for (let i = 0; i < positions.length; i++) {
const entry = positions[i];
const marketId = this.safeString(entry, 'symbol');
const marketInner = this.safeMarket(marketId, undefined, undefined, 'contract');
const positionSize = this.safeString(entry, 'positionSize');
if (positionSize !== '0') {
return this.parsePosition(entry, marketInner);
}
}
return undefined;
}
/**
* @method
* @name xt#fetchPositions
* @description fetch all open positions
* @see https://doc.xt.com/#futures_usergetPosition
* @param {string} [symbols] list of unified market symbols, not supported with xt
* @param {object} params extra parameters specific to the xt api endpoint
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
*/
async fetchPositions(symbols = undefined, params = {}) {
await this.loadMarkets();
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('fetchPositions', undefined, params);
let response = undefined;
if (subType === 'inverse') {
response = await this.privateInverseGetFutureUserV1PositionList(params);
}
else {
response = await this.privateLinearGetFutureUserV1PositionList(params);
}
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": [
// {
// "symbol": "btc_usdt",
// "positionType": "ISOLATED",
// "positionSide": "SHORT",
// "contractType": "PERPETUAL",
// "positionSize": "10",
// "closeOrderSize": "0",
// "availableCloseSize": "10",
// "entryPrice": "27060",
// "openOrderSize": "0",
// "isolatedMargin": "1.0824",
// "openOrderMarginFrozen": "0",
// "realizedProfit": "-0.00130138",
// "autoMargin": false,
// "leverage": 25
// },
// ]
// }
//
const positions = this.safeValue(response, 'result', []);
const result = [];
for (let i = 0; i < positions.length; i++) {
const entry = positions[i];
const marketId = this.safeString(entry, 'symbol');
const marketInner = this.safeMarket(marketId, undefined, undefined, 'contract');
result.push(this.parsePosition(entry, marketInner));
}
return this.filterByArrayPositions(result, 'symbol', symbols, false);
}
parsePosition(position, market = undefined) {
//
// {
// "symbol": "btc_usdt",
// "positionType": "ISOLATED",
// "positionSide": "SHORT",
// "contractType": "PERPETUAL",
// "positionSize": "10",
// "closeOrderSize": "0",
// "availableCloseSize": "10",
// "entryPrice": "27060",
// "openOrderSize": "0",
// "isolatedMargin": "1.0824",
// "openOrderMarginFrozen": "0",
// "realizedProfit": "-0.00130138",
// "autoMargin": false,
// "leverage": 25
// }
//
const marketId = this.safeString(position, 'symbol');
market = this.safeMarket(marketId, market, undefined, 'contract');
const symbol = this.safeSymbol(marketId, market, undefined, 'contract');
const positionType = this.safeString(position, 'positionType');
const marginMode = (positionType === 'CROSSED') ? 'cross' : 'isolated';
const collateral = this.safeNumber(position, 'isolatedMargin');
return this.safePosition({
'info': position,
'id': undefined,
'symbol': symbol,
'timestamp': undefined,
'datetime': undefined,
'hedged': undefined,
'side': this.safeStringLower(position, 'positionSide'),
'contracts': this.safeNumber(position, 'positionSize'),
'contractSize': market['contractSize'],
'entryPrice': this.safeNumber(position, 'entryPrice'),
'markPrice': undefined,
'notional': undefined,
'leverage': this.safeInteger(position, 'leverage'),
'collateral': collateral,
'initialMargin': collateral,
'maintenanceMargin': undefined,
'initialMarginPercentage': undefined,
'maintenanceMarginPercentage': undefined,
'unrealizedPnl': undefined,
'liquidationPrice': undefined,
'marginMode': marginMode,
'percentage': undefined,
'marginRatio': undefined,
});
}
/**
* @method
* @name xt#transfer
* @description transfer currency internally between wallets on the same account
* @see https://doc.xt.com/#transfersubTransferPost
* @param {string} code unified currency code
* @param {float} amount amount to transfer
* @param {string} fromAccount account to transfer from - spot, swap, leverage, finance
* @param {string} toAccount account to transfer to - spot, swap, leverage, finance
* @param {object} params extra parameters specific to the whitebit api endpoint
* @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
*/
async transfer(code, amount, fromAccount, toAccount, params = {}) {
await this.loadMarkets();
const currency = this.currency(code);
const accountsByType = this.safeValue(this.options, 'accountsById');
const fromAccountId = this.safeString(accountsByType, fromAccount, fromAccount);
const toAccountId = this.safeString(accountsByType, toAccount, toAccount);
const amountString = this.currencyToPrecision(code, amount);
const request = {
'bizId': this.uuid(),
'currency': currency['id'],
'amount': amountString,
'from': fromAccountId,
'to': toAccountId,
};
const response = await this.privateSpotPostBalanceTransfer(this.extend(request, params));
//
// {
// info: { rc: '0', mc: 'SUCCESS', ma: [], result: '226971333791398656' },
// id: '226971333791398656',
// timestamp: undefined,
// datetime: undefined,
// currency: undefined,
// amount: undefined,
// fromAccount: undefined,
// toAccount: undefined,
// status: undefined
// }
//
return this.parseTransfer(response, currency);
}
parseTransfer(transfer, currency = undefined) {
return {
'info': transfer,
'id': this.safeString(transfer, 'result'),
'timestamp': undefined,
'datetime': undefined,
'currency': undefined,
'amount': undefined,
'fromAccount': undefined,
'toAccount': undefined,
'status': undefined,
};
}
/**
* @method
* @name xt#setMarginMode
* @description set margin mode to 'cross' or 'isolated'
* @see https://doc.xt.com/#futures_userchangePositionType
* @param {string} marginMode 'cross' or 'isolated'
* @param {string} [symbol] required
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {string} [params.positionSide] *required* "long" or "short"
* @returns {object} response from the exchange
*/
async setMarginMode(marginMode, symbol = undefined, params = {}) {
if (symbol === undefined) {
throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires a symbol argument');
}
await this.loadMarkets();
const market = this.market(symbol);
if (market['spot']) {
throw new errors.BadSymbol(this.id + ' setMarginMode() supports contract markets only');
}
marginMode = marginMode.toLowerCase();
if (marginMode !== 'isolated' && marginMode !== 'cross') {
throw new errors.BadRequest(this.id + ' setMarginMode() marginMode argument should be isolated or cross');
}
if (marginMode === 'cross') {
marginMode = 'CROSSED';
}
else {
marginMode = 'ISOLATED';
}
const posSide = this.safeStringUpper(params, 'positionSide');
if (posSide === undefined) {
throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires a positionSide parameter, either "LONG" or "SHORT"');
}
const request = {
'positionType': marginMode,
'positionSide': posSide,
'symbol': market['id'],
};
const response = await this.privateLinearPostFutureUserV1PositionChangeType(this.extend(request, params));
//
// {
// "error": {
// "code": "",
// "msg": ""
// },
// "msgInfo": "",
// "result": {},
// "returnCode": 0
// }
//
return response; // unify return type
}
/**
* @method
* @name xt#editOrder
* @description cancels an order and places a new order
* @see https://doc.xt.com/#orderorderUpdate
* @see https://doc.xt.com/#futures_orderupdate
* @see https://doc.xt.com/#futures_entrustupdateProfit
* @param {string} id order id
* @param {string} symbol unified symbol of the market to create an order in
* @param {string} type 'market' or 'limit'
* @param {string} side 'buy' or 'sell'
* @param {float} amount how much of the currency you want to trade in units of the base currency
* @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
* @param {object} [params] extra parameters specific to the exchange API endpoint
* @param {float} [params.stopLoss] price to set a stop-loss on an open position
* @param {float} [params.takeProfit] price to set a take-profit on an open position
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
*/
async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
if (amount === undefined) {
throw new errors.ArgumentsRequired(this.id + ' editOrder() requires an amount argument');
}
await this.loadMarkets();
const market = this.market(symbol);
const request = {};
const stopLoss = this.safeNumber2(params, 'stopLoss', 'triggerStopPrice');
const takeProfit = this.safeNumber2(params, 'takeProfit', 'triggerProfitPrice');
params = this.omit(params, ['stopLoss', 'takeProfit']);
const isStopLoss = (stopLoss !== undefined);
const isTakeProfit = (takeProfit !== undefined);
if (isStopLoss || isTakeProfit) {
request['profitId'] = id;
}
else {
request['orderId'] = id;
request['price'] = this.priceToPrecision(symbol, price);
}
let response = undefined;
if (market['swap']) {
if (isStopLoss) {
request['triggerStopPrice'] = this.priceToPrecision(symbol, stopLoss);
}
else if (takeProfit !== undefined) {
request['triggerProfitPrice'] = this.priceToPrecision(symbol, takeProfit);
}
else {
request['origQty'] = this.amountToPrecision(symbol, amount);
}
let subType = undefined;
[subType, params] = this.handleSubTypeAndParams('editOrder', market, params);
if (subType === 'inverse') {
if (isStopLoss || isTakeProfit) {
response = await this.privateInversePostFutureTradeV1EntrustUpdateProfitStop(this.extend(request, params));
}
else {
response = await this.privateInversePostFutureTradeV1OrderUpdate(this.extend(request, params));
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": "483869474947826752"
// }
//
}
}
else {
if (isStopLoss || isTakeProfit) {
response = await this.privateLinearPostFutureTradeV1EntrustUpdateProfitStop(this.extend(request, params));
}
else {
response = await this.privateLinearPostFutureTradeV1OrderUpdate(this.extend(request, params));
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": "483869474947826752"
// }
//
}
}
}
else {
request['quantity'] = this.amountToPrecision(symbol, amount);
response = await this.privateSpotPutOrderOrderId(this.extend(request, params));
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {
// "orderId": "484203027161892224",
// "modifyId": "484203544105344000",
// "clientModifyId": null
// }
// }
//
}
const result = (market['swap']) ? response : this.safeDict(response, 'result', {});
return this.parseOrder(result, market);
}
handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
//
// spot: error
//
// {
// "rc": 1,
// "mc": "AUTH_103",
// "ma": [],
// "result": null
// }
//
// spot: success
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": []
// }
//
// swap and future: error
//
// {
// "returnCode": 1,
// "msgInfo": "failure",
// "error": {
// "code": "403",
// "msg": "invalid signature"
// },
// "result": null
// }
//
// swap and future: success
//
// {
// "returnCode": 0,
// "msgInfo": "success",
// "error": null,
// "result": null
// }
//
// other:
//
// {
// "rc": 0,
// "mc": "SUCCESS",
// "ma": [],
// "result": {}
// }
//
// {"returnCode":1,"msgInfo":"failure","error":{"code":"insufficient_balance","msg":"insufficient balance","args":[]},"result":null}
//
//
const status = this.safeStringUpper2(response, 'msgInfo', 'mc');
if (status !== undefined && status !== 'SUCCESS') {
const feedback = this.id + ' ' + body;
const error = this.safeValue(response, 'error', {});
const spotErrorCode = this.safeString(response, 'mc');
const errorCode = this.safeString(error, 'code', spotErrorCode);
const spotMessage = this.safeString(response, 'msgInfo');
const message = this.safeString(error, 'msg', spotMessage);
this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
throw new errors.ExchangeError(feedback);
}
return undefined;
}
sign(path, api = [], method = 'GET', params = {}, headers = undefined, body = undefined) {
const signed = api[0] === 'private';
const endpoint = api[1];
const request = '/' + this.implodeParams(path, params);
let payload = undefined;
if ((endpoint === 'spot') || (endpoint === 'user')) {
if (signed) {
payload = '/' + this.version + request;
}
else {
payload = '/' + this.version + '/public' + request;
}
}
else {
payload = request;
}
let url = this.urls['api'][endpoint] + payload;
const query = this.omit(params, this.extractParams(path));
const urlencoded = this.urlencode(this.keysort(query));
headers = {
'Content-Type': 'application/json',
};
if (signed) {
this.checkRequiredCredentials();
const defaultRecvWindow = this.safeString(this.options, 'recvWindow');
const recvWindow = this.safeString(query, 'recvWindow', defaultRecvWindow);
const timestamp = this.numberToString(this.nonce());
body = query;
if ((payload === '/v4/order') || (payload === '/future/trade/v1/order/create') || (payload === '/future/trade/v1/entrust/create-plan') || (payload === '/future/trade/v1/entrust/create-profit') || (payload === '/future/trade/v1/order/create-batch')) {
const id = 'CCXT';
if (payload.indexOf('future') > -1) {
body['clientMedia'] = id;
}
else {
body['media'] = id;
}
}
let isUndefinedBody = ((method === 'GET') || (path === 'order/{orderId}') || (path === 'ws-token'));
if ((method === 'PUT') && (endpoint === 'spot')) {
isUndefinedBody = false;
}
body = isUndefinedBody ? undefined : this.json(body);
let payloadString = undefined;
if ((endpoint === 'spot') || (endpoint === 'user')) {
payloadString = 'xt-validate-algorithms=HmacSHA256&xt-validate-appkey=' + this.apiKey + '&xt-validate-recvwindow=' + recvWindow + '&xt-validate-t' + 'imestamp=' + timestamp;
if (isUndefinedBody) {
if (urlencoded) {
url += '?' + urlencoded;
payloadString += '#' + method + '#' + payload + '#' + this.rawencode(this.keysort(query));
}
else {
payloadString += '#' + method + '#' + payload;
}
}
else {
payloadString += '#' + method + '#' + payload + '#' + body;
}
headers['xt-validate-algorithms'] = 'HmacSHA256';
headers['xt-validate-recvwindow'] = recvWindow;
}
else {
payloadString = 'xt-validate-appkey=' + this.apiKey + '&xt-validate-t' + 'imestamp=' + timestamp; // we can't glue timestamp, breaks in php
if (method === 'GET') {
if (urlencoded) {
url += '?' + urlencoded;
payloadString += '#' + payload + '#' + urlencoded;
}
else {
payloadString += '#' + payload;
}
}
else {
payloadString += '#' + payload + '#' + body;
}
}
const signature = this.hmac(this.encode(payloadString), this.encode(this.secret), sha256.sha256);
headers['xt-validate-appkey'] = this.apiKey;
headers['xt-validate-timestamp'] = timestamp;
headers['xt-validate-signature'] = signature;
}
else {
if (urlencoded) {
url += '?' + urlencoded;
}
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
}
module.exports = xt;