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