ccxt 4.4.21 → 4.4.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -111
- package/dist/ccxt.browser.min.js +2 -2
- package/dist/cjs/ccxt.js +6 -1
- package/dist/cjs/src/abstract/coincatch.js +9 -0
- package/dist/cjs/src/alpaca.js +1 -0
- package/dist/cjs/src/base/Exchange.js +21 -0
- package/dist/cjs/src/bigone.js +3 -0
- package/dist/cjs/src/binance.js +172 -44
- package/dist/cjs/src/bitfinex.js +4 -0
- package/dist/cjs/src/bitflyer.js +58 -0
- package/dist/cjs/src/bitget.js +77 -0
- package/dist/cjs/src/bitrue.js +3 -0
- package/dist/cjs/src/bybit.js +80 -2
- package/dist/cjs/src/cex.js +1307 -1381
- package/dist/cjs/src/coinbase.js +1 -1
- package/dist/cjs/src/coinbaseexchange.js +3 -0
- package/dist/cjs/src/coincatch.js +5370 -0
- package/dist/cjs/src/coinex.js +63 -1
- package/dist/cjs/src/cryptocom.js +1 -1
- package/dist/cjs/src/gate.js +103 -3
- package/dist/cjs/src/htx.js +1 -7
- package/dist/cjs/src/hyperliquid.js +10 -8
- package/dist/cjs/src/kucoin.js +27 -59
- package/dist/cjs/src/latoken.js +6 -0
- package/dist/cjs/src/mexc.js +1 -1
- package/dist/cjs/src/oceanex.js +2 -0
- package/dist/cjs/src/okcoin.js +1 -0
- package/dist/cjs/src/okx.js +74 -0
- package/dist/cjs/src/poloniex.js +5 -0
- package/dist/cjs/src/pro/coincatch.js +1554 -0
- package/js/ccxt.d.ts +9 -3
- package/js/ccxt.js +6 -2
- package/js/src/abstract/binance.d.ts +21 -0
- package/js/src/abstract/binancecoinm.d.ts +21 -0
- package/js/src/abstract/binanceus.d.ts +21 -0
- package/js/src/abstract/binanceusdm.d.ts +21 -0
- package/js/src/abstract/bitflyer.d.ts +1 -0
- package/js/src/abstract/bitget.d.ts +3 -0
- package/js/src/abstract/cex.d.ts +28 -29
- package/js/src/abstract/coincatch.d.ts +97 -0
- package/js/src/abstract/coincatch.js +11 -0
- package/js/src/abstract/gate.d.ts +5 -0
- package/js/src/abstract/gateio.d.ts +5 -0
- package/js/src/abstract/kucoin.d.ts +1 -0
- package/js/src/abstract/kucoinfutures.d.ts +1 -0
- package/js/src/abstract/okx.d.ts +1 -0
- package/js/src/alpaca.js +1 -0
- package/js/src/base/Exchange.d.ts +8 -2
- package/js/src/base/Exchange.js +21 -0
- package/js/src/base/types.d.ts +8 -0
- package/js/src/bigone.js +3 -0
- package/js/src/binance.d.ts +3 -1
- package/js/src/binance.js +172 -44
- package/js/src/bitfinex.js +4 -0
- package/js/src/bitflyer.d.ts +3 -1
- package/js/src/bitflyer.js +58 -0
- package/js/src/bitget.d.ts +3 -1
- package/js/src/bitget.js +77 -0
- package/js/src/bitrue.js +3 -0
- package/js/src/bybit.d.ts +3 -1
- package/js/src/bybit.js +80 -2
- package/js/src/cex.d.ts +34 -20
- package/js/src/cex.js +1308 -1382
- package/js/src/coinbase.js +1 -1
- package/js/src/coinbaseexchange.js +3 -0
- package/js/src/coincatch.d.ts +130 -0
- package/js/src/coincatch.js +5371 -0
- package/js/src/coinex.d.ts +1 -0
- package/js/src/coinex.js +63 -1
- package/js/src/cryptocom.js +1 -1
- package/js/src/gate.d.ts +2 -0
- package/js/src/gate.js +103 -3
- package/js/src/htx.js +1 -7
- package/js/src/hyperliquid.js +10 -8
- package/js/src/kucoin.d.ts +0 -1
- package/js/src/kucoin.js +27 -59
- package/js/src/latoken.js +6 -0
- package/js/src/mexc.js +1 -1
- package/js/src/oceanex.js +2 -0
- package/js/src/okcoin.js +1 -0
- package/js/src/okx.d.ts +3 -1
- package/js/src/okx.js +74 -0
- package/js/src/poloniex.js +5 -0
- package/js/src/pro/coincatch.d.ts +57 -0
- package/js/src/pro/coincatch.js +1555 -0
- package/package.json +1 -1
package/js/src/cex.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
8
|
import Exchange from './abstract/cex.js';
|
|
9
|
-
import { ExchangeError, ArgumentsRequired,
|
|
9
|
+
import { ExchangeError, ArgumentsRequired, NullResponse, PermissionDenied, InsufficientFunds, BadRequest } from './base/errors.js';
|
|
10
10
|
import { Precise } from './base/Precise.js';
|
|
11
11
|
import { TICK_SIZE } from './base/functions/number.js';
|
|
12
12
|
import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
|
|
@@ -21,7 +21,7 @@ export default class cex extends Exchange {
|
|
|
21
21
|
'id': 'cex',
|
|
22
22
|
'name': 'CEX.IO',
|
|
23
23
|
'countries': ['GB', 'EU', 'CY', 'RU'],
|
|
24
|
-
'rateLimit':
|
|
24
|
+
'rateLimit': 1667,
|
|
25
25
|
'pro': true,
|
|
26
26
|
'has': {
|
|
27
27
|
'CORS': undefined,
|
|
@@ -30,152 +30,82 @@ export default class cex extends Exchange {
|
|
|
30
30
|
'swap': false,
|
|
31
31
|
'future': false,
|
|
32
32
|
'option': false,
|
|
33
|
-
'addMargin': false,
|
|
34
33
|
'cancelAllOrders': true,
|
|
35
34
|
'cancelOrder': true,
|
|
36
|
-
'cancelOrders': false,
|
|
37
|
-
'createDepositAddress': false,
|
|
38
|
-
'createMarketBuyOrderWithCost': true,
|
|
39
|
-
'createMarketOrderWithCost': false,
|
|
40
|
-
'createMarketSellOrderWithCost': false,
|
|
41
35
|
'createOrder': true,
|
|
42
|
-
'
|
|
43
|
-
'createStopMarketOrder': false,
|
|
44
|
-
'createStopOrder': false,
|
|
45
|
-
'editOrder': true,
|
|
36
|
+
'fetchAccounts': true,
|
|
46
37
|
'fetchBalance': true,
|
|
47
38
|
'fetchClosedOrders': true,
|
|
48
39
|
'fetchCurrencies': true,
|
|
49
|
-
'fetchDeposit': false,
|
|
50
40
|
'fetchDepositAddress': true,
|
|
51
|
-
'
|
|
52
|
-
'fetchDepositAddressesByNetwork': false,
|
|
53
|
-
'fetchDeposits': false,
|
|
54
|
-
'fetchDepositsWithdrawals': false,
|
|
41
|
+
'fetchDepositsWithdrawals': true,
|
|
55
42
|
'fetchFundingHistory': false,
|
|
56
43
|
'fetchFundingRate': false,
|
|
57
44
|
'fetchFundingRateHistory': false,
|
|
58
45
|
'fetchFundingRates': false,
|
|
59
|
-
'
|
|
60
|
-
'fetchMarginMode': false,
|
|
46
|
+
'fetchLedger': true,
|
|
61
47
|
'fetchMarkets': true,
|
|
62
|
-
'fetchMarkOHLCV': false,
|
|
63
48
|
'fetchOHLCV': true,
|
|
64
|
-
'fetchOpenInterestHistory': false,
|
|
65
49
|
'fetchOpenOrders': true,
|
|
66
|
-
'fetchOrder': true,
|
|
67
50
|
'fetchOrderBook': true,
|
|
68
|
-
'fetchOrders': true,
|
|
69
|
-
'fetchPosition': false,
|
|
70
|
-
'fetchPositionHistory': false,
|
|
71
|
-
'fetchPositionMode': false,
|
|
72
|
-
'fetchPositions': false,
|
|
73
|
-
'fetchPositionsForSymbol': false,
|
|
74
|
-
'fetchPositionsHistory': false,
|
|
75
|
-
'fetchPositionsRisk': false,
|
|
76
|
-
'fetchPremiumIndexOHLCV': false,
|
|
77
51
|
'fetchTicker': true,
|
|
78
52
|
'fetchTickers': true,
|
|
53
|
+
'fetchTime': true,
|
|
79
54
|
'fetchTrades': true,
|
|
80
|
-
'fetchTradingFee': false,
|
|
81
55
|
'fetchTradingFees': true,
|
|
82
|
-
'
|
|
83
|
-
'fetchTransfer': false,
|
|
84
|
-
'fetchTransfers': false,
|
|
85
|
-
'fetchWithdrawal': false,
|
|
86
|
-
'fetchWithdrawals': false,
|
|
87
|
-
'fetchWithdrawalWhitelist': false,
|
|
88
|
-
'reduceMargin': false,
|
|
89
|
-
'setLeverage': false,
|
|
90
|
-
'setMargin': false,
|
|
91
|
-
'setMarginMode': false,
|
|
92
|
-
'transfer': false,
|
|
93
|
-
'withdraw': false,
|
|
94
|
-
},
|
|
95
|
-
'timeframes': {
|
|
96
|
-
'1m': '1m',
|
|
97
|
-
'1h': '1h',
|
|
98
|
-
'1d': '1d',
|
|
56
|
+
'transfer': true,
|
|
99
57
|
},
|
|
100
58
|
'urls': {
|
|
101
59
|
'logo': 'https://user-images.githubusercontent.com/1294454/27766442-8ddc33b0-5ed8-11e7-8b98-f786aef0f3c9.jpg',
|
|
102
60
|
'api': {
|
|
103
|
-
'
|
|
61
|
+
'public': 'https://trade.cex.io/api/spot/rest-public',
|
|
62
|
+
'private': 'https://trade.cex.io/api/spot/rest',
|
|
104
63
|
},
|
|
105
64
|
'www': 'https://cex.io',
|
|
106
|
-
'doc': 'https://cex.io/
|
|
65
|
+
'doc': 'https://trade.cex.io/docs/',
|
|
107
66
|
'fees': [
|
|
108
67
|
'https://cex.io/fee-schedule',
|
|
109
68
|
'https://cex.io/limits-commissions',
|
|
110
69
|
],
|
|
111
70
|
'referral': 'https://cex.io/r/0/up105393824/0/',
|
|
112
71
|
},
|
|
113
|
-
'requiredCredentials': {
|
|
114
|
-
'apiKey': true,
|
|
115
|
-
'secret': true,
|
|
116
|
-
'uid': true,
|
|
117
|
-
},
|
|
118
72
|
'api': {
|
|
119
73
|
'public': {
|
|
120
|
-
'get':
|
|
121
|
-
|
|
122
|
-
'
|
|
123
|
-
'
|
|
124
|
-
'
|
|
125
|
-
'
|
|
126
|
-
'
|
|
127
|
-
'
|
|
128
|
-
'
|
|
129
|
-
'
|
|
130
|
-
|
|
131
|
-
'post': [
|
|
132
|
-
'convert/{pair}',
|
|
133
|
-
'price_stats/{pair}',
|
|
134
|
-
],
|
|
74
|
+
'get': {},
|
|
75
|
+
'post': {
|
|
76
|
+
'get_server_time': 1,
|
|
77
|
+
'get_pairs_info': 1,
|
|
78
|
+
'get_currencies_info': 1,
|
|
79
|
+
'get_processing_info': 10,
|
|
80
|
+
'get_ticker': 1,
|
|
81
|
+
'get_trade_history': 1,
|
|
82
|
+
'get_order_book': 1,
|
|
83
|
+
'get_candles': 1,
|
|
84
|
+
},
|
|
135
85
|
},
|
|
136
86
|
'private': {
|
|
137
|
-
'
|
|
138
|
-
|
|
139
|
-
'
|
|
140
|
-
'
|
|
141
|
-
'
|
|
142
|
-
'
|
|
143
|
-
'
|
|
144
|
-
'
|
|
145
|
-
'
|
|
146
|
-
'
|
|
147
|
-
'
|
|
148
|
-
'
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
'
|
|
152
|
-
'
|
|
153
|
-
'
|
|
154
|
-
'
|
|
155
|
-
'
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
'fees': {
|
|
160
|
-
'trading': {
|
|
161
|
-
'maker': this.parseNumber('0.0016'),
|
|
162
|
-
'taker': this.parseNumber('0.0025'),
|
|
163
|
-
},
|
|
164
|
-
'funding': {
|
|
165
|
-
'withdraw': {},
|
|
166
|
-
'deposit': {
|
|
167
|
-
// 'USD': amount => amount * 0.035 + 0.25,
|
|
168
|
-
// 'EUR': amount => amount * 0.035 + 0.24,
|
|
169
|
-
// 'RUB': amount => amount * 0.05 + 15.57,
|
|
170
|
-
// 'GBP': amount => amount * 0.035 + 0.2,
|
|
171
|
-
'BTC': 0.0,
|
|
172
|
-
'ETH': 0.0,
|
|
173
|
-
'BCH': 0.0,
|
|
174
|
-
'DASH': 0.0,
|
|
175
|
-
'BTG': 0.0,
|
|
176
|
-
'ZEC': 0.0,
|
|
177
|
-
'XRP': 0.0,
|
|
178
|
-
'XLM': 0.0,
|
|
87
|
+
'get': {},
|
|
88
|
+
'post': {
|
|
89
|
+
'get_my_current_fee': 5,
|
|
90
|
+
'get_fee_strategy': 1,
|
|
91
|
+
'get_my_volume': 5,
|
|
92
|
+
'do_create_account': 1,
|
|
93
|
+
'get_my_account_status_v3': 5,
|
|
94
|
+
'get_my_wallet_balance': 5,
|
|
95
|
+
'get_my_orders': 5,
|
|
96
|
+
'do_my_new_order': 1,
|
|
97
|
+
'do_cancel_my_order': 1,
|
|
98
|
+
'do_cancel_all_orders': 5,
|
|
99
|
+
'get_order_book': 1,
|
|
100
|
+
'get_candles': 1,
|
|
101
|
+
'get_trade_history': 1,
|
|
102
|
+
'get_my_transaction_history': 1,
|
|
103
|
+
'get_my_funding_history': 5,
|
|
104
|
+
'do_my_internal_transfer': 1,
|
|
105
|
+
'get_processing_info': 10,
|
|
106
|
+
'get_deposit_address': 5,
|
|
107
|
+
'do_deposit_funds_from_wallet': 1,
|
|
108
|
+
'do_withdrawal_funds_to_wallet': 1,
|
|
179
109
|
},
|
|
180
110
|
},
|
|
181
111
|
},
|
|
@@ -183,1520 +113,1516 @@ export default class cex extends Exchange {
|
|
|
183
113
|
'exceptions': {
|
|
184
114
|
'exact': {},
|
|
185
115
|
'broad': {
|
|
116
|
+
'You have negative balance on following accounts': InsufficientFunds,
|
|
117
|
+
'Mandatory parameter side should be one of BUY,SELL': BadRequest,
|
|
118
|
+
'API orders from Main account are not allowed': BadRequest,
|
|
119
|
+
'check failed': BadRequest,
|
|
186
120
|
'Insufficient funds': InsufficientFunds,
|
|
187
|
-
'
|
|
188
|
-
'
|
|
189
|
-
'Order not found': OrderNotFound,
|
|
190
|
-
'limit exceeded': RateLimitExceeded,
|
|
191
|
-
'Invalid API key': AuthenticationError,
|
|
192
|
-
'There was an error while placing your order': InvalidOrder,
|
|
193
|
-
'Sorry, too many clients already': DDoSProtection,
|
|
194
|
-
'Invalid Symbols Pair': BadSymbol,
|
|
195
|
-
'Wrong currency pair': BadSymbol, // {"error":"There was an error while placing your order: Wrong currency pair.","safe":true}
|
|
121
|
+
'Get deposit address for main account is not allowed': PermissionDenied,
|
|
122
|
+
'Market Trigger orders are not allowed': BadRequest, // for some reason, triggerPrice does not work for market orders
|
|
196
123
|
},
|
|
197
124
|
},
|
|
125
|
+
'timeframes': {
|
|
126
|
+
'1m': '1m',
|
|
127
|
+
'5m': '5m',
|
|
128
|
+
'15m': '15m',
|
|
129
|
+
'30m': '30m',
|
|
130
|
+
'1h': '1h',
|
|
131
|
+
'2h': '2h',
|
|
132
|
+
'4h': '4h',
|
|
133
|
+
'1d': '1d',
|
|
134
|
+
},
|
|
198
135
|
'options': {
|
|
199
|
-
'fetchOHLCVWarning': true,
|
|
200
|
-
'createMarketBuyOrderRequiresPrice': true,
|
|
201
|
-
'order': {
|
|
202
|
-
'status': {
|
|
203
|
-
'c': 'canceled',
|
|
204
|
-
'd': 'closed',
|
|
205
|
-
'cd': 'canceled',
|
|
206
|
-
'a': 'open',
|
|
207
|
-
},
|
|
208
|
-
},
|
|
209
|
-
'defaultNetwork': 'ERC20',
|
|
210
|
-
'defaultNetworks': {
|
|
211
|
-
'USDT': 'TRC20',
|
|
212
|
-
},
|
|
213
136
|
'networks': {
|
|
214
|
-
'
|
|
215
|
-
'
|
|
216
|
-
'
|
|
217
|
-
'
|
|
137
|
+
'BTC': 'bitcoin',
|
|
138
|
+
'ERC20': 'ERC20',
|
|
139
|
+
'BSC20': 'binancesmartchain',
|
|
140
|
+
'DOGE': 'dogecoin',
|
|
141
|
+
'ALGO': 'algorand',
|
|
142
|
+
'XLM': 'stellar',
|
|
143
|
+
'ATOM': 'cosmos',
|
|
144
|
+
'LTC': 'litecoin',
|
|
145
|
+
'XRP': 'ripple',
|
|
146
|
+
'FTM': 'fantom',
|
|
147
|
+
'MINA': 'mina',
|
|
148
|
+
'THETA': 'theta',
|
|
149
|
+
'XTZ': 'tezos',
|
|
150
|
+
'TIA': 'celestia',
|
|
151
|
+
'CRONOS': 'cronos',
|
|
152
|
+
'MATIC': 'polygon',
|
|
153
|
+
'TON': 'ton',
|
|
154
|
+
'TRC20': 'tron',
|
|
155
|
+
'SOLANA': 'solana',
|
|
156
|
+
'SGB': 'songbird',
|
|
157
|
+
'DYDX': 'dydx',
|
|
158
|
+
'DASH': 'dash',
|
|
159
|
+
'ZIL': 'zilliqa',
|
|
160
|
+
'EOS': 'eos',
|
|
161
|
+
'AVALANCHEC': 'avalanche',
|
|
162
|
+
'ETHPOW': 'ethereumpow',
|
|
163
|
+
'NEAR': 'near',
|
|
164
|
+
'ARB': 'arbitrum',
|
|
165
|
+
'DOT': 'polkadot',
|
|
166
|
+
'OPT': 'optimism',
|
|
167
|
+
'INJ': 'injective',
|
|
168
|
+
'ADA': 'cardano',
|
|
169
|
+
'ONT': 'ontology',
|
|
170
|
+
'ICP': 'icp',
|
|
171
|
+
'KAVA': 'kava',
|
|
172
|
+
'KSM': 'kusama',
|
|
173
|
+
'SEI': 'sei',
|
|
174
|
+
// 'OSM': 'osmosis',
|
|
175
|
+
'NEO': 'neo',
|
|
176
|
+
'NEO3': 'neo3',
|
|
177
|
+
// 'TERRAOLD': 'terra', // tbd
|
|
178
|
+
// 'TERRA': 'terra2', // tbd
|
|
179
|
+
// 'EVER': 'everscale', // tbd
|
|
180
|
+
'XDC': 'xdc',
|
|
218
181
|
},
|
|
219
182
|
},
|
|
220
183
|
});
|
|
221
184
|
}
|
|
222
|
-
async fetchCurrenciesFromCache(params = {}) {
|
|
223
|
-
// this method is now redundant
|
|
224
|
-
// currencies are now fetched before markets
|
|
225
|
-
const options = this.safeValue(this.options, 'fetchCurrencies', {});
|
|
226
|
-
const timestamp = this.safeInteger(options, 'timestamp');
|
|
227
|
-
const expires = this.safeInteger(options, 'expires', 1000);
|
|
228
|
-
const now = this.milliseconds();
|
|
229
|
-
if ((timestamp === undefined) || ((now - timestamp) > expires)) {
|
|
230
|
-
const response = await this.publicGetCurrencyProfile(params);
|
|
231
|
-
this.options['fetchCurrencies'] = this.extend(options, {
|
|
232
|
-
'response': response,
|
|
233
|
-
'timestamp': now,
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
return this.safeValue(this.options['fetchCurrencies'], 'response');
|
|
237
|
-
}
|
|
238
185
|
async fetchCurrencies(params = {}) {
|
|
239
186
|
/**
|
|
240
187
|
* @method
|
|
241
188
|
* @name cex#fetchCurrencies
|
|
242
189
|
* @description fetches all available currencies on an exchange
|
|
243
|
-
* @
|
|
244
|
-
* @
|
|
190
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-currencies-info
|
|
191
|
+
* @param {dict} [params] extra parameters specific to the exchange API endpoint
|
|
192
|
+
* @returns {dict} an associative dictionary of currencies
|
|
245
193
|
*/
|
|
246
|
-
const
|
|
247
|
-
this.
|
|
248
|
-
'timestamp': this.milliseconds(),
|
|
249
|
-
'response': response,
|
|
250
|
-
};
|
|
194
|
+
const promises = [];
|
|
195
|
+
promises.push(this.publicPostGetCurrenciesInfo(params));
|
|
251
196
|
//
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
//
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
//
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
//
|
|
264
|
-
// "scale":0,
|
|
265
|
-
// "minimumCurrencyAmount":"0.00000001",
|
|
266
|
-
// "minimalWithdrawalAmount":-1
|
|
267
|
-
// },
|
|
268
|
-
// {
|
|
269
|
-
// "code":"BTC",
|
|
270
|
-
// "contract":false,
|
|
271
|
-
// "commodity":false,
|
|
272
|
-
// "fiat":false,
|
|
273
|
-
// "description":"",
|
|
274
|
-
// "precision":8,
|
|
275
|
-
// "scale":0,
|
|
276
|
-
// "minimumCurrencyAmount":"0.00000001",
|
|
277
|
-
// "minimalWithdrawalAmount":0.002
|
|
278
|
-
// },
|
|
279
|
-
// {
|
|
280
|
-
// "code":"ETH",
|
|
281
|
-
// "contract":false,
|
|
282
|
-
// "commodity":false,
|
|
283
|
-
// "fiat":false,
|
|
284
|
-
// "description":"",
|
|
285
|
-
// "precision":8,
|
|
286
|
-
// "scale":2,
|
|
287
|
-
// "minimumCurrencyAmount":"0.00000100",
|
|
288
|
-
// "minimalWithdrawalAmount":0.01
|
|
289
|
-
// }
|
|
290
|
-
// ],
|
|
291
|
-
// "pairs":[
|
|
292
|
-
// {
|
|
293
|
-
// "symbol1":"BTC",
|
|
294
|
-
// "symbol2":"USD",
|
|
295
|
-
// "pricePrecision":1,
|
|
296
|
-
// "priceScale":"/1000000",
|
|
297
|
-
// "minLotSize":0.002,
|
|
298
|
-
// "minLotSizeS2":20
|
|
299
|
-
// },
|
|
300
|
-
// {
|
|
301
|
-
// "symbol1":"ETH",
|
|
302
|
-
// "symbol2":"USD",
|
|
303
|
-
// "pricePrecision":2,
|
|
304
|
-
// "priceScale":"/10000",
|
|
305
|
-
// "minLotSize":0.1,
|
|
306
|
-
// "minLotSizeS2":20
|
|
307
|
-
// }
|
|
308
|
-
// ]
|
|
309
|
-
// }
|
|
310
|
-
// }
|
|
197
|
+
// {
|
|
198
|
+
// "ok": "ok",
|
|
199
|
+
// "data": [
|
|
200
|
+
// {
|
|
201
|
+
// "currency": "ZAP",
|
|
202
|
+
// "fiat": false,
|
|
203
|
+
// "precision": "8",
|
|
204
|
+
// "walletPrecision": "6",
|
|
205
|
+
// "walletDeposit": true,
|
|
206
|
+
// "walletWithdrawal": true
|
|
207
|
+
// },
|
|
208
|
+
// ...
|
|
311
209
|
//
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
210
|
+
promises.push(this.publicPostGetProcessingInfo(params));
|
|
211
|
+
//
|
|
212
|
+
// {
|
|
213
|
+
// "ok": "ok",
|
|
214
|
+
// "data": {
|
|
215
|
+
// "ADA": {
|
|
216
|
+
// "name": "Cardano",
|
|
217
|
+
// "blockchains": {
|
|
218
|
+
// "cardano": {
|
|
219
|
+
// "type": "coin",
|
|
220
|
+
// "deposit": "enabled",
|
|
221
|
+
// "minDeposit": "1",
|
|
222
|
+
// "withdrawal": "enabled",
|
|
223
|
+
// "minWithdrawal": "5",
|
|
224
|
+
// "withdrawalFee": "1",
|
|
225
|
+
// "withdrawalFeePercent": "0",
|
|
226
|
+
// "depositConfirmations": "15"
|
|
227
|
+
// }
|
|
228
|
+
// }
|
|
229
|
+
// },
|
|
230
|
+
// ...
|
|
231
|
+
//
|
|
232
|
+
const responses = await Promise.all(promises);
|
|
233
|
+
const dataCurrencies = this.safeList(responses[0], 'data', []);
|
|
234
|
+
const dataNetworks = this.safeDict(responses[1], 'data', {});
|
|
235
|
+
const currenciesIndexed = this.indexBy(dataCurrencies, 'currency');
|
|
236
|
+
const data = this.deepExtend(currenciesIndexed, dataNetworks);
|
|
237
|
+
return this.parseCurrencies(this.toArray(data));
|
|
238
|
+
}
|
|
239
|
+
parseCurrency(rawCurrency) {
|
|
240
|
+
const id = this.safeString(rawCurrency, 'currency');
|
|
241
|
+
const code = this.safeCurrencyCode(id);
|
|
242
|
+
const type = this.safeBool(rawCurrency, 'fiat') ? 'fiat' : 'crypto';
|
|
243
|
+
const currencyDepositEnabled = this.safeBool(rawCurrency, 'walletDeposit');
|
|
244
|
+
const currencyWithdrawEnabled = this.safeBool(rawCurrency, 'walletWithdrawal');
|
|
245
|
+
const currencyPrecision = this.parseNumber(this.parsePrecision(this.safeString(rawCurrency, 'precision')));
|
|
246
|
+
const networks = {};
|
|
247
|
+
const rawNetworks = this.safeDict(rawCurrency, 'blockchains', {});
|
|
248
|
+
const keys = Object.keys(rawNetworks);
|
|
249
|
+
for (let j = 0; j < keys.length; j++) {
|
|
250
|
+
const networkId = keys[j];
|
|
251
|
+
const rawNetwork = rawNetworks[networkId];
|
|
252
|
+
const networkCode = this.networkIdToCode(networkId);
|
|
253
|
+
const deposit = this.safeString(rawNetwork, 'deposit') === 'enabled';
|
|
254
|
+
const withdraw = this.safeString(rawNetwork, 'withdrawal') === 'enabled';
|
|
255
|
+
networks[networkCode] = {
|
|
256
|
+
'id': networkId,
|
|
257
|
+
'network': networkCode,
|
|
258
|
+
'margin': undefined,
|
|
259
|
+
'deposit': deposit,
|
|
260
|
+
'withdraw': withdraw,
|
|
261
|
+
'fee': this.safeNumber(rawNetwork, 'withdrawalFee'),
|
|
262
|
+
'precision': currencyPrecision,
|
|
329
263
|
'limits': {
|
|
330
|
-
'
|
|
331
|
-
'min': this.safeNumber(
|
|
264
|
+
'deposit': {
|
|
265
|
+
'min': this.safeNumber(rawNetwork, 'minDeposit'),
|
|
332
266
|
'max': undefined,
|
|
333
267
|
},
|
|
334
268
|
'withdraw': {
|
|
335
|
-
'min': this.safeNumber(
|
|
269
|
+
'min': this.safeNumber(rawNetwork, 'minWithdrawal'),
|
|
336
270
|
'max': undefined,
|
|
337
271
|
},
|
|
338
272
|
},
|
|
339
|
-
'info':
|
|
273
|
+
'info': rawNetwork,
|
|
340
274
|
};
|
|
341
275
|
}
|
|
342
|
-
return
|
|
276
|
+
return this.safeCurrencyStructure({
|
|
277
|
+
'id': id,
|
|
278
|
+
'code': code,
|
|
279
|
+
'name': undefined,
|
|
280
|
+
'type': type,
|
|
281
|
+
'active': undefined,
|
|
282
|
+
'deposit': currencyDepositEnabled,
|
|
283
|
+
'withdraw': currencyWithdrawEnabled,
|
|
284
|
+
'fee': undefined,
|
|
285
|
+
'precision': currencyPrecision,
|
|
286
|
+
'limits': {
|
|
287
|
+
'amount': {
|
|
288
|
+
'min': undefined,
|
|
289
|
+
'max': undefined,
|
|
290
|
+
},
|
|
291
|
+
'withdraw': {
|
|
292
|
+
'min': undefined,
|
|
293
|
+
'max': undefined,
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
'networks': networks,
|
|
297
|
+
'info': rawCurrency,
|
|
298
|
+
});
|
|
343
299
|
}
|
|
344
300
|
async fetchMarkets(params = {}) {
|
|
345
301
|
/**
|
|
346
302
|
* @method
|
|
347
303
|
* @name cex#fetchMarkets
|
|
348
|
-
* @description retrieves data on all markets for
|
|
304
|
+
* @description retrieves data on all markets for ace
|
|
305
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-pairs-info
|
|
349
306
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
350
307
|
* @returns {object[]} an array of objects representing market data
|
|
351
308
|
*/
|
|
352
|
-
const
|
|
353
|
-
const currenciesData = this.safeValue(currenciesResponse, 'data', {});
|
|
354
|
-
const currencies = this.safeValue(currenciesData, 'symbols', []);
|
|
355
|
-
const currenciesById = this.indexBy(currencies, 'code');
|
|
356
|
-
const pairs = this.safeValue(currenciesData, 'pairs', []);
|
|
357
|
-
const response = await this.publicGetCurrencyLimits(params);
|
|
309
|
+
const response = await this.publicPostGetPairsInfo(params);
|
|
358
310
|
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
364
|
-
//
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
// "maxLotSize":null,
|
|
379
|
-
// "minPrice":"25",
|
|
380
|
-
// "maxPrice":"8192"
|
|
381
|
-
// }
|
|
382
|
-
// ]
|
|
383
|
-
// }
|
|
384
|
-
// }
|
|
311
|
+
// {
|
|
312
|
+
// "ok": "ok",
|
|
313
|
+
// "data": [
|
|
314
|
+
// {
|
|
315
|
+
// "base": "AI",
|
|
316
|
+
// "quote": "USD",
|
|
317
|
+
// "baseMin": "30",
|
|
318
|
+
// "baseMax": "2516000",
|
|
319
|
+
// "baseLotSize": "0.000001",
|
|
320
|
+
// "quoteMin": "10",
|
|
321
|
+
// "quoteMax": "1000000",
|
|
322
|
+
// "quoteLotSize": "0.01000000",
|
|
323
|
+
// "basePrecision": "6",
|
|
324
|
+
// "quotePrecision": "8",
|
|
325
|
+
// "pricePrecision": "4",
|
|
326
|
+
// "minPrice": "0.0377",
|
|
327
|
+
// "maxPrice": "19.5000"
|
|
328
|
+
// },
|
|
329
|
+
// ...
|
|
385
330
|
//
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
'
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
'contract': false,
|
|
424
|
-
'linear': undefined,
|
|
425
|
-
'inverse': undefined,
|
|
426
|
-
'contractSize': undefined,
|
|
427
|
-
'expiry': undefined,
|
|
428
|
-
'expiryDatetime': undefined,
|
|
429
|
-
'strike': undefined,
|
|
430
|
-
'optionType': undefined,
|
|
431
|
-
'precision': {
|
|
432
|
-
'amount': this.parseNumber(this.parsePrecision(amountPrecisionString)),
|
|
433
|
-
'price': this.parseNumber(this.parsePrecision(pricePrecisionString)),
|
|
331
|
+
const data = this.safeList(response, 'data', []);
|
|
332
|
+
return this.parseMarkets(data);
|
|
333
|
+
}
|
|
334
|
+
parseMarket(market) {
|
|
335
|
+
const baseId = this.safeString(market, 'base');
|
|
336
|
+
const base = this.safeCurrencyCode(baseId);
|
|
337
|
+
const quoteId = this.safeString(market, 'quote');
|
|
338
|
+
const quote = this.safeCurrencyCode(quoteId);
|
|
339
|
+
const id = base + '-' + quote; // not actual id, but for this exchange we can use this abbreviation, because e.g. tickers have hyphen in between
|
|
340
|
+
const symbol = base + '/' + quote;
|
|
341
|
+
return this.safeMarketStructure({
|
|
342
|
+
'id': id,
|
|
343
|
+
'symbol': symbol,
|
|
344
|
+
'base': base,
|
|
345
|
+
'baseId': baseId,
|
|
346
|
+
'quote': quote,
|
|
347
|
+
'quoteId': quoteId,
|
|
348
|
+
'settle': undefined,
|
|
349
|
+
'settleId': undefined,
|
|
350
|
+
'type': 'spot',
|
|
351
|
+
'spot': true,
|
|
352
|
+
'margin': false,
|
|
353
|
+
'swap': false,
|
|
354
|
+
'future': false,
|
|
355
|
+
'option': false,
|
|
356
|
+
'contract': false,
|
|
357
|
+
'linear': undefined,
|
|
358
|
+
'inverse': undefined,
|
|
359
|
+
'contractSize': undefined,
|
|
360
|
+
'expiry': undefined,
|
|
361
|
+
'expiryDatetime': undefined,
|
|
362
|
+
'strike': undefined,
|
|
363
|
+
'optionType': undefined,
|
|
364
|
+
'limits': {
|
|
365
|
+
'amount': {
|
|
366
|
+
'min': this.safeNumber(market, 'baseMin'),
|
|
367
|
+
'max': this.safeNumber(market, 'baseMax'),
|
|
434
368
|
},
|
|
435
|
-
'
|
|
436
|
-
'
|
|
437
|
-
|
|
438
|
-
'max': undefined,
|
|
439
|
-
},
|
|
440
|
-
'amount': {
|
|
441
|
-
'min': this.safeNumber(market, 'minLotSize'),
|
|
442
|
-
'max': this.safeNumber(market, 'maxLotSize'),
|
|
443
|
-
},
|
|
444
|
-
'price': {
|
|
445
|
-
'min': this.safeNumber(market, 'minPrice'),
|
|
446
|
-
'max': this.safeNumber(market, 'maxPrice'),
|
|
447
|
-
},
|
|
448
|
-
'cost': {
|
|
449
|
-
'min': this.safeNumber(market, 'minLotSizeS2'),
|
|
450
|
-
'max': undefined,
|
|
451
|
-
},
|
|
369
|
+
'price': {
|
|
370
|
+
'min': this.safeNumber(market, 'minPrice'),
|
|
371
|
+
'max': this.safeNumber(market, 'maxPrice'),
|
|
452
372
|
},
|
|
453
|
-
'
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
return this.safeBalance(result);
|
|
373
|
+
'cost': {
|
|
374
|
+
'min': this.safeNumber(market, 'quoteMin'),
|
|
375
|
+
'max': this.safeNumber(market, 'quoteMax'),
|
|
376
|
+
},
|
|
377
|
+
'leverage': {
|
|
378
|
+
'min': undefined,
|
|
379
|
+
'max': undefined,
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
'precision': {
|
|
383
|
+
'amount': this.safeString(market, 'baseLotSize'),
|
|
384
|
+
'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))),
|
|
385
|
+
// 'cost': this.parseNumber (this.parsePrecision (this.safeString (market, 'quoteLotSize'))), // buggy, doesn't reflect their documentation
|
|
386
|
+
'base': this.parseNumber(this.parsePrecision(this.safeString(market, 'basePrecision'))),
|
|
387
|
+
'quote': this.parseNumber(this.parsePrecision(this.safeString(market, 'quotePrecision'))),
|
|
388
|
+
},
|
|
389
|
+
'active': undefined,
|
|
390
|
+
'created': undefined,
|
|
391
|
+
'info': market,
|
|
392
|
+
});
|
|
475
393
|
}
|
|
476
|
-
async
|
|
394
|
+
async fetchTime(params = {}) {
|
|
477
395
|
/**
|
|
478
396
|
* @method
|
|
479
|
-
* @name cex#
|
|
480
|
-
* @
|
|
481
|
-
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
397
|
+
* @name cex#fetchTime
|
|
398
|
+
* @description fetches the current integer timestamp in milliseconds from the exchange server
|
|
482
399
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
483
|
-
* @returns {
|
|
400
|
+
* @returns {int} the current integer timestamp in milliseconds from the exchange server
|
|
484
401
|
*/
|
|
485
|
-
await this.
|
|
486
|
-
|
|
487
|
-
|
|
402
|
+
const response = await this.publicPostGetServerTime(params);
|
|
403
|
+
//
|
|
404
|
+
// {
|
|
405
|
+
// "ok": "ok",
|
|
406
|
+
// "data": {
|
|
407
|
+
// "timestamp": "1728472063472",
|
|
408
|
+
// "ISODate": "2024-10-09T11:07:43.472Z"
|
|
409
|
+
// }
|
|
410
|
+
// }
|
|
411
|
+
//
|
|
412
|
+
const data = this.safeDict(response, 'data');
|
|
413
|
+
const timestamp = this.safeInteger(data, 'timestamp');
|
|
414
|
+
return timestamp;
|
|
488
415
|
}
|
|
489
|
-
async
|
|
416
|
+
async fetchTicker(symbol, params = {}) {
|
|
490
417
|
/**
|
|
491
418
|
* @method
|
|
492
|
-
* @name cex#
|
|
493
|
-
* @
|
|
494
|
-
* @
|
|
495
|
-
* @param {string}
|
|
496
|
-
* @param {int} [limit] the maximum amount of order book entries to return
|
|
419
|
+
* @name cex#fetchTicker
|
|
420
|
+
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
421
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-ticker
|
|
422
|
+
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
497
423
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
498
|
-
* @returns {object}
|
|
424
|
+
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
499
425
|
*/
|
|
500
426
|
await this.loadMarkets();
|
|
501
|
-
const
|
|
502
|
-
|
|
503
|
-
'pair': market['id'],
|
|
504
|
-
};
|
|
505
|
-
if (limit !== undefined) {
|
|
506
|
-
request['depth'] = limit;
|
|
507
|
-
}
|
|
508
|
-
const response = await this.publicGetOrderBookPair(this.extend(request, params));
|
|
509
|
-
const timestamp = this.safeTimestamp(response, 'timestamp');
|
|
510
|
-
return this.parseOrderBook(response, market['symbol'], timestamp);
|
|
511
|
-
}
|
|
512
|
-
parseOHLCV(ohlcv, market = undefined) {
|
|
513
|
-
//
|
|
514
|
-
// [
|
|
515
|
-
// 1591403940,
|
|
516
|
-
// 0.024972,
|
|
517
|
-
// 0.024972,
|
|
518
|
-
// 0.024969,
|
|
519
|
-
// 0.024969,
|
|
520
|
-
// 0.49999900
|
|
521
|
-
// ]
|
|
522
|
-
//
|
|
523
|
-
return [
|
|
524
|
-
this.safeTimestamp(ohlcv, 0),
|
|
525
|
-
this.safeNumber(ohlcv, 1),
|
|
526
|
-
this.safeNumber(ohlcv, 2),
|
|
527
|
-
this.safeNumber(ohlcv, 3),
|
|
528
|
-
this.safeNumber(ohlcv, 4),
|
|
529
|
-
this.safeNumber(ohlcv, 5),
|
|
530
|
-
];
|
|
427
|
+
const response = await this.fetchTickers([symbol], params);
|
|
428
|
+
return this.safeDict(response, symbol, {});
|
|
531
429
|
}
|
|
532
|
-
async
|
|
430
|
+
async fetchTickers(symbols = undefined, params = {}) {
|
|
533
431
|
/**
|
|
534
432
|
* @method
|
|
535
|
-
* @name cex#
|
|
536
|
-
* @
|
|
537
|
-
* @
|
|
538
|
-
* @param {string}
|
|
539
|
-
* @param {string} timeframe the length of time each candle represents
|
|
540
|
-
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
541
|
-
* @param {int} [limit] the maximum amount of candles to fetch
|
|
433
|
+
* @name cex#fetchTickers
|
|
434
|
+
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
435
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-ticker
|
|
436
|
+
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
542
437
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
543
|
-
* @returns {
|
|
438
|
+
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
544
439
|
*/
|
|
545
440
|
await this.loadMarkets();
|
|
546
|
-
const
|
|
547
|
-
if (
|
|
548
|
-
|
|
549
|
-
}
|
|
550
|
-
else {
|
|
551
|
-
if (this.options['fetchOHLCVWarning']) {
|
|
552
|
-
throw new ExchangeError(this.id + " fetchOHLCV warning: CEX can return historical candles for a certain date only, this might produce an empty or null reply. Set exchange.options['fetchOHLCVWarning'] = false or add ({ 'options': { 'fetchOHLCVWarning': false }}) to constructor params to suppress this warning message.");
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
const request = {
|
|
556
|
-
'pair': market['id'],
|
|
557
|
-
'yyyymmdd': this.yyyymmdd(since, ''),
|
|
558
|
-
};
|
|
559
|
-
try {
|
|
560
|
-
const response = await this.publicGetOhlcvHdYyyymmddPair(this.extend(request, params));
|
|
561
|
-
//
|
|
562
|
-
// {
|
|
563
|
-
// "time":20200606,
|
|
564
|
-
// "data1m":"[[1591403940,0.024972,0.024972,0.024969,0.024969,0.49999900]]",
|
|
565
|
-
// }
|
|
566
|
-
//
|
|
567
|
-
const key = 'data' + this.safeString(this.timeframes, timeframe, timeframe);
|
|
568
|
-
const data = this.safeString(response, key);
|
|
569
|
-
const ohlcvs = JSON.parse(data);
|
|
570
|
-
return this.parseOHLCVs(ohlcvs, market, timeframe, since, limit);
|
|
571
|
-
}
|
|
572
|
-
catch (e) {
|
|
573
|
-
if (e instanceof NullResponse) {
|
|
574
|
-
return [];
|
|
575
|
-
}
|
|
441
|
+
const request = {};
|
|
442
|
+
if (symbols !== undefined) {
|
|
443
|
+
request['pairs'] = this.marketIds(symbols);
|
|
576
444
|
}
|
|
577
|
-
|
|
445
|
+
const response = await this.publicPostGetTicker(this.extend(request, params));
|
|
446
|
+
//
|
|
447
|
+
// {
|
|
448
|
+
// "ok": "ok",
|
|
449
|
+
// "data": {
|
|
450
|
+
// "AI-USD": {
|
|
451
|
+
// "bestBid": "0.3917",
|
|
452
|
+
// "bestAsk": "0.3949",
|
|
453
|
+
// "bestBidChange": "0.0035",
|
|
454
|
+
// "bestBidChangePercentage": "0.90",
|
|
455
|
+
// "bestAskChange": "0.0038",
|
|
456
|
+
// "bestAskChangePercentage": "0.97",
|
|
457
|
+
// "low": "0.3787",
|
|
458
|
+
// "high": "0.3925",
|
|
459
|
+
// "volume30d": "2945.722277",
|
|
460
|
+
// "lastTradeDateISO": "2024-10-11T06:18:42.077Z",
|
|
461
|
+
// "volume": "120.736000",
|
|
462
|
+
// "quoteVolume": "46.65654070",
|
|
463
|
+
// "lastTradeVolume": "67.914000",
|
|
464
|
+
// "volumeUSD": "46.65",
|
|
465
|
+
// "last": "0.3949",
|
|
466
|
+
// "lastTradePrice": "0.3925",
|
|
467
|
+
// "priceChange": "0.0038",
|
|
468
|
+
// "priceChangePercentage": "0.97"
|
|
469
|
+
// },
|
|
470
|
+
// ...
|
|
471
|
+
//
|
|
472
|
+
const data = this.safeDict(response, 'data', {});
|
|
473
|
+
return this.parseTickers(data, symbols);
|
|
578
474
|
}
|
|
579
475
|
parseTicker(ticker, market = undefined) {
|
|
580
|
-
const
|
|
581
|
-
const
|
|
582
|
-
const high = this.safeString(ticker, 'high');
|
|
583
|
-
const low = this.safeString(ticker, 'low');
|
|
584
|
-
const bid = this.safeString(ticker, 'bid');
|
|
585
|
-
const ask = this.safeString(ticker, 'ask');
|
|
586
|
-
const last = this.safeString(ticker, 'last');
|
|
587
|
-
const symbol = this.safeSymbol(undefined, market);
|
|
476
|
+
const marketId = this.safeString(ticker, 'id');
|
|
477
|
+
const symbol = this.safeSymbol(marketId, market);
|
|
588
478
|
return this.safeTicker({
|
|
589
479
|
'symbol': symbol,
|
|
590
|
-
'timestamp':
|
|
591
|
-
'datetime':
|
|
592
|
-
'high': high,
|
|
593
|
-
'low': low,
|
|
594
|
-
'bid':
|
|
480
|
+
'timestamp': undefined,
|
|
481
|
+
'datetime': undefined,
|
|
482
|
+
'high': this.safeNumber(ticker, 'high'),
|
|
483
|
+
'low': this.safeNumber(ticker, 'low'),
|
|
484
|
+
'bid': this.safeNumber(ticker, 'bestBid'),
|
|
595
485
|
'bidVolume': undefined,
|
|
596
|
-
'ask':
|
|
486
|
+
'ask': this.safeNumber(ticker, 'bestAsk'),
|
|
597
487
|
'askVolume': undefined,
|
|
598
488
|
'vwap': undefined,
|
|
599
489
|
'open': undefined,
|
|
600
|
-
'close':
|
|
601
|
-
'last': last,
|
|
490
|
+
'close': this.safeString(ticker, 'lastTradePrice'),
|
|
602
491
|
'previousClose': undefined,
|
|
603
|
-
'change':
|
|
604
|
-
'percentage':
|
|
492
|
+
'change': this.safeNumber(ticker, 'priceChange'),
|
|
493
|
+
'percentage': this.safeNumber(ticker, 'priceChangePercentage'),
|
|
605
494
|
'average': undefined,
|
|
606
|
-
'baseVolume': volume,
|
|
607
|
-
'quoteVolume':
|
|
495
|
+
'baseVolume': this.safeString(ticker, 'volume'),
|
|
496
|
+
'quoteVolume': this.safeString(ticker, 'quoteVolume'),
|
|
608
497
|
'info': ticker,
|
|
609
498
|
}, market);
|
|
610
499
|
}
|
|
611
|
-
async
|
|
612
|
-
/**
|
|
613
|
-
* @method
|
|
614
|
-
* @name cex#fetchTickers
|
|
615
|
-
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
616
|
-
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
617
|
-
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
618
|
-
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
619
|
-
*/
|
|
620
|
-
await this.loadMarkets();
|
|
621
|
-
symbols = this.marketSymbols(symbols);
|
|
622
|
-
const currencies = Object.keys(this.currencies);
|
|
623
|
-
const request = {
|
|
624
|
-
'currencies': currencies.join('/'),
|
|
625
|
-
};
|
|
626
|
-
const response = await this.publicGetTickersCurrencies(this.extend(request, params));
|
|
627
|
-
const tickers = this.safeValue(response, 'data', []);
|
|
628
|
-
const result = {};
|
|
629
|
-
for (let t = 0; t < tickers.length; t++) {
|
|
630
|
-
const ticker = tickers[t];
|
|
631
|
-
const marketId = this.safeString(ticker, 'pair');
|
|
632
|
-
const market = this.safeMarket(marketId, undefined, ':');
|
|
633
|
-
const symbol = market['symbol'];
|
|
634
|
-
result[symbol] = this.parseTicker(ticker, market);
|
|
635
|
-
}
|
|
636
|
-
return this.filterByArrayTickers(result, 'symbol', symbols);
|
|
637
|
-
}
|
|
638
|
-
async fetchTicker(symbol, params = {}) {
|
|
500
|
+
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
639
501
|
/**
|
|
640
502
|
* @method
|
|
641
|
-
* @name cex#
|
|
642
|
-
* @
|
|
643
|
-
* @
|
|
644
|
-
* @param {string} symbol unified symbol of the market to fetch
|
|
503
|
+
* @name cex#fetchTrades
|
|
504
|
+
* @description get the list of most recent trades for a particular symbol
|
|
505
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-trade-history
|
|
506
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
507
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
508
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
645
509
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
646
|
-
* @
|
|
510
|
+
* @param {int} [params.until] timestamp in ms of the latest entry
|
|
511
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
647
512
|
*/
|
|
648
513
|
await this.loadMarkets();
|
|
649
514
|
const market = this.market(symbol);
|
|
650
515
|
const request = {
|
|
651
516
|
'pair': market['id'],
|
|
652
517
|
};
|
|
653
|
-
|
|
654
|
-
|
|
518
|
+
if (since !== undefined) {
|
|
519
|
+
request['fromDateISO'] = this.iso8601(since);
|
|
520
|
+
}
|
|
521
|
+
let until = undefined;
|
|
522
|
+
[until, params] = this.handleParamInteger2(params, 'until', 'till');
|
|
523
|
+
if (until !== undefined) {
|
|
524
|
+
request['toDateISO'] = this.iso8601(until);
|
|
525
|
+
}
|
|
526
|
+
if (limit !== undefined) {
|
|
527
|
+
request['pageSize'] = Math.min(limit, 10000); // has a bug, still returns more trades
|
|
528
|
+
}
|
|
529
|
+
const response = await this.publicPostGetTradeHistory(this.extend(request, params));
|
|
530
|
+
//
|
|
531
|
+
// {
|
|
532
|
+
// "ok": "ok",
|
|
533
|
+
// "data": {
|
|
534
|
+
// "pageSize": "10",
|
|
535
|
+
// "trades": [
|
|
536
|
+
// {
|
|
537
|
+
// "tradeId": "1728630559823-0",
|
|
538
|
+
// "dateISO": "2024-10-11T07:09:19.823Z",
|
|
539
|
+
// "side": "SELL",
|
|
540
|
+
// "price": "60879.5",
|
|
541
|
+
// "amount": "0.00165962"
|
|
542
|
+
// },
|
|
543
|
+
// ... followed by older trades
|
|
544
|
+
//
|
|
545
|
+
const data = this.safeDict(response, 'data', {});
|
|
546
|
+
const trades = this.safeList(data, 'trades', []);
|
|
547
|
+
return this.parseTrades(trades, market, since, limit);
|
|
655
548
|
}
|
|
656
549
|
parseTrade(trade, market = undefined) {
|
|
657
550
|
//
|
|
658
|
-
// fetchTrades
|
|
551
|
+
// public fetchTrades
|
|
659
552
|
//
|
|
660
|
-
//
|
|
661
|
-
//
|
|
662
|
-
//
|
|
663
|
-
//
|
|
664
|
-
//
|
|
665
|
-
//
|
|
666
|
-
//
|
|
553
|
+
// {
|
|
554
|
+
// "tradeId": "1728630559823-0",
|
|
555
|
+
// "dateISO": "2024-10-11T07:09:19.823Z",
|
|
556
|
+
// "side": "SELL",
|
|
557
|
+
// "price": "60879.5",
|
|
558
|
+
// "amount": "0.00165962"
|
|
559
|
+
// },
|
|
667
560
|
//
|
|
668
|
-
const
|
|
669
|
-
const
|
|
670
|
-
const type = undefined;
|
|
671
|
-
const side = this.safeString(trade, 'type');
|
|
672
|
-
const priceString = this.safeString(trade, 'price');
|
|
673
|
-
const amountString = this.safeString(trade, 'amount');
|
|
561
|
+
const dateStr = this.safeString(trade, 'dateISO');
|
|
562
|
+
const timestamp = this.parse8601(dateStr);
|
|
674
563
|
market = this.safeMarket(undefined, market);
|
|
675
564
|
return this.safeTrade({
|
|
676
565
|
'info': trade,
|
|
677
|
-
'id': id,
|
|
678
566
|
'timestamp': timestamp,
|
|
679
567
|
'datetime': this.iso8601(timestamp),
|
|
680
568
|
'symbol': market['symbol'],
|
|
681
|
-
'
|
|
682
|
-
'side': side,
|
|
569
|
+
'id': this.safeString(trade, 'tradeId'),
|
|
683
570
|
'order': undefined,
|
|
571
|
+
'type': undefined,
|
|
684
572
|
'takerOrMaker': undefined,
|
|
685
|
-
'
|
|
686
|
-
'
|
|
573
|
+
'side': this.safeStringLower(trade, 'side'),
|
|
574
|
+
'price': this.safeString(trade, 'price'),
|
|
575
|
+
'amount': this.safeString(trade, 'amount'),
|
|
687
576
|
'cost': undefined,
|
|
688
577
|
'fee': undefined,
|
|
689
578
|
}, market);
|
|
690
579
|
}
|
|
691
|
-
async
|
|
580
|
+
async fetchOrderBook(symbol, limit = undefined, params = {}) {
|
|
692
581
|
/**
|
|
693
582
|
* @method
|
|
694
|
-
* @name cex#
|
|
695
|
-
* @
|
|
696
|
-
* @
|
|
697
|
-
* @param {string} symbol unified symbol of the market to fetch
|
|
698
|
-
* @param {int} [
|
|
699
|
-
* @param {int} [limit] the maximum amount of trades to fetch
|
|
583
|
+
* @name cex#fetchOrderBook
|
|
584
|
+
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
585
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-order-book
|
|
586
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
587
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
700
588
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
701
|
-
* @returns {
|
|
589
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
590
|
+
*/
|
|
591
|
+
await this.loadMarkets();
|
|
592
|
+
const market = this.market(symbol);
|
|
593
|
+
const request = {
|
|
594
|
+
'pair': market['id'],
|
|
595
|
+
};
|
|
596
|
+
const response = await this.publicPostGetOrderBook(this.extend(request, params));
|
|
597
|
+
//
|
|
598
|
+
// {
|
|
599
|
+
// "ok": "ok",
|
|
600
|
+
// "data": {
|
|
601
|
+
// "timestamp": "1728636922648",
|
|
602
|
+
// "currency1": "BTC",
|
|
603
|
+
// "currency2": "USDT",
|
|
604
|
+
// "bids": [
|
|
605
|
+
// [
|
|
606
|
+
// "60694.1",
|
|
607
|
+
// "13.12849761"
|
|
608
|
+
// ],
|
|
609
|
+
// [
|
|
610
|
+
// "60694.0",
|
|
611
|
+
// "0.71829244"
|
|
612
|
+
// ],
|
|
613
|
+
// ...
|
|
614
|
+
//
|
|
615
|
+
const orderBook = this.safeDict(response, 'data', {});
|
|
616
|
+
const timestamp = this.safeInteger(orderBook, 'timestamp');
|
|
617
|
+
return this.parseOrderBook(orderBook, market['symbol'], timestamp);
|
|
618
|
+
}
|
|
619
|
+
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
620
|
+
/**
|
|
621
|
+
* @method
|
|
622
|
+
* @name cex#fetchOHLCV
|
|
623
|
+
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
624
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-candles
|
|
625
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
626
|
+
* @param {string} timeframe the length of time each candle represents
|
|
627
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
628
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
629
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
630
|
+
* @param {int} [params.until] timestamp in ms of the latest entry
|
|
631
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
702
632
|
*/
|
|
633
|
+
let dataType = undefined;
|
|
634
|
+
[dataType, params] = this.handleOptionAndParams(params, 'fetchOHLCV', 'dataType');
|
|
635
|
+
if (dataType === undefined) {
|
|
636
|
+
throw new ArgumentsRequired(this.id + ' fetchOHLCV requires a parameter "dataType" to be either "bestBid" or "bestAsk"');
|
|
637
|
+
}
|
|
703
638
|
await this.loadMarkets();
|
|
704
639
|
const market = this.market(symbol);
|
|
705
640
|
const request = {
|
|
706
641
|
'pair': market['id'],
|
|
642
|
+
'resolution': this.timeframes[timeframe],
|
|
643
|
+
'dataType': dataType,
|
|
707
644
|
};
|
|
708
|
-
|
|
709
|
-
|
|
645
|
+
if (since !== undefined) {
|
|
646
|
+
request['fromISO'] = this.iso8601(since);
|
|
647
|
+
}
|
|
648
|
+
let until = undefined;
|
|
649
|
+
[until, params] = this.handleParamInteger2(params, 'until', 'till');
|
|
650
|
+
if (until !== undefined) {
|
|
651
|
+
request['toISO'] = this.iso8601(until);
|
|
652
|
+
}
|
|
653
|
+
else if (since === undefined) {
|
|
654
|
+
// exchange still requires that we provide one of them
|
|
655
|
+
request['toISO'] = this.iso8601(this.milliseconds());
|
|
656
|
+
}
|
|
657
|
+
if (since !== undefined && until !== undefined && limit !== undefined) {
|
|
658
|
+
throw new ArgumentsRequired(this.id + ' fetchOHLCV does not support fetching candles with both a limit and since/until');
|
|
659
|
+
}
|
|
660
|
+
else if ((since !== undefined || until !== undefined) && limit === undefined) {
|
|
661
|
+
throw new ArgumentsRequired(this.id + ' fetchOHLCV requires a limit parameter when fetching candles with since or until');
|
|
662
|
+
}
|
|
663
|
+
if (limit !== undefined) {
|
|
664
|
+
request['limit'] = limit;
|
|
665
|
+
}
|
|
666
|
+
const response = await this.publicPostGetCandles(this.extend(request, params));
|
|
667
|
+
//
|
|
668
|
+
// {
|
|
669
|
+
// "ok": "ok",
|
|
670
|
+
// "data": [
|
|
671
|
+
// {
|
|
672
|
+
// "timestamp": "1728643320000",
|
|
673
|
+
// "open": "61061",
|
|
674
|
+
// "high": "61095.1",
|
|
675
|
+
// "low": "61048.5",
|
|
676
|
+
// "close": "61087.8",
|
|
677
|
+
// "volume": "0",
|
|
678
|
+
// "resolution": "1m",
|
|
679
|
+
// "isClosed": true,
|
|
680
|
+
// "timestampISO": "2024-10-11T10:42:00.000Z"
|
|
681
|
+
// },
|
|
682
|
+
// ...
|
|
683
|
+
//
|
|
684
|
+
const data = this.safeList(response, 'data', []);
|
|
685
|
+
return this.parseOHLCVs(data, market, timeframe, since, limit);
|
|
686
|
+
}
|
|
687
|
+
parseOHLCV(ohlcv, market = undefined) {
|
|
688
|
+
return [
|
|
689
|
+
this.safeInteger(ohlcv, 'timestamp'),
|
|
690
|
+
this.safeNumber(ohlcv, 'open'),
|
|
691
|
+
this.safeNumber(ohlcv, 'high'),
|
|
692
|
+
this.safeNumber(ohlcv, 'low'),
|
|
693
|
+
this.safeNumber(ohlcv, 'close'),
|
|
694
|
+
this.safeNumber(ohlcv, 'volume'),
|
|
695
|
+
];
|
|
710
696
|
}
|
|
711
697
|
async fetchTradingFees(params = {}) {
|
|
712
698
|
/**
|
|
713
699
|
* @method
|
|
714
700
|
* @name cex#fetchTradingFees
|
|
715
|
-
* @see https://docs.cex.io/#get-my-fee
|
|
716
701
|
* @description fetch the trading fees for multiple markets
|
|
702
|
+
* @see https://trade.cex.io/docs/#rest-public-api-calls-candles
|
|
717
703
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
718
704
|
* @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
|
|
719
705
|
*/
|
|
720
706
|
await this.loadMarkets();
|
|
721
|
-
const response = await this.
|
|
707
|
+
const response = await this.privatePostGetMyCurrentFee(params);
|
|
722
708
|
//
|
|
723
|
-
//
|
|
724
|
-
//
|
|
725
|
-
//
|
|
726
|
-
//
|
|
727
|
-
//
|
|
728
|
-
//
|
|
729
|
-
//
|
|
730
|
-
//
|
|
731
|
-
// }
|
|
709
|
+
// {
|
|
710
|
+
// "ok": "ok",
|
|
711
|
+
// "data": {
|
|
712
|
+
// "tradingFee": {
|
|
713
|
+
// "AI-USD": {
|
|
714
|
+
// "percent": "0.25"
|
|
715
|
+
// },
|
|
716
|
+
// ...
|
|
732
717
|
//
|
|
733
|
-
const data = this.
|
|
718
|
+
const data = this.safeDict(response, 'data', {});
|
|
719
|
+
const fees = this.safeDict(data, 'tradingFee', {});
|
|
720
|
+
return this.parseTradingFees(fees, true);
|
|
721
|
+
}
|
|
722
|
+
parseTradingFees(response, useKeyAsId = false) {
|
|
734
723
|
const result = {};
|
|
724
|
+
const keys = Object.keys(response);
|
|
725
|
+
for (let i = 0; i < keys.length; i++) {
|
|
726
|
+
const key = keys[i];
|
|
727
|
+
let market = undefined;
|
|
728
|
+
if (useKeyAsId) {
|
|
729
|
+
market = this.safeMarket(key);
|
|
730
|
+
}
|
|
731
|
+
const parsed = this.parseTradingFee(response[key], market);
|
|
732
|
+
result[parsed['symbol']] = parsed;
|
|
733
|
+
}
|
|
735
734
|
for (let i = 0; i < this.symbols.length; i++) {
|
|
736
735
|
const symbol = this.symbols[i];
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
const maker = this.parseNumber(Precise.stringDiv(makerString, '100'));
|
|
742
|
-
const taker = this.parseNumber(Precise.stringDiv(takerString, '100'));
|
|
743
|
-
result[symbol] = {
|
|
744
|
-
'info': fee,
|
|
745
|
-
'symbol': symbol,
|
|
746
|
-
'maker': maker,
|
|
747
|
-
'taker': taker,
|
|
748
|
-
'percentage': true,
|
|
749
|
-
};
|
|
736
|
+
if (!(symbol in result)) {
|
|
737
|
+
const market = this.market(symbol);
|
|
738
|
+
result[symbol] = this.parseTradingFee(response, market);
|
|
739
|
+
}
|
|
750
740
|
}
|
|
751
741
|
return result;
|
|
752
742
|
}
|
|
753
|
-
|
|
743
|
+
parseTradingFee(fee, market = undefined) {
|
|
744
|
+
return {
|
|
745
|
+
'info': fee,
|
|
746
|
+
'symbol': this.safeString(market, 'symbol'),
|
|
747
|
+
'maker': this.safeNumber(fee, 'percent'),
|
|
748
|
+
'taker': this.safeNumber(fee, 'percent'),
|
|
749
|
+
'percentage': undefined,
|
|
750
|
+
'tierBased': undefined,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
async fetchAccounts(params = {}) {
|
|
754
|
+
await this.loadMarkets();
|
|
755
|
+
const response = await this.privatePostGetMyAccountStatusV3(params);
|
|
756
|
+
//
|
|
757
|
+
// {
|
|
758
|
+
// "ok": "ok",
|
|
759
|
+
// "data": {
|
|
760
|
+
// "convertedCurrency": "USD",
|
|
761
|
+
// "balancesPerAccounts": {
|
|
762
|
+
// "": {
|
|
763
|
+
// "AI": {
|
|
764
|
+
// "balance": "0.000000",
|
|
765
|
+
// "balanceOnHold": "0.000000"
|
|
766
|
+
// },
|
|
767
|
+
// "USDT": {
|
|
768
|
+
// "balance": "0.00000000",
|
|
769
|
+
// "balanceOnHold": "0.00000000"
|
|
770
|
+
// }
|
|
771
|
+
// }
|
|
772
|
+
// }
|
|
773
|
+
// }
|
|
774
|
+
// }
|
|
775
|
+
//
|
|
776
|
+
const data = this.safeDict(response, 'data', {});
|
|
777
|
+
const balances = this.safeDict(data, 'balancesPerAccounts', {});
|
|
778
|
+
const arrays = this.toArray(balances);
|
|
779
|
+
return this.parseAccounts(arrays, params);
|
|
780
|
+
}
|
|
781
|
+
parseAccount(account) {
|
|
782
|
+
return {
|
|
783
|
+
'id': undefined,
|
|
784
|
+
'type': undefined,
|
|
785
|
+
'code': undefined,
|
|
786
|
+
'info': account,
|
|
787
|
+
};
|
|
788
|
+
}
|
|
789
|
+
async fetchBalance(params = {}) {
|
|
754
790
|
/**
|
|
755
791
|
* @method
|
|
756
|
-
* @name cex#
|
|
757
|
-
* @
|
|
758
|
-
* @
|
|
759
|
-
* @see https://cex.io/rest-api#place-order
|
|
760
|
-
* @param {string} symbol unified symbol of the market to create an order in
|
|
761
|
-
* @param {string} type 'market' or 'limit'
|
|
762
|
-
* @param {string} side 'buy' or 'sell'
|
|
763
|
-
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
764
|
-
* @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
792
|
+
* @name cex#fetchBalance
|
|
793
|
+
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
794
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-account-status-v3
|
|
765
795
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
766
|
-
* @param {
|
|
767
|
-
* @
|
|
796
|
+
* @param {object} [params.method] 'privatePostGetMyWalletBalance' or 'privatePostGetMyAccountStatusV3'
|
|
797
|
+
* @param {object} [params.account] in case 'privatePostGetMyAccountStatusV3' is chosen, this can specify the account name (default is empty string)
|
|
798
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
768
799
|
*/
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
const costRequest = Precise.stringMul(amountString, priceString);
|
|
793
|
-
quoteAmount = this.costToPrecision(symbol, costRequest);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
quoteAmount = this.costToPrecision(symbol, amount);
|
|
798
|
-
}
|
|
799
|
-
request['amount'] = quoteAmount;
|
|
800
|
+
let accountName = undefined;
|
|
801
|
+
[accountName, params] = this.handleParamString(params, 'account', ''); // default is empty string
|
|
802
|
+
let method = undefined;
|
|
803
|
+
[method, params] = this.handleParamString(params, 'method', 'privatePostGetMyWalletBalance');
|
|
804
|
+
let accountBalance = undefined;
|
|
805
|
+
if (method === 'privatePostGetMyAccountStatusV3') {
|
|
806
|
+
const response = await this.privatePostGetMyAccountStatusV3(params);
|
|
807
|
+
//
|
|
808
|
+
// {
|
|
809
|
+
// "ok": "ok",
|
|
810
|
+
// "data": {
|
|
811
|
+
// "convertedCurrency": "USD",
|
|
812
|
+
// "balancesPerAccounts": {
|
|
813
|
+
// "": {
|
|
814
|
+
// "AI": {
|
|
815
|
+
// "balance": "0.000000",
|
|
816
|
+
// "balanceOnHold": "0.000000"
|
|
817
|
+
// },
|
|
818
|
+
// ....
|
|
819
|
+
//
|
|
820
|
+
const data = this.safeDict(response, 'data', {});
|
|
821
|
+
const balances = this.safeDict(data, 'balancesPerAccounts', {});
|
|
822
|
+
accountBalance = this.safeDict(balances, accountName, {});
|
|
800
823
|
}
|
|
801
824
|
else {
|
|
802
|
-
|
|
825
|
+
const response = await this.privatePostGetMyWalletBalance(params);
|
|
826
|
+
//
|
|
827
|
+
// {
|
|
828
|
+
// "ok": "ok",
|
|
829
|
+
// "data": {
|
|
830
|
+
// "AI": {
|
|
831
|
+
// "balance": "25.606429"
|
|
832
|
+
// },
|
|
833
|
+
// "USDT": {
|
|
834
|
+
// "balance": "7.935449"
|
|
835
|
+
// },
|
|
836
|
+
// ...
|
|
837
|
+
//
|
|
838
|
+
accountBalance = this.safeDict(response, 'data', {});
|
|
803
839
|
}
|
|
804
|
-
|
|
805
|
-
|
|
840
|
+
return this.parseBalance(accountBalance);
|
|
841
|
+
}
|
|
842
|
+
parseBalance(response) {
|
|
843
|
+
const result = {
|
|
844
|
+
'info': response,
|
|
845
|
+
};
|
|
846
|
+
const keys = Object.keys(response);
|
|
847
|
+
for (let i = 0; i < keys.length; i++) {
|
|
848
|
+
const key = keys[i];
|
|
849
|
+
const balance = this.safeDict(response, key, {});
|
|
850
|
+
const code = this.safeCurrencyCode(key);
|
|
851
|
+
const account = {
|
|
852
|
+
'used': this.safeString(balance, 'balanceOnHold'),
|
|
853
|
+
'free': this.safeString(balance, 'balance'),
|
|
854
|
+
};
|
|
855
|
+
result[code] = account;
|
|
806
856
|
}
|
|
807
|
-
|
|
808
|
-
|
|
857
|
+
return this.safeBalance(result);
|
|
858
|
+
}
|
|
859
|
+
async fetchOrdersByStatus(status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
860
|
+
/**
|
|
861
|
+
* @method
|
|
862
|
+
* @name cex#fetchOrders
|
|
863
|
+
* @description fetches information on multiple orders made by the user
|
|
864
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-orders
|
|
865
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
866
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
867
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
868
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
869
|
+
* @param {int} [params.until] timestamp in ms of the latest entry
|
|
870
|
+
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
871
|
+
*/
|
|
872
|
+
await this.loadMarkets();
|
|
873
|
+
const request = {};
|
|
874
|
+
const isClosedOrders = (status === 'closed');
|
|
875
|
+
if (isClosedOrders) {
|
|
876
|
+
request['archived'] = true;
|
|
809
877
|
}
|
|
810
|
-
|
|
878
|
+
let market = undefined;
|
|
879
|
+
if (symbol !== undefined) {
|
|
880
|
+
market = this.market(symbol);
|
|
881
|
+
request['pair'] = market['id'];
|
|
882
|
+
}
|
|
883
|
+
if (limit !== undefined) {
|
|
884
|
+
request['pageSize'] = limit;
|
|
885
|
+
}
|
|
886
|
+
if (since !== undefined) {
|
|
887
|
+
request['serverCreateTimestampFrom'] = since;
|
|
888
|
+
}
|
|
889
|
+
else if (isClosedOrders) {
|
|
890
|
+
// exchange requires a `since` parameter for closed orders, so set default to allowed 365
|
|
891
|
+
request['serverCreateTimestampFrom'] = this.milliseconds() - 364 * 24 * 60 * 60 * 1000;
|
|
892
|
+
}
|
|
893
|
+
let until = undefined;
|
|
894
|
+
[until, params] = this.handleParamInteger2(params, 'until', 'till');
|
|
895
|
+
if (until !== undefined) {
|
|
896
|
+
request['serverCreateTimestampTo'] = until;
|
|
897
|
+
}
|
|
898
|
+
const response = await this.privatePostGetMyOrders(this.extend(request, params));
|
|
811
899
|
//
|
|
812
|
-
//
|
|
813
|
-
// "id": "12978363524",
|
|
814
|
-
// "time": 1586610022259,
|
|
815
|
-
// "type": "buy",
|
|
816
|
-
// "price": "0.033934",
|
|
817
|
-
// "amount": "0.10722802",
|
|
818
|
-
// "pending": "0.10722802",
|
|
819
|
-
// "complete": false
|
|
820
|
-
// }
|
|
900
|
+
// if called without `pair`
|
|
821
901
|
//
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
902
|
+
// {
|
|
903
|
+
// "ok": "ok",
|
|
904
|
+
// "data": [
|
|
905
|
+
// {
|
|
906
|
+
// "orderId": "1313003",
|
|
907
|
+
// "clientOrderId": "037F0AFEB93A",
|
|
908
|
+
// "clientId": "up421412345",
|
|
909
|
+
// "accountId": null,
|
|
910
|
+
// "status": "FILLED",
|
|
911
|
+
// "statusIsFinal": true,
|
|
912
|
+
// "currency1": "AI",
|
|
913
|
+
// "currency2": "USDT",
|
|
914
|
+
// "side": "BUY",
|
|
915
|
+
// "orderType": "Market",
|
|
916
|
+
// "timeInForce": "IOC",
|
|
917
|
+
// "comment": null,
|
|
918
|
+
// "rejectCode": null,
|
|
919
|
+
// "rejectReason": null,
|
|
920
|
+
// "initialOnHoldAmountCcy1": null,
|
|
921
|
+
// "initialOnHoldAmountCcy2": "10.23456700",
|
|
922
|
+
// "executedAmountCcy1": "25.606429",
|
|
923
|
+
// "executedAmountCcy2": "10.20904439",
|
|
924
|
+
// "requestedAmountCcy1": null,
|
|
925
|
+
// "requestedAmountCcy2": "10.20904439",
|
|
926
|
+
// "originalAmountCcy2": "10.23456700",
|
|
927
|
+
// "feeAmount": "0.02552261",
|
|
928
|
+
// "feeCurrency": "USDT",
|
|
929
|
+
// "price": null,
|
|
930
|
+
// "averagePrice": "0.3986",
|
|
931
|
+
// "clientCreateTimestamp": "1728474625320",
|
|
932
|
+
// "serverCreateTimestamp": "1728474624956",
|
|
933
|
+
// "lastUpdateTimestamp": "1728474628015",
|
|
934
|
+
// "expireTime": null,
|
|
935
|
+
// "effectiveTime": null
|
|
936
|
+
// },
|
|
937
|
+
// ...
|
|
938
|
+
//
|
|
939
|
+
const data = this.safeValue(response, 'data', []);
|
|
940
|
+
return this.parseOrders(data, market, since, limit);
|
|
941
|
+
}
|
|
942
|
+
async fetchClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
943
|
+
/**
|
|
944
|
+
* @method
|
|
945
|
+
* @name cex#fetchClosedOrders
|
|
946
|
+
* @description fetches information on multiple canceled orders made by the user
|
|
947
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
948
|
+
* @param {int} [since] timestamp in ms of the earliest order, default is undefined
|
|
949
|
+
* @param {int} [limit] max number of orders to return, default is undefined
|
|
950
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
951
|
+
* @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
952
|
+
*/
|
|
953
|
+
return await this.fetchOrdersByStatus('closed', symbol, since, limit, params);
|
|
954
|
+
}
|
|
955
|
+
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
956
|
+
/**
|
|
957
|
+
* @method
|
|
958
|
+
* @name cex#fetchOpenOrders
|
|
959
|
+
* @description fetches information on multiple canceled orders made by the user
|
|
960
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
961
|
+
* @param {int} [since] timestamp in ms of the earliest order, default is undefined
|
|
962
|
+
* @param {int} [limit] max number of orders to return, default is undefined
|
|
963
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
964
|
+
* @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
965
|
+
*/
|
|
966
|
+
return await this.fetchOrdersByStatus('open', symbol, since, limit, params);
|
|
967
|
+
}
|
|
968
|
+
parseOrderStatus(status) {
|
|
969
|
+
const statuses = {
|
|
970
|
+
'FILLED': 'closed',
|
|
971
|
+
'CANCELLED': 'canceled',
|
|
972
|
+
};
|
|
973
|
+
return this.safeString(statuses, status, undefined);
|
|
974
|
+
}
|
|
975
|
+
parseOrder(order, market = undefined) {
|
|
976
|
+
//
|
|
977
|
+
// "orderId": "1313003",
|
|
978
|
+
// "clientOrderId": "037F0AFEB93A",
|
|
979
|
+
// "clientId": "up421412345",
|
|
980
|
+
// "accountId": null,
|
|
981
|
+
// "status": "FILLED",
|
|
982
|
+
// "statusIsFinal": true,
|
|
983
|
+
// "currency1": "AI",
|
|
984
|
+
// "currency2": "USDT",
|
|
985
|
+
// "side": "BUY",
|
|
986
|
+
// "orderType": "Market",
|
|
987
|
+
// "timeInForce": "IOC",
|
|
988
|
+
// "comment": null,
|
|
989
|
+
// "rejectCode": null,
|
|
990
|
+
// "rejectReason": null,
|
|
991
|
+
// "initialOnHoldAmountCcy1": null,
|
|
992
|
+
// "initialOnHoldAmountCcy2": "10.23456700",
|
|
993
|
+
// "executedAmountCcy1": "25.606429",
|
|
994
|
+
// "executedAmountCcy2": "10.20904439",
|
|
995
|
+
// "requestedAmountCcy1": null,
|
|
996
|
+
// "requestedAmountCcy2": "10.20904439",
|
|
997
|
+
// "originalAmountCcy2": "10.23456700",
|
|
998
|
+
// "feeAmount": "0.02552261",
|
|
999
|
+
// "feeCurrency": "USDT",
|
|
1000
|
+
// "price": null,
|
|
1001
|
+
// "averagePrice": "0.3986",
|
|
1002
|
+
// "clientCreateTimestamp": "1728474625320",
|
|
1003
|
+
// "serverCreateTimestamp": "1728474624956",
|
|
1004
|
+
// "lastUpdateTimestamp": "1728474628015",
|
|
1005
|
+
// "expireTime": null,
|
|
1006
|
+
// "effectiveTime": null
|
|
1007
|
+
//
|
|
1008
|
+
const currency1 = this.safeString(order, 'currency1');
|
|
1009
|
+
const currency2 = this.safeString(order, 'currency2');
|
|
1010
|
+
let marketId = undefined;
|
|
1011
|
+
if (currency1 !== undefined && currency2 !== undefined) {
|
|
1012
|
+
marketId = currency1 + '-' + currency2;
|
|
830
1013
|
}
|
|
1014
|
+
market = this.safeMarket(marketId, market);
|
|
1015
|
+
const symbol = market['symbol'];
|
|
1016
|
+
const status = this.parseOrderStatus(this.safeString(order, 'status'));
|
|
1017
|
+
const fee = {};
|
|
1018
|
+
const feeAmount = this.safeNumber(order, 'feeAmount');
|
|
1019
|
+
if (feeAmount !== undefined) {
|
|
1020
|
+
const currencyId = this.safeString(order, 'feeCurrency');
|
|
1021
|
+
const feeCode = this.safeCurrencyCode(currencyId);
|
|
1022
|
+
fee['currency'] = feeCode;
|
|
1023
|
+
fee['fee'] = feeAmount;
|
|
1024
|
+
}
|
|
1025
|
+
const timestamp = this.safeInteger(order, 'serverCreateTimestamp');
|
|
1026
|
+
const requestedBase = this.safeNumber(order, 'requestedAmountCcy1');
|
|
1027
|
+
const executedBase = this.safeNumber(order, 'executedAmountCcy1');
|
|
1028
|
+
// const requestedQuote = this.safeNumber (order, 'requestedAmountCcy2');
|
|
1029
|
+
const executedQuote = this.safeNumber(order, 'executedAmountCcy2');
|
|
831
1030
|
return this.safeOrder({
|
|
832
|
-
'id': this.safeString(
|
|
833
|
-
'
|
|
834
|
-
'clientOrderId': undefined,
|
|
1031
|
+
'id': this.safeString(order, 'orderId'),
|
|
1032
|
+
'clientOrderId': this.safeString(order, 'clientOrderId'),
|
|
835
1033
|
'timestamp': timestamp,
|
|
836
1034
|
'datetime': this.iso8601(timestamp),
|
|
1035
|
+
'lastUpdateTimestamp': this.safeInteger(order, 'lastUpdateTimestamp'),
|
|
837
1036
|
'lastTradeTimestamp': undefined,
|
|
838
|
-
'
|
|
839
|
-
'
|
|
840
|
-
'
|
|
1037
|
+
'symbol': symbol,
|
|
1038
|
+
'type': this.safeStringLower(order, 'orderType'),
|
|
1039
|
+
'timeInForce': this.safeString(order, 'timeInForce'),
|
|
1040
|
+
'postOnly': undefined,
|
|
1041
|
+
'side': this.safeStringLower(order, 'side'),
|
|
1042
|
+
'price': this.safeNumber(order, 'price'),
|
|
1043
|
+
'stopPrice': this.safeNumber(order, 'stopPrice'),
|
|
1044
|
+
'amount': requestedBase,
|
|
1045
|
+
'cost': executedQuote,
|
|
1046
|
+
'average': this.safeNumber(order, 'averagePrice'),
|
|
1047
|
+
'filled': executedBase,
|
|
1048
|
+
'remaining': undefined,
|
|
841
1049
|
'status': status,
|
|
842
|
-
'
|
|
843
|
-
'amount': placedAmount,
|
|
844
|
-
'cost': undefined,
|
|
845
|
-
'average': undefined,
|
|
846
|
-
'remaining': remaining,
|
|
847
|
-
'filled': filled,
|
|
848
|
-
'fee': undefined,
|
|
1050
|
+
'fee': fee,
|
|
849
1051
|
'trades': undefined,
|
|
850
|
-
|
|
1052
|
+
'info': order,
|
|
1053
|
+
}, market);
|
|
1054
|
+
}
|
|
1055
|
+
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
|
|
1056
|
+
/**
|
|
1057
|
+
* @method
|
|
1058
|
+
* @name cex#createOrder
|
|
1059
|
+
* @description create a trade order
|
|
1060
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-new-order
|
|
1061
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
1062
|
+
* @param {string} type 'market' or 'limit'
|
|
1063
|
+
* @param {string} side 'buy' or 'sell'
|
|
1064
|
+
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
1065
|
+
* @param {float} [price] the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
|
1066
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1067
|
+
* @param {string} [params.accountId] account-id to use (default is empty string)
|
|
1068
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1069
|
+
*/
|
|
1070
|
+
let accountId = undefined;
|
|
1071
|
+
[accountId, params] = this.handleOptionAndParams(params, 'createOrder', 'accountId');
|
|
1072
|
+
if (accountId === undefined) {
|
|
1073
|
+
throw new ArgumentsRequired(this.id + ' createOrder() : API trading is now allowed from main account, set params["accountId"] or .options["createOrder"]["accountId"] to the name of your sub-account');
|
|
1074
|
+
}
|
|
1075
|
+
await this.loadMarkets();
|
|
1076
|
+
const market = this.market(symbol);
|
|
1077
|
+
const request = {
|
|
1078
|
+
'clientOrderId': this.uuid(),
|
|
1079
|
+
'currency1': market['baseId'],
|
|
1080
|
+
'currency2': market['quoteId'],
|
|
1081
|
+
'accountId': accountId,
|
|
1082
|
+
'orderType': this.capitalize(type.toLowerCase()),
|
|
1083
|
+
'side': side.toUpperCase(),
|
|
1084
|
+
'timestamp': this.milliseconds(),
|
|
1085
|
+
'amountCcy1': this.amountToPrecision(symbol, amount),
|
|
1086
|
+
};
|
|
1087
|
+
let timeInForce = undefined;
|
|
1088
|
+
[timeInForce, params] = this.handleOptionAndParams(params, 'createOrder', 'timeInForce', 'GTC');
|
|
1089
|
+
if (type === 'limit') {
|
|
1090
|
+
request['price'] = this.priceToPrecision(symbol, price);
|
|
1091
|
+
request['timeInForce'] = timeInForce;
|
|
1092
|
+
}
|
|
1093
|
+
let triggerPrice = undefined;
|
|
1094
|
+
[triggerPrice, params] = this.handleParamString(params, 'triggerPrice');
|
|
1095
|
+
if (triggerPrice !== undefined) {
|
|
1096
|
+
request['type'] = 'Stop Limit';
|
|
1097
|
+
request['stopPrice'] = triggerPrice;
|
|
1098
|
+
}
|
|
1099
|
+
const response = await this.privatePostDoMyNewOrder(this.extend(request, params));
|
|
1100
|
+
//
|
|
1101
|
+
// on success
|
|
1102
|
+
//
|
|
1103
|
+
// {
|
|
1104
|
+
// "ok": "ok",
|
|
1105
|
+
// "data": {
|
|
1106
|
+
// "messageType": "executionReport",
|
|
1107
|
+
// "clientId": "up132245425",
|
|
1108
|
+
// "orderId": "1318485",
|
|
1109
|
+
// "clientOrderId": "b5b6cd40-154c-4c1c-bd51-4a442f3d50b9",
|
|
1110
|
+
// "accountId": "sub1",
|
|
1111
|
+
// "status": "FILLED",
|
|
1112
|
+
// "currency1": "LTC",
|
|
1113
|
+
// "currency2": "USDT",
|
|
1114
|
+
// "side": "BUY",
|
|
1115
|
+
// "executedAmountCcy1": "0.23000000",
|
|
1116
|
+
// "executedAmountCcy2": "15.09030000",
|
|
1117
|
+
// "requestedAmountCcy1": "0.23000000",
|
|
1118
|
+
// "requestedAmountCcy2": null,
|
|
1119
|
+
// "orderType": "Market",
|
|
1120
|
+
// "timeInForce": null,
|
|
1121
|
+
// "comment": null,
|
|
1122
|
+
// "executionType": "Trade",
|
|
1123
|
+
// "executionId": "1726747124624_101_41116",
|
|
1124
|
+
// "transactTime": "2024-10-15T15:08:12.794Z",
|
|
1125
|
+
// "expireTime": null,
|
|
1126
|
+
// "effectiveTime": null,
|
|
1127
|
+
// "averagePrice": "65.61",
|
|
1128
|
+
// "lastQuantity": "0.23000000",
|
|
1129
|
+
// "lastAmountCcy1": "0.23000000",
|
|
1130
|
+
// "lastAmountCcy2": "15.09030000",
|
|
1131
|
+
// "lastPrice": "65.61",
|
|
1132
|
+
// "feeAmount": "0.03772575",
|
|
1133
|
+
// "feeCurrency": "USDT",
|
|
1134
|
+
// "clientCreateTimestamp": "1729004892014",
|
|
1135
|
+
// "serverCreateTimestamp": "1729004891628",
|
|
1136
|
+
// "lastUpdateTimestamp": "1729004892786"
|
|
1137
|
+
// }
|
|
1138
|
+
// }
|
|
1139
|
+
//
|
|
1140
|
+
// on failure, there are extra fields
|
|
1141
|
+
//
|
|
1142
|
+
// "status": "REJECTED",
|
|
1143
|
+
// "requestedAmountCcy1": null,
|
|
1144
|
+
// "orderRejectReason": "{\\" code \\ ":405,\\" reason \\ ":\\" Either AmountCcy1(OrderQty)or AmountCcy2(CashOrderQty)should be specified for market order not both \\ "}",
|
|
1145
|
+
// "rejectCode": 405,
|
|
1146
|
+
// "rejectReason": "Either AmountCcy1 (OrderQty) or AmountCcy2 (CashOrderQty) should be specified for market order not both",
|
|
1147
|
+
//
|
|
1148
|
+
const data = this.safeDict(response, 'data');
|
|
1149
|
+
return this.parseOrder(data, market);
|
|
851
1150
|
}
|
|
852
1151
|
async cancelOrder(id, symbol = undefined, params = {}) {
|
|
853
1152
|
/**
|
|
854
1153
|
* @method
|
|
855
1154
|
* @name cex#cancelOrder
|
|
856
|
-
* @see https://docs.cex.io/#cancel-order
|
|
857
1155
|
* @description cancels an open order
|
|
1156
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-cancel-order
|
|
858
1157
|
* @param {string} id order id
|
|
859
|
-
* @param {string} symbol
|
|
1158
|
+
* @param {string} symbol unified symbol of the market the order was made in
|
|
860
1159
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
861
1160
|
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
862
1161
|
*/
|
|
863
1162
|
await this.loadMarkets();
|
|
864
1163
|
const request = {
|
|
865
|
-
'
|
|
1164
|
+
'orderId': parseInt(id),
|
|
1165
|
+
'cancelRequestId': 'c_' + (this.milliseconds()).toString(),
|
|
1166
|
+
'timestamp': this.milliseconds(),
|
|
866
1167
|
};
|
|
867
|
-
const response = await this.
|
|
868
|
-
//
|
|
869
|
-
|
|
1168
|
+
const response = await this.privatePostDoCancelMyOrder(this.extend(request, params));
|
|
1169
|
+
//
|
|
1170
|
+
// {"ok":"ok","data":{}}
|
|
1171
|
+
//
|
|
1172
|
+
const data = this.safeDict(response, 'data', {});
|
|
1173
|
+
return this.parseOrder(data);
|
|
870
1174
|
}
|
|
871
1175
|
async cancelAllOrders(symbol = undefined, params = {}) {
|
|
872
1176
|
/**
|
|
873
1177
|
* @method
|
|
874
1178
|
* @name cex#cancelAllOrders
|
|
875
|
-
* @see https://docs.cex.io/#cancel-all-orders-for-given-pair
|
|
876
1179
|
* @description cancel all open orders in a market
|
|
877
|
-
* @
|
|
878
|
-
* @param {
|
|
879
|
-
* @param {
|
|
1180
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-cancel-all-orders
|
|
1181
|
+
* @param {string} symbol alpaca cancelAllOrders cannot setting symbol, it will cancel all open orders
|
|
1182
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
880
1183
|
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
881
1184
|
*/
|
|
882
|
-
if (symbol === undefined) {
|
|
883
|
-
throw new ArgumentsRequired(this.id + ' cancelAllOrders requires a symbol.');
|
|
884
|
-
}
|
|
885
1185
|
await this.loadMarkets();
|
|
886
|
-
const
|
|
887
|
-
const request = {
|
|
888
|
-
'pair': market['id'],
|
|
889
|
-
};
|
|
890
|
-
const orders = await this.privatePostCancelOrdersPair(this.extend(request, params));
|
|
1186
|
+
const response = await this.privatePostDoCancelAllOrders(params);
|
|
891
1187
|
//
|
|
892
|
-
//
|
|
893
|
-
//
|
|
894
|
-
//
|
|
895
|
-
//
|
|
896
|
-
//
|
|
897
|
-
//
|
|
1188
|
+
// {
|
|
1189
|
+
// "ok": "ok",
|
|
1190
|
+
// "data": {
|
|
1191
|
+
// "clientOrderIds": [
|
|
1192
|
+
// "3AF77B67109F"
|
|
1193
|
+
// ]
|
|
1194
|
+
// }
|
|
1195
|
+
// }
|
|
898
1196
|
//
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
if (typeof timestamp === 'string' && timestamp.indexOf('T') >= 0) {
|
|
906
|
-
// ISO8601 string
|
|
907
|
-
timestamp = this.parse8601(timestamp);
|
|
1197
|
+
const data = this.safeDict(response, 'data', {});
|
|
1198
|
+
const ids = this.safeList(data, 'clientOrderIds', []);
|
|
1199
|
+
const orders = [];
|
|
1200
|
+
for (let i = 0; i < ids.length; i++) {
|
|
1201
|
+
const id = ids[i];
|
|
1202
|
+
orders.push({ 'clientOrderId': id });
|
|
908
1203
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
1204
|
+
return this.parseOrders(orders);
|
|
1205
|
+
}
|
|
1206
|
+
async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1207
|
+
/**
|
|
1208
|
+
* @method
|
|
1209
|
+
* @name cex#fetchLedger
|
|
1210
|
+
* @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
|
|
1211
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-transaction-history
|
|
1212
|
+
* @param {string} [code] unified currency code
|
|
1213
|
+
* @param {int} [since] timestamp in ms of the earliest ledger entry
|
|
1214
|
+
* @param {int} [limit] max number of ledger entries to return
|
|
1215
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1216
|
+
* @param {int} [params.until] timestamp in ms of the latest ledger entry
|
|
1217
|
+
* @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger-structure}
|
|
1218
|
+
*/
|
|
1219
|
+
await this.loadMarkets();
|
|
1220
|
+
let currency = undefined;
|
|
1221
|
+
const request = {};
|
|
1222
|
+
if (code !== undefined) {
|
|
1223
|
+
currency = this.currency(code);
|
|
1224
|
+
request['currency'] = currency['id'];
|
|
925
1225
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
let amount = this.omitZero(this.safeString(order, 'amount'));
|
|
929
|
-
// sell orders can have a negative amount
|
|
930
|
-
// https://github.com/ccxt/ccxt/issues/5338
|
|
931
|
-
if (amount !== undefined) {
|
|
932
|
-
amount = Precise.stringAbs(amount);
|
|
1226
|
+
if (since !== undefined) {
|
|
1227
|
+
request['dateFrom'] = since;
|
|
933
1228
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
amount = Precise.stringAbs(this.safeString(order, amountKey));
|
|
1229
|
+
if (limit !== undefined) {
|
|
1230
|
+
request['pageSize'] = limit;
|
|
937
1231
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
if (market !== undefined) {
|
|
943
|
-
symbol = market['symbol'];
|
|
944
|
-
const taCost = this.safeString(order, 'ta:' + market['quote']);
|
|
945
|
-
const ttaCost = this.safeString(order, 'tta:' + market['quote']);
|
|
946
|
-
cost = Precise.stringAdd(taCost, ttaCost);
|
|
947
|
-
const baseFee = 'fa:' + market['base'];
|
|
948
|
-
const baseTakerFee = 'tfa:' + market['base'];
|
|
949
|
-
const quoteFee = 'fa:' + market['quote'];
|
|
950
|
-
const quoteTakerFee = 'tfa:' + market['quote'];
|
|
951
|
-
let feeRate = this.safeString(order, 'tradingFeeMaker');
|
|
952
|
-
if (!feeRate) {
|
|
953
|
-
feeRate = this.safeString(order, 'tradingFeeTaker', feeRate);
|
|
954
|
-
}
|
|
955
|
-
if (feeRate) {
|
|
956
|
-
feeRate = Precise.stringDiv(feeRate, '100'); // convert to mathematically-correct percentage coefficients: 1.0 = 100%
|
|
957
|
-
}
|
|
958
|
-
if ((baseFee in order) || (baseTakerFee in order)) {
|
|
959
|
-
const baseFeeCost = this.safeNumber2(order, baseFee, baseTakerFee);
|
|
960
|
-
fee = {
|
|
961
|
-
'currency': market['base'],
|
|
962
|
-
'rate': this.parseNumber(feeRate),
|
|
963
|
-
'cost': baseFeeCost,
|
|
964
|
-
};
|
|
965
|
-
}
|
|
966
|
-
else if ((quoteFee in order) || (quoteTakerFee in order)) {
|
|
967
|
-
const quoteFeeCost = this.safeNumber2(order, quoteFee, quoteTakerFee);
|
|
968
|
-
fee = {
|
|
969
|
-
'currency': market['quote'],
|
|
970
|
-
'rate': this.parseNumber(feeRate),
|
|
971
|
-
'cost': quoteFeeCost,
|
|
972
|
-
};
|
|
973
|
-
}
|
|
1232
|
+
let until = undefined;
|
|
1233
|
+
[until, params] = this.handleParamInteger2(params, 'until', 'till');
|
|
1234
|
+
if (until !== undefined) {
|
|
1235
|
+
request['dateTo'] = until;
|
|
974
1236
|
}
|
|
975
|
-
|
|
976
|
-
|
|
1237
|
+
const response = await this.privatePostGetMyTransactionHistory(this.extend(request, params));
|
|
1238
|
+
//
|
|
1239
|
+
// {
|
|
1240
|
+
// "ok": "ok",
|
|
1241
|
+
// "data": [
|
|
1242
|
+
// {
|
|
1243
|
+
// "transactionId": "30367722",
|
|
1244
|
+
// "timestamp": "2024-10-14T14:08:49.987Z",
|
|
1245
|
+
// "accountId": "",
|
|
1246
|
+
// "type": "withdraw",
|
|
1247
|
+
// "amount": "-12.39060600",
|
|
1248
|
+
// "details": "Withdraw fundingId=1235039 clientId=up421412345 walletTxId=76337154166",
|
|
1249
|
+
// "currency": "USDT"
|
|
1250
|
+
// },
|
|
1251
|
+
// ...
|
|
1252
|
+
//
|
|
1253
|
+
const data = this.safeList(response, 'data', []);
|
|
1254
|
+
return this.parseLedger(data, currency, since, limit);
|
|
1255
|
+
}
|
|
1256
|
+
parseLedgerEntry(item, currency = undefined) {
|
|
1257
|
+
let amount = this.safeString(item, 'amount');
|
|
1258
|
+
let direction = undefined;
|
|
1259
|
+
if (Precise.stringLe(amount, '0')) {
|
|
1260
|
+
direction = 'out';
|
|
1261
|
+
amount = Precise.stringMul('-1', amount);
|
|
977
1262
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
const orderId = this.safeString(order, 'id');
|
|
981
|
-
if ('vtx' in order) {
|
|
982
|
-
trades = [];
|
|
983
|
-
for (let i = 0; i < order['vtx'].length; i++) {
|
|
984
|
-
const item = order['vtx'][i];
|
|
985
|
-
const tradeSide = this.safeString(item, 'type');
|
|
986
|
-
if (tradeSide === 'cancel') {
|
|
987
|
-
// looks like this might represent the cancelled part of an order
|
|
988
|
-
// { "id": "4426729543",
|
|
989
|
-
// "type": "cancel",
|
|
990
|
-
// "time": "2017-09-22T00:24:30.476Z",
|
|
991
|
-
// "user": "up106404164",
|
|
992
|
-
// "c": "user:up106404164:a:BCH",
|
|
993
|
-
// "d": "order:4426728375:a:BCH",
|
|
994
|
-
// "a": "0.09935956",
|
|
995
|
-
// "amount": "0.09935956",
|
|
996
|
-
// "balance": "0.42580261",
|
|
997
|
-
// "symbol": "BCH",
|
|
998
|
-
// "order": "4426728375",
|
|
999
|
-
// "buy": null,
|
|
1000
|
-
// "sell": null,
|
|
1001
|
-
// "pair": null,
|
|
1002
|
-
// "pos": null,
|
|
1003
|
-
// "cs": "0.42580261",
|
|
1004
|
-
// "ds": 0 }
|
|
1005
|
-
continue;
|
|
1006
|
-
}
|
|
1007
|
-
const tradePrice = this.safeString(item, 'price');
|
|
1008
|
-
if (tradePrice === undefined) {
|
|
1009
|
-
// this represents the order
|
|
1010
|
-
// {
|
|
1011
|
-
// "a": "0.47000000",
|
|
1012
|
-
// "c": "user:up106404164:a:EUR",
|
|
1013
|
-
// "d": "order:6065499239:a:EUR",
|
|
1014
|
-
// "cs": "1432.93",
|
|
1015
|
-
// "ds": "476.72",
|
|
1016
|
-
// "id": "6065499249",
|
|
1017
|
-
// "buy": null,
|
|
1018
|
-
// "pos": null,
|
|
1019
|
-
// "pair": null,
|
|
1020
|
-
// "sell": null,
|
|
1021
|
-
// "time": "2018-04-22T13:07:22.152Z",
|
|
1022
|
-
// "type": "buy",
|
|
1023
|
-
// "user": "up106404164",
|
|
1024
|
-
// "order": "6065499239",
|
|
1025
|
-
// "amount": "-715.97000000",
|
|
1026
|
-
// "symbol": "EUR",
|
|
1027
|
-
// "balance": "1432.93000000" }
|
|
1028
|
-
continue;
|
|
1029
|
-
}
|
|
1030
|
-
// todo: deal with these
|
|
1031
|
-
if (tradeSide === 'costsNothing') {
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
// --
|
|
1035
|
-
// if (side !== tradeSide)
|
|
1036
|
-
// throw new Error (JSON.stringify (order, null, 2));
|
|
1037
|
-
// if (orderId !== item['order'])
|
|
1038
|
-
// throw new Error (JSON.stringify (order, null, 2));
|
|
1039
|
-
// --
|
|
1040
|
-
// partial buy trade
|
|
1041
|
-
// {
|
|
1042
|
-
// "a": "0.01589885",
|
|
1043
|
-
// "c": "user:up106404164:a:BTC",
|
|
1044
|
-
// "d": "order:6065499239:a:BTC",
|
|
1045
|
-
// "cs": "0.36300000",
|
|
1046
|
-
// "ds": 0,
|
|
1047
|
-
// "id": "6067991213",
|
|
1048
|
-
// "buy": "6065499239",
|
|
1049
|
-
// "pos": null,
|
|
1050
|
-
// "pair": null,
|
|
1051
|
-
// "sell": "6067991206",
|
|
1052
|
-
// "time": "2018-04-22T23:09:11.773Z",
|
|
1053
|
-
// "type": "buy",
|
|
1054
|
-
// "user": "up106404164",
|
|
1055
|
-
// "order": "6065499239",
|
|
1056
|
-
// "price": 7146.5,
|
|
1057
|
-
// "amount": "0.01589885",
|
|
1058
|
-
// "symbol": "BTC",
|
|
1059
|
-
// "balance": "0.36300000",
|
|
1060
|
-
// "symbol2": "EUR",
|
|
1061
|
-
// "fee_amount": "0.19" }
|
|
1062
|
-
// --
|
|
1063
|
-
// trade with zero amount, but non-zero fee
|
|
1064
|
-
// {
|
|
1065
|
-
// "a": "0.00000000",
|
|
1066
|
-
// "c": "user:up106404164:a:EUR",
|
|
1067
|
-
// "d": "order:5840654423:a:EUR",
|
|
1068
|
-
// "cs": 559744,
|
|
1069
|
-
// "ds": 0,
|
|
1070
|
-
// "id": "5840654429",
|
|
1071
|
-
// "buy": "5807238573",
|
|
1072
|
-
// "pos": null,
|
|
1073
|
-
// "pair": null,
|
|
1074
|
-
// "sell": "5840654423",
|
|
1075
|
-
// "time": "2018-03-15T03:20:14.010Z",
|
|
1076
|
-
// "type": "sell",
|
|
1077
|
-
// "user": "up106404164",
|
|
1078
|
-
// "order": "5840654423",
|
|
1079
|
-
// "price": 730,
|
|
1080
|
-
// "amount": "0.00000000",
|
|
1081
|
-
// "symbol": "EUR",
|
|
1082
|
-
// "balance": "5597.44000000",
|
|
1083
|
-
// "symbol2": "BCH",
|
|
1084
|
-
// "fee_amount": "0.01" }
|
|
1085
|
-
// --
|
|
1086
|
-
// trade which should have an amount of exactly 0.002BTC
|
|
1087
|
-
// {
|
|
1088
|
-
// "a": "16.70000000",
|
|
1089
|
-
// "c": "user:up106404164:a:GBP",
|
|
1090
|
-
// "d": "order:9927386681:a:GBP",
|
|
1091
|
-
// "cs": "86.90",
|
|
1092
|
-
// "ds": 0,
|
|
1093
|
-
// "id": "9927401610",
|
|
1094
|
-
// "buy": "9927401601",
|
|
1095
|
-
// "pos": null,
|
|
1096
|
-
// "pair": null,
|
|
1097
|
-
// "sell": "9927386681",
|
|
1098
|
-
// "time": "2019-08-21T15:25:37.777Z",
|
|
1099
|
-
// "type": "sell",
|
|
1100
|
-
// "user": "up106404164",
|
|
1101
|
-
// "order": "9927386681",
|
|
1102
|
-
// "price": 8365,
|
|
1103
|
-
// "amount": "16.70000000",
|
|
1104
|
-
// "office": "UK",
|
|
1105
|
-
// "symbol": "GBP",
|
|
1106
|
-
// "balance": "86.90000000",
|
|
1107
|
-
// "symbol2": "BTC",
|
|
1108
|
-
// "fee_amount": "0.03"
|
|
1109
|
-
// }
|
|
1110
|
-
const tradeTimestamp = this.parse8601(this.safeString(item, 'time'));
|
|
1111
|
-
const tradeAmount = this.safeString(item, 'amount');
|
|
1112
|
-
const feeCost = this.safeString(item, 'fee_amount');
|
|
1113
|
-
let absTradeAmount = Precise.stringAbs(tradeAmount);
|
|
1114
|
-
let tradeCost = undefined;
|
|
1115
|
-
if (tradeSide === 'sell') {
|
|
1116
|
-
tradeCost = absTradeAmount;
|
|
1117
|
-
absTradeAmount = Precise.stringDiv(Precise.stringAdd(feeCost, tradeCost), tradePrice);
|
|
1118
|
-
}
|
|
1119
|
-
else {
|
|
1120
|
-
tradeCost = Precise.stringMul(absTradeAmount, tradePrice);
|
|
1121
|
-
}
|
|
1122
|
-
trades.push({
|
|
1123
|
-
'id': this.safeString(item, 'id'),
|
|
1124
|
-
'timestamp': tradeTimestamp,
|
|
1125
|
-
'datetime': this.iso8601(tradeTimestamp),
|
|
1126
|
-
'order': orderId,
|
|
1127
|
-
'symbol': symbol,
|
|
1128
|
-
'price': this.parseNumber(tradePrice),
|
|
1129
|
-
'amount': this.parseNumber(absTradeAmount),
|
|
1130
|
-
'cost': this.parseNumber(tradeCost),
|
|
1131
|
-
'side': tradeSide,
|
|
1132
|
-
'fee': {
|
|
1133
|
-
'cost': this.parseNumber(feeCost),
|
|
1134
|
-
'currency': market['quote'],
|
|
1135
|
-
},
|
|
1136
|
-
'info': item,
|
|
1137
|
-
'type': undefined,
|
|
1138
|
-
'takerOrMaker': undefined,
|
|
1139
|
-
});
|
|
1140
|
-
}
|
|
1263
|
+
else {
|
|
1264
|
+
direction = 'in';
|
|
1141
1265
|
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1266
|
+
const currencyId = this.safeString(item, 'currency');
|
|
1267
|
+
currency = this.safeCurrency(currencyId, currency);
|
|
1268
|
+
const code = this.safeCurrencyCode(currencyId, currency);
|
|
1269
|
+
const timestampString = this.safeString(item, 'timestamp');
|
|
1270
|
+
const timestamp = this.parse8601(timestampString);
|
|
1271
|
+
const type = this.safeString(item, 'type');
|
|
1272
|
+
return this.safeLedgerEntry({
|
|
1273
|
+
'info': item,
|
|
1274
|
+
'id': this.safeString(item, 'transactionId'),
|
|
1275
|
+
'direction': direction,
|
|
1276
|
+
'account': this.safeString(item, 'accountId', ''),
|
|
1277
|
+
'referenceAccount': undefined,
|
|
1278
|
+
'referenceId': undefined,
|
|
1279
|
+
'type': this.parseLedgerEntryType(type),
|
|
1280
|
+
'currency': code,
|
|
1281
|
+
'amount': this.parseNumber(amount),
|
|
1147
1282
|
'timestamp': timestamp,
|
|
1148
|
-
'
|
|
1149
|
-
'
|
|
1150
|
-
'
|
|
1151
|
-
'
|
|
1152
|
-
'
|
|
1153
|
-
|
|
1154
|
-
'side': side,
|
|
1155
|
-
'price': price,
|
|
1156
|
-
'stopPrice': undefined,
|
|
1157
|
-
'triggerPrice': undefined,
|
|
1158
|
-
'cost': cost,
|
|
1159
|
-
'amount': amount,
|
|
1160
|
-
'filled': filled,
|
|
1161
|
-
'remaining': remaining,
|
|
1162
|
-
'trades': trades,
|
|
1163
|
-
'fee': fee,
|
|
1164
|
-
'average': undefined,
|
|
1165
|
-
});
|
|
1283
|
+
'datetime': this.iso8601(timestamp),
|
|
1284
|
+
'before': undefined,
|
|
1285
|
+
'after': undefined,
|
|
1286
|
+
'status': undefined,
|
|
1287
|
+
'fee': undefined,
|
|
1288
|
+
}, currency);
|
|
1166
1289
|
}
|
|
1167
|
-
|
|
1290
|
+
parseLedgerEntryType(type) {
|
|
1291
|
+
const ledgerType = {
|
|
1292
|
+
'deposit': 'deposit',
|
|
1293
|
+
'withdraw': 'withdrawal',
|
|
1294
|
+
'commission': 'fee',
|
|
1295
|
+
};
|
|
1296
|
+
return this.safeString(ledgerType, type, type);
|
|
1297
|
+
}
|
|
1298
|
+
async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1168
1299
|
/**
|
|
1169
1300
|
* @method
|
|
1170
|
-
* @name cex#
|
|
1171
|
-
* @
|
|
1172
|
-
* @
|
|
1173
|
-
* @param {string}
|
|
1174
|
-
* @param {int} [since]
|
|
1175
|
-
* @param {int} [limit]
|
|
1301
|
+
* @name cex#fetchDepositsWithdrawals
|
|
1302
|
+
* @description fetch history of deposits and withdrawals
|
|
1303
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-funding-history
|
|
1304
|
+
* @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined
|
|
1305
|
+
* @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined
|
|
1306
|
+
* @param {int} [limit] max number of deposit/withdrawals to return, default is undefined
|
|
1176
1307
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1177
|
-
* @returns {
|
|
1308
|
+
* @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
1178
1309
|
*/
|
|
1179
1310
|
await this.loadMarkets();
|
|
1180
1311
|
const request = {};
|
|
1181
|
-
let
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
market = this.market(symbol);
|
|
1185
|
-
request['pair'] = market['id'];
|
|
1186
|
-
orders = await this.privatePostOpenOrdersPair(this.extend(request, params));
|
|
1312
|
+
let currency = undefined;
|
|
1313
|
+
if (code !== undefined) {
|
|
1314
|
+
currency = this.currency(code);
|
|
1187
1315
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1316
|
+
if (since !== undefined) {
|
|
1317
|
+
request['dateFrom'] = since;
|
|
1318
|
+
}
|
|
1319
|
+
if (limit !== undefined) {
|
|
1320
|
+
request['pageSize'] = limit;
|
|
1190
1321
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1322
|
+
let until = undefined;
|
|
1323
|
+
[until, params] = this.handleParamInteger2(params, 'until', 'till');
|
|
1324
|
+
if (until !== undefined) {
|
|
1325
|
+
request['dateTo'] = until;
|
|
1193
1326
|
}
|
|
1194
|
-
|
|
1327
|
+
const response = await this.privatePostGetMyFundingHistory(this.extend(request, params));
|
|
1328
|
+
//
|
|
1329
|
+
// {
|
|
1330
|
+
// "ok": "ok",
|
|
1331
|
+
// "data": [
|
|
1332
|
+
// {
|
|
1333
|
+
// "clientId": "up421412345",
|
|
1334
|
+
// "accountId": "",
|
|
1335
|
+
// "currency": "USDT",
|
|
1336
|
+
// "direction": "withdraw",
|
|
1337
|
+
// "amount": "12.39060600",
|
|
1338
|
+
// "commissionAmount": "0.00000000",
|
|
1339
|
+
// "status": "approved",
|
|
1340
|
+
// "updatedAt": "2024-10-14T14:08:50.013Z",
|
|
1341
|
+
// "txId": "30367718",
|
|
1342
|
+
// "details": {}
|
|
1343
|
+
// },
|
|
1344
|
+
// ...
|
|
1345
|
+
//
|
|
1346
|
+
const data = this.safeList(response, 'data', []);
|
|
1347
|
+
return this.parseTransactions(data, currency, since, limit);
|
|
1195
1348
|
}
|
|
1196
|
-
|
|
1349
|
+
parseTransaction(transaction, currency = undefined) {
|
|
1350
|
+
const currencyId = this.safeString(transaction, 'currency');
|
|
1351
|
+
const direction = this.safeString(transaction, 'direction');
|
|
1352
|
+
const type = (direction === 'withdraw') ? 'withdrawal' : 'deposit';
|
|
1353
|
+
const code = this.safeCurrencyCode(currencyId, currency);
|
|
1354
|
+
const updatedAt = this.safeString(transaction, 'updatedAt');
|
|
1355
|
+
const timestamp = this.parse8601(updatedAt);
|
|
1356
|
+
return {
|
|
1357
|
+
'info': transaction,
|
|
1358
|
+
'id': this.safeString(transaction, 'txId'),
|
|
1359
|
+
'txid': undefined,
|
|
1360
|
+
'type': type,
|
|
1361
|
+
'currency': code,
|
|
1362
|
+
'network': undefined,
|
|
1363
|
+
'amount': this.safeNumber(transaction, 'amount'),
|
|
1364
|
+
'status': this.parseTransactionStatus(this.safeString(transaction, 'status')),
|
|
1365
|
+
'timestamp': timestamp,
|
|
1366
|
+
'datetime': this.iso8601(timestamp),
|
|
1367
|
+
'address': undefined,
|
|
1368
|
+
'addressFrom': undefined,
|
|
1369
|
+
'addressTo': undefined,
|
|
1370
|
+
'tag': undefined,
|
|
1371
|
+
'tagFrom': undefined,
|
|
1372
|
+
'tagTo': undefined,
|
|
1373
|
+
'updated': undefined,
|
|
1374
|
+
'comment': undefined,
|
|
1375
|
+
'fee': {
|
|
1376
|
+
'currency': code,
|
|
1377
|
+
'cost': this.safeNumber(transaction, 'commissionAmount'),
|
|
1378
|
+
},
|
|
1379
|
+
'internal': undefined,
|
|
1380
|
+
};
|
|
1381
|
+
}
|
|
1382
|
+
parseTransactionStatus(status) {
|
|
1383
|
+
const statuses = {
|
|
1384
|
+
'rejected': 'rejected',
|
|
1385
|
+
'pending': 'pending',
|
|
1386
|
+
'approved': 'ok',
|
|
1387
|
+
};
|
|
1388
|
+
return this.safeString(statuses, status, status);
|
|
1389
|
+
}
|
|
1390
|
+
async transfer(code, amount, fromAccount, toAccount, params = {}) {
|
|
1197
1391
|
/**
|
|
1198
1392
|
* @method
|
|
1199
|
-
* @name cex#
|
|
1200
|
-
* @
|
|
1201
|
-
* @
|
|
1202
|
-
* @param {string}
|
|
1203
|
-
* @param {
|
|
1204
|
-
* @param {
|
|
1393
|
+
* @name cex#transfer
|
|
1394
|
+
* @description transfer currency internally between wallets on the same account
|
|
1395
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-internal-transfer
|
|
1396
|
+
* @param {string} code unified currency code
|
|
1397
|
+
* @param {float} amount amount to transfer
|
|
1398
|
+
* @param {string} fromAccount 'SPOT', 'FUND', or 'CONTRACT'
|
|
1399
|
+
* @param {string} toAccount 'SPOT', 'FUND', or 'CONTRACT'
|
|
1205
1400
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1206
|
-
* @returns {
|
|
1401
|
+
* @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
|
|
1207
1402
|
*/
|
|
1208
|
-
|
|
1209
|
-
|
|
1403
|
+
let transfer = undefined;
|
|
1404
|
+
if (toAccount !== '' && fromAccount !== '') {
|
|
1405
|
+
transfer = await this.transferBetweenSubAccounts(code, amount, fromAccount, toAccount, params);
|
|
1210
1406
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1407
|
+
else {
|
|
1408
|
+
transfer = await this.transferBetweenMainAndSubAccount(code, amount, fromAccount, toAccount, params);
|
|
1409
|
+
}
|
|
1410
|
+
const fillResponseFromRequest = this.handleOption('transfer', 'fillResponseFromRequest', true);
|
|
1411
|
+
if (fillResponseFromRequest) {
|
|
1412
|
+
transfer['fromAccount'] = fromAccount;
|
|
1413
|
+
transfer['toAccount'] = toAccount;
|
|
1414
|
+
}
|
|
1415
|
+
return transfer;
|
|
1216
1416
|
}
|
|
1217
|
-
async
|
|
1218
|
-
/**
|
|
1219
|
-
* @method
|
|
1220
|
-
* @name cex#fetchOrder
|
|
1221
|
-
* @see https://docs.cex.io/?python#get-order-details
|
|
1222
|
-
* @description fetches information on an order made by the user
|
|
1223
|
-
* @param {string} id the order id
|
|
1224
|
-
* @param {string} symbol not used by cex fetchOrder
|
|
1225
|
-
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1226
|
-
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1227
|
-
*/
|
|
1417
|
+
async transferBetweenMainAndSubAccount(code, amount, fromAccount, toAccount, params = {}) {
|
|
1228
1418
|
await this.loadMarkets();
|
|
1419
|
+
const currency = this.currency(code);
|
|
1420
|
+
const fromMain = (fromAccount === '');
|
|
1421
|
+
const targetAccount = fromMain ? toAccount : fromAccount;
|
|
1422
|
+
const guid = this.safeString(params, 'guid', this.uuid());
|
|
1229
1423
|
const request = {
|
|
1230
|
-
'
|
|
1424
|
+
'currency': currency['id'],
|
|
1425
|
+
'amount': this.currencyToPrecision(code, amount),
|
|
1426
|
+
'accountId': targetAccount,
|
|
1427
|
+
'clientTxId': guid,
|
|
1231
1428
|
};
|
|
1232
|
-
|
|
1233
|
-
|
|
1429
|
+
let response = undefined;
|
|
1430
|
+
if (fromMain) {
|
|
1431
|
+
response = await this.privatePostDoDepositFundsFromWallet(this.extend(request, params));
|
|
1432
|
+
}
|
|
1433
|
+
else {
|
|
1434
|
+
response = await this.privatePostDoWithdrawalFundsToWallet(this.extend(request, params));
|
|
1435
|
+
}
|
|
1436
|
+
// both endpoints return the same structure, the only difference is that
|
|
1437
|
+
// the "accountId" is filled with the "subAccount"
|
|
1234
1438
|
//
|
|
1235
1439
|
// {
|
|
1236
|
-
// "
|
|
1237
|
-
// "
|
|
1238
|
-
//
|
|
1239
|
-
//
|
|
1240
|
-
//
|
|
1241
|
-
//
|
|
1242
|
-
//
|
|
1243
|
-
// "status": "d",
|
|
1244
|
-
// "symbol1": "ETH",
|
|
1245
|
-
// "symbol2": "EUR",
|
|
1246
|
-
// "amount": "0.50000000",
|
|
1247
|
-
// "kind": "api",
|
|
1248
|
-
// "price": "923.3386",
|
|
1249
|
-
// "tfacf": "1",
|
|
1250
|
-
// "fa:EUR": "0.55",
|
|
1251
|
-
// "ta:EUR": "369.77",
|
|
1252
|
-
// "remains": "0.00000000",
|
|
1253
|
-
// "tfa:EUR": "0.22",
|
|
1254
|
-
// "tta:EUR": "91.95",
|
|
1255
|
-
// "a:ETH:cds": "0.50000000",
|
|
1256
|
-
// "a:EUR:cds": "461.72",
|
|
1257
|
-
// "f:EUR:cds": "0.77",
|
|
1258
|
-
// "tradingFeeMaker": "0.15",
|
|
1259
|
-
// "tradingFeeTaker": "0.23",
|
|
1260
|
-
// "tradingFeeStrategy": "userVolumeAmount",
|
|
1261
|
-
// "tradingFeeUserVolumeAmount": "2896912572",
|
|
1262
|
-
// "orderId": "5442731603",
|
|
1263
|
-
// "next": false,
|
|
1264
|
-
// "vtx": [
|
|
1265
|
-
// {
|
|
1266
|
-
// "id": "5442734452",
|
|
1267
|
-
// "type": "sell",
|
|
1268
|
-
// "time": "2018-01-16T19:52:58.452Z",
|
|
1269
|
-
// "user": "up106404164",
|
|
1270
|
-
// "c": "user:up106404164:a:EUR",
|
|
1271
|
-
// "d": "order:5442731603:a:EUR",
|
|
1272
|
-
// "a": "104.53000000",
|
|
1273
|
-
// "amount": "104.53000000",
|
|
1274
|
-
// "balance": "932.71000000",
|
|
1275
|
-
// "symbol": "EUR",
|
|
1276
|
-
// "order": "5442731603",
|
|
1277
|
-
// "buy": "5442734443",
|
|
1278
|
-
// "sell": "5442731603",
|
|
1279
|
-
// "pair": null,
|
|
1280
|
-
// "pos": null,
|
|
1281
|
-
// "office": null,
|
|
1282
|
-
// "cs": "932.71",
|
|
1283
|
-
// "ds": 0,
|
|
1284
|
-
// "price": 923.3386,
|
|
1285
|
-
// "symbol2": "ETH",
|
|
1286
|
-
// "fee_amount": "0.16"
|
|
1287
|
-
// },
|
|
1288
|
-
// {
|
|
1289
|
-
// "id": "5442731609",
|
|
1290
|
-
// "type": "sell",
|
|
1291
|
-
// "time": "2018-01-16T19:52:38.071Z",
|
|
1292
|
-
// "user": "up106404164",
|
|
1293
|
-
// "c": "user:up106404164:a:EUR",
|
|
1294
|
-
// "d": "order:5442731603:a:EUR",
|
|
1295
|
-
// "a": "91.73000000",
|
|
1296
|
-
// "amount": "91.73000000",
|
|
1297
|
-
// "balance": "563.49000000",
|
|
1298
|
-
// "symbol": "EUR",
|
|
1299
|
-
// "order": "5442731603",
|
|
1300
|
-
// "buy": "5442618127",
|
|
1301
|
-
// "sell": "5442731603",
|
|
1302
|
-
// "pair": null,
|
|
1303
|
-
// "pos": null,
|
|
1304
|
-
// "office": null,
|
|
1305
|
-
// "cs": "563.49",
|
|
1306
|
-
// "ds": 0,
|
|
1307
|
-
// "price": 924.0092,
|
|
1308
|
-
// "symbol2": "ETH",
|
|
1309
|
-
// "fee_amount": "0.22"
|
|
1310
|
-
// },
|
|
1311
|
-
// {
|
|
1312
|
-
// "id": "5442731604",
|
|
1313
|
-
// "type": "sell",
|
|
1314
|
-
// "time": "2018-01-16T19:52:38.071Z",
|
|
1315
|
-
// "user": "up106404164",
|
|
1316
|
-
// "c": "order:5442731603:a:ETH",
|
|
1317
|
-
// "d": "user:up106404164:a:ETH",
|
|
1318
|
-
// "a": "0.50000000",
|
|
1319
|
-
// "amount": "-0.50000000",
|
|
1320
|
-
// "balance": "15.80995000",
|
|
1321
|
-
// "symbol": "ETH",
|
|
1322
|
-
// "order": "5442731603",
|
|
1323
|
-
// "buy": null,
|
|
1324
|
-
// "sell": null,
|
|
1325
|
-
// "pair": null,
|
|
1326
|
-
// "pos": null,
|
|
1327
|
-
// "office": null,
|
|
1328
|
-
// "cs": "0.50000000",
|
|
1329
|
-
// "ds": "15.80995000"
|
|
1330
|
-
// }
|
|
1331
|
-
// ]
|
|
1440
|
+
// "ok": "ok",
|
|
1441
|
+
// "data": {
|
|
1442
|
+
// "accountId": "sub1",
|
|
1443
|
+
// "clientTxId": "27ba8284-67cf-4386-9ec7-80b3871abd45",
|
|
1444
|
+
// "currency": "USDT",
|
|
1445
|
+
// "status": "approved"
|
|
1446
|
+
// }
|
|
1332
1447
|
// }
|
|
1333
1448
|
//
|
|
1334
|
-
|
|
1449
|
+
const data = this.safeDict(response, 'data', {});
|
|
1450
|
+
return this.parseTransfer(data, currency);
|
|
1335
1451
|
}
|
|
1336
|
-
async
|
|
1337
|
-
/**
|
|
1338
|
-
* @method
|
|
1339
|
-
* @name cex#fetchOrders
|
|
1340
|
-
* @see https://docs.cex.io/#archived-orders
|
|
1341
|
-
* @description fetches information on multiple orders made by the user
|
|
1342
|
-
* @param {string} symbol unified market symbol of the market orders were made in
|
|
1343
|
-
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
1344
|
-
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
1345
|
-
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1346
|
-
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1347
|
-
*/
|
|
1452
|
+
async transferBetweenSubAccounts(code, amount, fromAccount, toAccount, params = {}) {
|
|
1348
1453
|
await this.loadMarkets();
|
|
1349
|
-
const
|
|
1454
|
+
const currency = this.currency(code);
|
|
1350
1455
|
const request = {
|
|
1351
|
-
'
|
|
1352
|
-
'
|
|
1353
|
-
'
|
|
1456
|
+
'currency': currency['id'],
|
|
1457
|
+
'amount': this.currencyToPrecision(code, amount),
|
|
1458
|
+
'fromAccountId': fromAccount,
|
|
1459
|
+
'toAccountId': toAccount,
|
|
1354
1460
|
};
|
|
1355
|
-
const response = await this.
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
// "symbol1": "ETH",
|
|
1367
|
-
// "symbol2": "GBP",
|
|
1368
|
-
// "amount": "0.20000000",
|
|
1369
|
-
// "price": "200.5625",
|
|
1370
|
-
// "remains": "0.20000000",
|
|
1371
|
-
// 'a:ETH:cds': "0.20000000",
|
|
1372
|
-
// "tradingFeeMaker": "0",
|
|
1373
|
-
// "tradingFeeTaker": "0.16",
|
|
1374
|
-
// "tradingFeeUserVolumeAmount": "10155061217",
|
|
1375
|
-
// "orderId": "4005785516" }
|
|
1376
|
-
// --
|
|
1377
|
-
// cancelled (partially filled buy):
|
|
1378
|
-
// { "id": "4084911657",
|
|
1379
|
-
// "type": "buy",
|
|
1380
|
-
// "time": "2017-08-05T03:18:39.596Z",
|
|
1381
|
-
// "lastTxTime": "2019-03-19T17:37:46.404Z",
|
|
1382
|
-
// "lastTx": "8459265833",
|
|
1383
|
-
// "pos": null,
|
|
1384
|
-
// "status": "cd",
|
|
1385
|
-
// "symbol1": "BTC",
|
|
1386
|
-
// "symbol2": "GBP",
|
|
1387
|
-
// "amount": "0.05000000",
|
|
1388
|
-
// "price": "2241.4692",
|
|
1389
|
-
// "tfacf": "1",
|
|
1390
|
-
// "remains": "0.03910535",
|
|
1391
|
-
// 'tfa:GBP': "0.04",
|
|
1392
|
-
// 'tta:GBP': "24.39",
|
|
1393
|
-
// 'a:BTC:cds': "0.01089465",
|
|
1394
|
-
// 'a:GBP:cds': "112.26",
|
|
1395
|
-
// 'f:GBP:cds': "0.04",
|
|
1396
|
-
// "tradingFeeMaker": "0",
|
|
1397
|
-
// "tradingFeeTaker": "0.16",
|
|
1398
|
-
// "tradingFeeUserVolumeAmount": "13336396963",
|
|
1399
|
-
// "orderId": "4084911657" }
|
|
1400
|
-
// --
|
|
1401
|
-
// cancelled (partially filled sell):
|
|
1402
|
-
// { "id": "4426728375",
|
|
1403
|
-
// "type": "sell",
|
|
1404
|
-
// "time": "2017-09-22T00:24:20.126Z",
|
|
1405
|
-
// "lastTxTime": "2017-09-22T00:24:30.476Z",
|
|
1406
|
-
// "lastTx": "4426729543",
|
|
1407
|
-
// "pos": null,
|
|
1408
|
-
// "status": "cd",
|
|
1409
|
-
// "symbol1": "BCH",
|
|
1410
|
-
// "symbol2": "BTC",
|
|
1411
|
-
// "amount": "0.10000000",
|
|
1412
|
-
// "price": "0.11757182",
|
|
1413
|
-
// "tfacf": "1",
|
|
1414
|
-
// "remains": "0.09935956",
|
|
1415
|
-
// 'tfa:BTC': "0.00000014",
|
|
1416
|
-
// 'tta:BTC': "0.00007537",
|
|
1417
|
-
// 'a:BCH:cds': "0.10000000",
|
|
1418
|
-
// 'a:BTC:cds': "0.00007537",
|
|
1419
|
-
// 'f:BTC:cds': "0.00000014",
|
|
1420
|
-
// "tradingFeeMaker": "0",
|
|
1421
|
-
// "tradingFeeTaker": "0.18",
|
|
1422
|
-
// "tradingFeeUserVolumeAmount": "3466715450",
|
|
1423
|
-
// "orderId": "4426728375" }
|
|
1424
|
-
// --
|
|
1425
|
-
// filled:
|
|
1426
|
-
// { "id": "5342275378",
|
|
1427
|
-
// "type": "sell",
|
|
1428
|
-
// "time": "2018-01-04T00:28:12.992Z",
|
|
1429
|
-
// "lastTxTime": "2018-01-04T00:28:12.992Z",
|
|
1430
|
-
// "lastTx": "5342275393",
|
|
1431
|
-
// "pos": null,
|
|
1432
|
-
// "status": "d",
|
|
1433
|
-
// "symbol1": "BCH",
|
|
1434
|
-
// "symbol2": "BTC",
|
|
1435
|
-
// "amount": "0.10000000",
|
|
1436
|
-
// "kind": "api",
|
|
1437
|
-
// "price": "0.17",
|
|
1438
|
-
// "remains": "0.00000000",
|
|
1439
|
-
// 'tfa:BTC': "0.00003902",
|
|
1440
|
-
// 'tta:BTC': "0.01699999",
|
|
1441
|
-
// 'a:BCH:cds': "0.10000000",
|
|
1442
|
-
// 'a:BTC:cds': "0.01699999",
|
|
1443
|
-
// 'f:BTC:cds': "0.00003902",
|
|
1444
|
-
// "tradingFeeMaker": "0.15",
|
|
1445
|
-
// "tradingFeeTaker": "0.23",
|
|
1446
|
-
// "tradingFeeUserVolumeAmount": "1525951128",
|
|
1447
|
-
// "orderId": "5342275378" }
|
|
1448
|
-
// --
|
|
1449
|
-
// market order (buy):
|
|
1450
|
-
// { "id": "6281946200",
|
|
1451
|
-
// "pos": null,
|
|
1452
|
-
// "time": "2018-05-23T11:55:43.467Z",
|
|
1453
|
-
// "type": "buy",
|
|
1454
|
-
// "amount": "0.00000000",
|
|
1455
|
-
// "lastTx": "6281946210",
|
|
1456
|
-
// "status": "d",
|
|
1457
|
-
// "amount2": "20.00",
|
|
1458
|
-
// "orderId": "6281946200",
|
|
1459
|
-
// "remains": "0.00000000",
|
|
1460
|
-
// "symbol1": "ETH",
|
|
1461
|
-
// "symbol2": "EUR",
|
|
1462
|
-
// "tfa:EUR": "0.05",
|
|
1463
|
-
// "tta:EUR": "19.94",
|
|
1464
|
-
// "a:ETH:cds": "0.03764100",
|
|
1465
|
-
// "a:EUR:cds": "20.00",
|
|
1466
|
-
// "f:EUR:cds": "0.05",
|
|
1467
|
-
// "lastTxTime": "2018-05-23T11:55:43.467Z",
|
|
1468
|
-
// "tradingFeeTaker": "0.25",
|
|
1469
|
-
// "tradingFeeUserVolumeAmount": "55998097" }
|
|
1470
|
-
// --
|
|
1471
|
-
// market order (sell):
|
|
1472
|
-
// { "id": "6282200948",
|
|
1473
|
-
// "pos": null,
|
|
1474
|
-
// "time": "2018-05-23T12:42:58.315Z",
|
|
1475
|
-
// "type": "sell",
|
|
1476
|
-
// "amount": "-0.05000000",
|
|
1477
|
-
// "lastTx": "6282200958",
|
|
1478
|
-
// "status": "d",
|
|
1479
|
-
// "orderId": "6282200948",
|
|
1480
|
-
// "remains": "0.00000000",
|
|
1481
|
-
// "symbol1": "ETH",
|
|
1482
|
-
// "symbol2": "EUR",
|
|
1483
|
-
// "tfa:EUR": "0.07",
|
|
1484
|
-
// "tta:EUR": "26.49",
|
|
1485
|
-
// "a:ETH:cds": "0.05000000",
|
|
1486
|
-
// "a:EUR:cds": "26.49",
|
|
1487
|
-
// "f:EUR:cds": "0.07",
|
|
1488
|
-
// "lastTxTime": "2018-05-23T12:42:58.315Z",
|
|
1489
|
-
// "tradingFeeTaker": "0.25",
|
|
1490
|
-
// "tradingFeeUserVolumeAmount": "56294576" }
|
|
1491
|
-
const order = response[i];
|
|
1492
|
-
const status = this.parseOrderStatus(this.safeString(order, 'status'));
|
|
1493
|
-
const baseId = this.safeString(order, 'symbol1');
|
|
1494
|
-
const quoteId = this.safeString(order, 'symbol2');
|
|
1495
|
-
const base = this.safeCurrencyCode(baseId);
|
|
1496
|
-
const quote = this.safeCurrencyCode(quoteId);
|
|
1497
|
-
const symbolInner = base + '/' + quote;
|
|
1498
|
-
const side = this.safeString(order, 'type');
|
|
1499
|
-
const baseAmount = this.safeNumber(order, 'a:' + baseId + ':cds');
|
|
1500
|
-
const quoteAmount = this.safeNumber(order, 'a:' + quoteId + ':cds');
|
|
1501
|
-
const fee = this.safeNumber(order, 'f:' + quoteId + ':cds');
|
|
1502
|
-
const amount = this.safeString(order, 'amount');
|
|
1503
|
-
const price = this.safeString(order, 'price');
|
|
1504
|
-
const remaining = this.safeString(order, 'remains');
|
|
1505
|
-
const filled = Precise.stringSub(amount, remaining);
|
|
1506
|
-
let orderAmount = undefined;
|
|
1507
|
-
let cost = undefined;
|
|
1508
|
-
let average = undefined;
|
|
1509
|
-
let type = undefined;
|
|
1510
|
-
if (!price) {
|
|
1511
|
-
type = 'market';
|
|
1512
|
-
orderAmount = baseAmount;
|
|
1513
|
-
cost = quoteAmount;
|
|
1514
|
-
average = Precise.stringDiv(orderAmount, cost);
|
|
1515
|
-
}
|
|
1516
|
-
else {
|
|
1517
|
-
const ta = this.safeString(order, 'ta:' + quoteId, '0');
|
|
1518
|
-
const tta = this.safeString(order, 'tta:' + quoteId, '0');
|
|
1519
|
-
const fa = this.safeString(order, 'fa:' + quoteId, '0');
|
|
1520
|
-
const tfa = this.safeString(order, 'tfa:' + quoteId, '0');
|
|
1521
|
-
if (side === 'sell') {
|
|
1522
|
-
cost = Precise.stringAdd(Precise.stringAdd(ta, tta), Precise.stringAdd(fa, tfa));
|
|
1523
|
-
}
|
|
1524
|
-
else {
|
|
1525
|
-
cost = Precise.stringSub(Precise.stringAdd(ta, tta), Precise.stringAdd(fa, tfa));
|
|
1526
|
-
}
|
|
1527
|
-
type = 'limit';
|
|
1528
|
-
orderAmount = amount;
|
|
1529
|
-
average = Precise.stringDiv(cost, filled);
|
|
1530
|
-
}
|
|
1531
|
-
const time = this.safeString(order, 'time');
|
|
1532
|
-
const lastTxTime = this.safeString(order, 'lastTxTime');
|
|
1533
|
-
const timestamp = this.parse8601(time);
|
|
1534
|
-
const safeOrder = this.safeOrder({
|
|
1535
|
-
'info': order,
|
|
1536
|
-
'id': this.safeString(order, 'id'),
|
|
1537
|
-
'timestamp': timestamp,
|
|
1538
|
-
'datetime': this.iso8601(timestamp),
|
|
1539
|
-
'lastUpdated': this.parse8601(lastTxTime),
|
|
1540
|
-
'status': status,
|
|
1541
|
-
'symbol': symbolInner,
|
|
1542
|
-
'side': side,
|
|
1543
|
-
'price': price,
|
|
1544
|
-
'amount': orderAmount,
|
|
1545
|
-
'average': average,
|
|
1546
|
-
'type': type,
|
|
1547
|
-
'filled': filled,
|
|
1548
|
-
'cost': cost,
|
|
1549
|
-
'remaining': remaining,
|
|
1550
|
-
'fee': {
|
|
1551
|
-
'cost': fee,
|
|
1552
|
-
'currency': quote,
|
|
1553
|
-
},
|
|
1554
|
-
});
|
|
1555
|
-
results.push(safeOrder);
|
|
1556
|
-
}
|
|
1557
|
-
return results;
|
|
1558
|
-
}
|
|
1559
|
-
parseOrderStatus(status) {
|
|
1560
|
-
return this.safeString(this.options['order']['status'], status, status);
|
|
1461
|
+
const response = await this.privatePostDoMyInternalTransfer(this.extend(request, params));
|
|
1462
|
+
//
|
|
1463
|
+
// {
|
|
1464
|
+
// "ok": "ok",
|
|
1465
|
+
// "data": {
|
|
1466
|
+
// "transactionId": "30225415"
|
|
1467
|
+
// }
|
|
1468
|
+
// }
|
|
1469
|
+
//
|
|
1470
|
+
const data = this.safeDict(response, 'data', {});
|
|
1471
|
+
return this.parseTransfer(data, currency);
|
|
1561
1472
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
const
|
|
1587
|
-
|
|
1588
|
-
'
|
|
1589
|
-
'
|
|
1590
|
-
'
|
|
1591
|
-
'
|
|
1473
|
+
parseTransfer(transfer, currency = undefined) {
|
|
1474
|
+
//
|
|
1475
|
+
// transferBetweenSubAccounts
|
|
1476
|
+
//
|
|
1477
|
+
// {
|
|
1478
|
+
// "ok": "ok",
|
|
1479
|
+
// "data": {
|
|
1480
|
+
// "transactionId": "30225415"
|
|
1481
|
+
// }
|
|
1482
|
+
// }
|
|
1483
|
+
//
|
|
1484
|
+
// transfer between main/sub
|
|
1485
|
+
//
|
|
1486
|
+
// {
|
|
1487
|
+
// "ok": "ok",
|
|
1488
|
+
// "data": {
|
|
1489
|
+
// "accountId": "sub1",
|
|
1490
|
+
// "clientTxId": "27ba8284-67cf-4386-9ec7-80b3871abd45",
|
|
1491
|
+
// "currency": "USDT",
|
|
1492
|
+
// "status": "approved"
|
|
1493
|
+
// }
|
|
1494
|
+
// }
|
|
1495
|
+
//
|
|
1496
|
+
const currencyId = this.safeString(transfer, 'currency');
|
|
1497
|
+
const currencyCode = this.safeCurrencyCode(currencyId, currency);
|
|
1498
|
+
return {
|
|
1499
|
+
'info': transfer,
|
|
1500
|
+
'id': this.safeString2(transfer, 'transactionId', 'clientTxId'),
|
|
1501
|
+
'timestamp': undefined,
|
|
1502
|
+
'datetime': undefined,
|
|
1503
|
+
'currency': currencyCode,
|
|
1504
|
+
'amount': undefined,
|
|
1505
|
+
'fromAccount': undefined,
|
|
1506
|
+
'toAccount': undefined,
|
|
1507
|
+
'status': this.parseTransactionStatus(this.safeString(transfer, 'status')),
|
|
1592
1508
|
};
|
|
1593
|
-
const response = await this.privatePostCancelReplaceOrderPair(this.extend(request, params));
|
|
1594
|
-
return this.parseOrder(response, market);
|
|
1595
1509
|
}
|
|
1596
1510
|
async fetchDepositAddress(code, params = {}) {
|
|
1597
1511
|
/**
|
|
1598
1512
|
* @method
|
|
1599
1513
|
* @name cex#fetchDepositAddress
|
|
1600
|
-
* @see https://docs.cex.io/#get-crypto-address
|
|
1601
1514
|
* @description fetch the deposit address for a currency associated with this account
|
|
1515
|
+
* @see https://trade.cex.io/docs/#rest-private-api-calls-deposit-address
|
|
1602
1516
|
* @param {string} code unified currency code
|
|
1603
1517
|
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1518
|
+
* @param {string} [params.accountId] account-id (default to empty string) to refer to (at this moment, only sub-accounts allowed by exchange)
|
|
1604
1519
|
* @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
|
|
1605
1520
|
*/
|
|
1521
|
+
let accountId = undefined;
|
|
1522
|
+
[accountId, params] = this.handleOptionAndParams(params, 'createOrder', 'accountId');
|
|
1523
|
+
if (accountId === undefined) {
|
|
1524
|
+
throw new ArgumentsRequired(this.id + ' fetchDepositAddress() : main account is not allowed to fetch deposit address from api, set params["accountId"] or .options["createOrder"]["accountId"] to the name of your sub-account');
|
|
1525
|
+
}
|
|
1606
1526
|
await this.loadMarkets();
|
|
1527
|
+
let networkCode = undefined;
|
|
1528
|
+
[networkCode, params] = this.handleNetworkCodeAndParams(params);
|
|
1607
1529
|
const currency = this.currency(code);
|
|
1608
1530
|
const request = {
|
|
1531
|
+
'accountId': accountId,
|
|
1609
1532
|
'currency': currency['id'],
|
|
1533
|
+
'blockchain': this.networkCodeToId(networkCode),
|
|
1610
1534
|
};
|
|
1611
|
-
const
|
|
1612
|
-
// atm, cex doesn't support network in the request
|
|
1613
|
-
const response = await this.privatePostGetCryptoAddress(this.extend(request, query));
|
|
1535
|
+
const response = await this.privatePostGetDepositAddress(this.extend(request, params));
|
|
1614
1536
|
//
|
|
1615
1537
|
// {
|
|
1616
|
-
//
|
|
1617
|
-
//
|
|
1618
|
-
//
|
|
1619
|
-
//
|
|
1620
|
-
//
|
|
1621
|
-
//
|
|
1622
|
-
//
|
|
1623
|
-
//
|
|
1538
|
+
// "ok": "ok",
|
|
1539
|
+
// "data": {
|
|
1540
|
+
// "address": "TCr..................1AE",
|
|
1541
|
+
// "accountId": "sub1",
|
|
1542
|
+
// "currency": "USDT",
|
|
1543
|
+
// "blockchain": "tron"
|
|
1544
|
+
// }
|
|
1545
|
+
// }
|
|
1624
1546
|
//
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
// }
|
|
1633
|
-
//
|
|
1634
|
-
const data = this.safeValue(response, 'data', {});
|
|
1635
|
-
const addresses = this.safeValue(data, 'addresses', []);
|
|
1636
|
-
const chainsIndexedById = this.indexBy(addresses, 'blockchain');
|
|
1637
|
-
const selectedNetworkId = this.selectNetworkIdFromRawNetworks(code, networkCode, chainsIndexedById);
|
|
1638
|
-
const addressObject = this.safeValue(chainsIndexedById, selectedNetworkId, {});
|
|
1639
|
-
const address = this.safeString2(addressObject, 'address', 'destination');
|
|
1547
|
+
const data = this.safeDict(response, 'data', {});
|
|
1548
|
+
return this.parseDepositAddress(data, currency);
|
|
1549
|
+
}
|
|
1550
|
+
parseDepositAddress(depositAddress, currency = undefined) {
|
|
1551
|
+
const address = this.safeString(depositAddress, 'address');
|
|
1552
|
+
const currencyId = this.safeString(depositAddress, 'currency');
|
|
1553
|
+
currency = this.safeCurrency(currencyId, currency);
|
|
1640
1554
|
this.checkAddress(address);
|
|
1641
1555
|
return {
|
|
1642
|
-
'info':
|
|
1643
|
-
'currency': code,
|
|
1644
|
-
'network': this.networkIdToCode(
|
|
1556
|
+
'info': depositAddress,
|
|
1557
|
+
'currency': currency['code'],
|
|
1558
|
+
'network': this.networkIdToCode(this.safeString(depositAddress, 'blockchain')),
|
|
1645
1559
|
'address': address,
|
|
1646
|
-
'tag':
|
|
1560
|
+
'tag': undefined,
|
|
1647
1561
|
};
|
|
1648
1562
|
}
|
|
1649
|
-
nonce() {
|
|
1650
|
-
return this.milliseconds();
|
|
1651
|
-
}
|
|
1652
1563
|
sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
|
1653
|
-
let url = this.urls['api'][
|
|
1564
|
+
let url = this.urls['api'][api] + '/' + this.implodeParams(path, params);
|
|
1654
1565
|
const query = this.omit(params, this.extractParams(path));
|
|
1655
1566
|
if (api === 'public') {
|
|
1656
|
-
if (
|
|
1657
|
-
|
|
1567
|
+
if (method === 'GET') {
|
|
1568
|
+
if (Object.keys(query).length) {
|
|
1569
|
+
url += '?' + this.urlencode(query);
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
else {
|
|
1573
|
+
body = this.json(query);
|
|
1574
|
+
headers = {
|
|
1575
|
+
'Content-Type': 'application/json',
|
|
1576
|
+
};
|
|
1658
1577
|
}
|
|
1659
1578
|
}
|
|
1660
1579
|
else {
|
|
1661
1580
|
this.checkRequiredCredentials();
|
|
1662
|
-
const
|
|
1663
|
-
|
|
1664
|
-
const
|
|
1665
|
-
|
|
1666
|
-
'key': this.apiKey,
|
|
1667
|
-
'signature': signature.toUpperCase(),
|
|
1668
|
-
'nonce': nonce,
|
|
1669
|
-
}, query));
|
|
1581
|
+
const seconds = this.seconds().toString();
|
|
1582
|
+
body = this.json(query);
|
|
1583
|
+
const auth = path + seconds + body;
|
|
1584
|
+
const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha256, 'base64');
|
|
1670
1585
|
headers = {
|
|
1671
1586
|
'Content-Type': 'application/json',
|
|
1587
|
+
'X-AGGR-KEY': this.apiKey,
|
|
1588
|
+
'X-AGGR-TIMESTAMP': seconds,
|
|
1589
|
+
'X-AGGR-SIGNATURE': signature,
|
|
1672
1590
|
};
|
|
1673
1591
|
}
|
|
1674
1592
|
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
|
1675
1593
|
}
|
|
1676
1594
|
handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
if (body === 'true') {
|
|
1681
|
-
return undefined;
|
|
1682
|
-
}
|
|
1595
|
+
// in some cases, like from createOrder, exchange returns nested escaped JSON string:
|
|
1596
|
+
// {"ok":"ok","data":{"messageType":"executionReport", "orderRejectReason":"{\"code\":405}"} }
|
|
1597
|
+
// and because of `.parseJson` bug, we need extra fix
|
|
1683
1598
|
if (response === undefined) {
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
if ('
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1599
|
+
if (body === undefined) {
|
|
1600
|
+
throw new NullResponse(this.id + ' returned empty response');
|
|
1601
|
+
}
|
|
1602
|
+
else if (body[0] === '{') {
|
|
1603
|
+
const fixed = this.fixStringifiedJsonMembers(body);
|
|
1604
|
+
response = this.parseJson(fixed);
|
|
1605
|
+
}
|
|
1606
|
+
else {
|
|
1607
|
+
throw new NullResponse(this.id + ' returned unparsed response: ' + body);
|
|
1691
1608
|
}
|
|
1692
1609
|
}
|
|
1693
|
-
|
|
1694
|
-
|
|
1610
|
+
const error = this.safeString(response, 'error');
|
|
1611
|
+
if (error !== undefined) {
|
|
1695
1612
|
const feedback = this.id + ' ' + body;
|
|
1696
|
-
this.throwExactlyMatchedException(this.exceptions['exact'],
|
|
1697
|
-
this.throwBroadlyMatchedException(this.exceptions['broad'],
|
|
1613
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], error, feedback);
|
|
1614
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], error, feedback);
|
|
1698
1615
|
throw new ExchangeError(feedback);
|
|
1699
1616
|
}
|
|
1617
|
+
// check errors in order-engine (the responses are not standard, so we parse here)
|
|
1618
|
+
if (url.indexOf('do_my_new_order') >= 0) {
|
|
1619
|
+
const data = this.safeDict(response, 'data', {});
|
|
1620
|
+
const rejectReason = this.safeString(data, 'rejectReason');
|
|
1621
|
+
if (rejectReason !== undefined) {
|
|
1622
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], rejectReason, rejectReason);
|
|
1623
|
+
throw new ExchangeError(this.id + ' createOrder() ' + rejectReason);
|
|
1624
|
+
}
|
|
1625
|
+
}
|
|
1700
1626
|
return undefined;
|
|
1701
1627
|
}
|
|
1702
1628
|
}
|