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