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