ccxt 4.3.89 → 4.3.91

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.
Files changed (69) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +1 -1
  4. package/dist/cjs/src/alpaca.js +2 -2
  5. package/dist/cjs/src/ascendex.js +95 -97
  6. package/dist/cjs/src/binance.js +1 -1
  7. package/dist/cjs/src/bingx.js +31 -17
  8. package/dist/cjs/src/bitfinex2.js +21 -22
  9. package/dist/cjs/src/bitget.js +2 -2
  10. package/dist/cjs/src/bitmart.js +6 -9
  11. package/dist/cjs/src/coinbaseinternational.js +2 -1
  12. package/dist/cjs/src/coinex.js +1 -17
  13. package/dist/cjs/src/hitbtc.js +2 -0
  14. package/dist/cjs/src/htx.js +49 -49
  15. package/dist/cjs/src/huobijp.js +0 -9
  16. package/dist/cjs/src/kucoin.js +59 -21
  17. package/dist/cjs/src/kucoinfutures.js +26 -2
  18. package/dist/cjs/src/latoken.js +1 -0
  19. package/dist/cjs/src/okx.js +1 -8
  20. package/dist/cjs/src/pro/binance.js +323 -0
  21. package/dist/cjs/src/pro/bingx.js +263 -91
  22. package/dist/cjs/src/pro/bithumb.js +5 -1
  23. package/dist/cjs/src/pro/bybit.js +1 -1
  24. package/dist/cjs/src/pro/coinex.js +994 -679
  25. package/dist/cjs/src/pro/lbank.js +2 -3
  26. package/dist/cjs/src/pro/okx.js +159 -3
  27. package/dist/cjs/src/whitebit.js +5 -3
  28. package/dist/cjs/src/woo.js +1 -1
  29. package/js/ccxt.d.ts +1 -1
  30. package/js/ccxt.js +1 -1
  31. package/js/src/abstract/kucoin.d.ts +1 -0
  32. package/js/src/abstract/kucoinfutures.d.ts +1 -0
  33. package/js/src/alpaca.js +2 -2
  34. package/js/src/ascendex.js +95 -97
  35. package/js/src/binance.js +1 -1
  36. package/js/src/bingx.js +31 -17
  37. package/js/src/bitfinex2.d.ts +0 -1
  38. package/js/src/bitfinex2.js +21 -22
  39. package/js/src/bitget.js +2 -2
  40. package/js/src/bitmart.d.ts +0 -1
  41. package/js/src/bitmart.js +6 -9
  42. package/js/src/coinbaseinternational.js +2 -1
  43. package/js/src/coinex.d.ts +0 -2
  44. package/js/src/coinex.js +1 -17
  45. package/js/src/hitbtc.js +2 -0
  46. package/js/src/htx.js +49 -49
  47. package/js/src/huobijp.d.ts +0 -1
  48. package/js/src/huobijp.js +0 -9
  49. package/js/src/kucoin.d.ts +3 -1
  50. package/js/src/kucoin.js +59 -21
  51. package/js/src/kucoinfutures.d.ts +1 -0
  52. package/js/src/kucoinfutures.js +26 -2
  53. package/js/src/latoken.js +1 -0
  54. package/js/src/okx.d.ts +0 -1
  55. package/js/src/okx.js +1 -8
  56. package/js/src/pro/binance.d.ts +9 -1
  57. package/js/src/pro/binance.js +327 -1
  58. package/js/src/pro/bingx.d.ts +2 -2
  59. package/js/src/pro/bingx.js +263 -91
  60. package/js/src/pro/bithumb.js +5 -1
  61. package/js/src/pro/bybit.js +1 -1
  62. package/js/src/pro/coinex.d.ts +12 -6
  63. package/js/src/pro/coinex.js +996 -681
  64. package/js/src/pro/lbank.js +2 -3
  65. package/js/src/pro/okx.d.ts +7 -0
  66. package/js/src/pro/okx.js +162 -4
  67. package/js/src/whitebit.js +5 -3
  68. package/js/src/woo.js +1 -1
  69. package/package.json +1 -1
@@ -1,11 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var Precise = require('../base/Precise.js');
4
3
  var coinex$1 = require('../coinex.js');
5
4
  var errors = require('../base/errors.js');
6
5
  var Cache = require('../base/ws/Cache.js');
7
6
  var sha256 = require('../static_dependencies/noble-hashes/sha256.js');
8
- var md5 = require('../static_dependencies/noble-hashes/md5.js');
9
7
 
10
8
  // ---------------------------------------------------------------------------
11
9
  // ---------------------------------------------------------------------------
@@ -15,25 +13,30 @@ class coinex extends coinex$1 {
15
13
  'has': {
16
14
  'ws': true,
17
15
  'watchBalance': true,
16
+ 'watchBidsAsks': true,
18
17
  'watchTicker': true,
19
18
  'watchTickers': true,
20
19
  'watchTrades': true,
21
- 'watchMyTrades': false,
20
+ 'watchTradesForSymbols': true,
21
+ 'watchMyTrades': true,
22
22
  'watchOrders': true,
23
23
  'watchOrderBook': true,
24
- 'watchOHLCV': true,
25
- 'fetchOHLCVWs': true,
24
+ 'watchOrderBookForSymbols': true,
25
+ 'watchOHLCV': false,
26
+ 'fetchOHLCVWs': false,
26
27
  },
27
28
  'urls': {
28
29
  'api': {
29
30
  'ws': {
30
- 'spot': 'wss://socket.coinex.com/',
31
- 'swap': 'wss://perpetual.coinex.com/',
31
+ 'spot': 'wss://socket.coinex.com/v2/spot/',
32
+ 'swap': 'wss://socket.coinex.com/v2/futures/',
32
33
  },
33
34
  },
34
35
  },
35
36
  'options': {
36
- 'watchOHLCVWarning': true,
37
+ 'ws': {
38
+ 'gunzip': true,
39
+ },
37
40
  'timeframes': {
38
41
  '1m': 60,
39
42
  '3m': 180,
@@ -53,20 +56,31 @@ class coinex extends coinex$1 {
53
56
  'watchOrderBook': {
54
57
  'limits': [5, 10, 20, 50],
55
58
  'defaultLimit': 50,
56
- 'aggregations': ['10', '1', '0', '0.1', '0.01'],
59
+ 'aggregations': ['1000', '100', '10', '1', '0', '0.1', '0.01', '0.001', '0.0001', '0.00001', '0.000001', '0.0000001', '0.00000001', '0.000000001', '0.0000000001', '0.00000000001'],
57
60
  'defaultAggregation': '0',
58
61
  },
59
62
  },
60
63
  'streaming': {},
61
64
  'exceptions': {
62
- 'codes': {
63
- '1': errors.BadRequest,
64
- '2': errors.ExchangeError,
65
- '3': errors.ExchangeNotAvailable,
66
- '4': errors.NotSupported,
67
- '5': errors.RequestTimeout,
68
- '6': errors.AuthenticationError, // Permission denied
65
+ 'exact': {
66
+ '20001': errors.BadRequest,
67
+ '20002': errors.NotSupported,
68
+ '21001': errors.AuthenticationError,
69
+ '21002': errors.AuthenticationError,
70
+ '23001': errors.RequestTimeout,
71
+ '23002': errors.RateLimitExceeded,
72
+ '24001': errors.ExchangeError,
73
+ '24002': errors.ExchangeNotAvailable,
74
+ '30001': errors.BadRequest,
75
+ '30002': errors.NotSupported,
76
+ '31001': errors.AuthenticationError,
77
+ '31002': errors.AuthenticationError,
78
+ '33001': errors.RequestTimeout,
79
+ '33002': errors.RateLimitExceeded,
80
+ '34001': errors.ExchangeError,
81
+ '34002': errors.ExchangeNotAvailable, // Service unavailable temporarily
69
82
  },
83
+ 'broad': {},
70
84
  },
71
85
  });
72
86
  }
@@ -81,61 +95,66 @@ class coinex extends coinex$1 {
81
95
  //
82
96
  // {
83
97
  // "method": "state.update",
84
- // "params": [{
85
- // "BTCUSDT": {
86
- // "last": "31577.89",
87
- // "open": "29318.36",
88
- // "close": "31577.89",
89
- // "high": "32222.19",
90
- // "low": "29317.21",
91
- // "volume": "630.43024965",
92
- // "sell_total": "13.66143951",
93
- // "buy_total": "2.76410939",
94
- // "period": 86400,
95
- // "deal": "19457487.84611409070000000000"
96
- // }
97
- // }]
98
+ // "data": {
99
+ // "state_list": [
100
+ // {
101
+ // "market": "LATUSDT",
102
+ // "last": "0.008157",
103
+ // "open": "0.008286",
104
+ // "close": "0.008157",
105
+ // "high": "0.008390",
106
+ // "low": "0.008106",
107
+ // "volume": "807714.49139758",
108
+ // "volume_sell": "286170.69645599",
109
+ // "volume_buy": "266161.23236408",
110
+ // "value": "6689.21644207",
111
+ // "period": 86400
112
+ // },
113
+ // ]
114
+ // },
115
+ // "id": null
98
116
  // }
99
117
  //
100
118
  // swap
101
119
  //
102
120
  // {
103
121
  // "method": "state.update",
104
- // "params": [{
105
- // "BTCUSDT": {
106
- // "period": 86400,
107
- // "funding_time": 422,
108
- // "position_amount": "285.6246",
109
- // "funding_rate_last": "-0.00097933",
110
- // "funding_rate_next": "0.00022519",
111
- // "funding_rate_predict": "0.00075190",
112
- // "insurance": "17474289.49925859030905338270",
113
- // "last": "31570.08",
114
- // "sign_price": "31568.09",
115
- // "index_price": "31561.85000000",
116
- // "open": "29296.11",
117
- // "close": "31570.08",
118
- // "high": "32463.40",
119
- // "low": "29296.11",
120
- // "volume": "8774.7318",
121
- // "deal": "270675177.827928219109030017258398",
122
- // "sell_total": "19.2230",
123
- // "buy_total": "25.7814"
124
- // }
125
- // }]
122
+ // "data": {
123
+ // "state_list": [
124
+ // {
125
+ // "market": "ETHUSD_SIGNPRICE",
126
+ // "last": "1892.29",
127
+ // "open": "1884.62",
128
+ // "close": "1892.29",
129
+ // "high": "1894.09",
130
+ // "low": "1863.72",
131
+ // "volume": "0",
132
+ // "value": "0",
133
+ // "volume_sell": "0",
134
+ // "volume_buy": "0",
135
+ // "open_interest_size": "0",
136
+ // "insurance_fund_size": "0",
137
+ // "latest_funding_rate": "0",
138
+ // "next_funding_rate": "0",
139
+ // "latest_funding_time": 0,
140
+ // "next_funding_time": 0,
141
+ // "period": 86400
142
+ // },
143
+ // ]
144
+ // ],
145
+ // "id": null
126
146
  // }
127
147
  //
128
148
  const defaultType = this.safeString(this.options, 'defaultType');
129
- const params = this.safeValue(message, 'params', []);
130
- const rawTickers = this.safeValue(params, 0, {});
131
- const keys = Object.keys(rawTickers);
149
+ const data = this.safeDict(message, 'data', {});
150
+ const rawTickers = this.safeList(data, 'state_list', []);
132
151
  const newTickers = [];
133
- for (let i = 0; i < keys.length; i++) {
134
- const marketId = keys[i];
135
- const rawTicker = rawTickers[marketId];
152
+ for (let i = 0; i < rawTickers.length; i++) {
153
+ const entry = rawTickers[i];
154
+ const marketId = this.safeString(entry, 'market');
136
155
  const symbol = this.safeSymbol(marketId, undefined, undefined, defaultType);
137
156
  const market = this.safeMarket(marketId, undefined, undefined, defaultType);
138
- const parsedTicker = this.parseWSTicker(rawTicker, market);
157
+ const parsedTicker = this.parseWSTicker(entry, market);
139
158
  this.tickers[symbol] = parsedTicker;
140
159
  newTickers.push(parsedTicker);
141
160
  }
@@ -159,52 +178,53 @@ class coinex extends coinex$1 {
159
178
  // spot
160
179
  //
161
180
  // {
162
- // "last": "31577.89",
163
- // "open": "29318.36",
164
- // "close": "31577.89",
165
- // "high": "32222.19",
166
- // "low": "29317.21",
167
- // "volume": "630.43024965",
168
- // "sell_total": "13.66143951",
169
- // "buy_total": "2.76410939",
170
- // "period": 86400,
171
- // "deal": "19457487.84611409070000000000"
181
+ // "market": "LATUSDT",
182
+ // "last": "0.008157",
183
+ // "open": "0.008286",
184
+ // "close": "0.008157",
185
+ // "high": "0.008390",
186
+ // "low": "0.008106",
187
+ // "volume": "807714.49139758",
188
+ // "volume_sell": "286170.69645599",
189
+ // "volume_buy": "266161.23236408",
190
+ // "value": "6689.21644207",
191
+ // "period": 86400
172
192
  // }
173
193
  //
174
194
  // swap
175
195
  //
176
196
  // {
177
- // "period": 86400,
178
- // "funding_time": 422,
179
- // "position_amount": "285.6246",
180
- // "funding_rate_last": "-0.00097933",
181
- // "funding_rate_next": "0.00022519",
182
- // "funding_rate_predict": "0.00075190",
183
- // "insurance": "17474289.49925859030905338270",
184
- // "last": "31570.08",
185
- // "sign_price": "31568.09",
186
- // "index_price": "31561.85000000",
187
- // "open": "29296.11",
188
- // "close": "31570.08",
189
- // "high": "32463.40",
190
- // "low": "29296.11",
191
- // "volume": "8774.7318",
192
- // "deal": "270675177.827928219109030017258398",
193
- // "sell_total": "19.2230",
194
- // "buy_total": "25.7814"
197
+ // "market": "ETHUSD_SIGNPRICE",
198
+ // "last": "1892.29",
199
+ // "open": "1884.62",
200
+ // "close": "1892.29",
201
+ // "high": "1894.09",
202
+ // "low": "1863.72",
203
+ // "volume": "0",
204
+ // "value": "0",
205
+ // "volume_sell": "0",
206
+ // "volume_buy": "0",
207
+ // "open_interest_size": "0",
208
+ // "insurance_fund_size": "0",
209
+ // "latest_funding_rate": "0",
210
+ // "next_funding_rate": "0",
211
+ // "latest_funding_time": 0,
212
+ // "next_funding_time": 0,
213
+ // "period": 86400
195
214
  // }
196
215
  //
197
216
  const defaultType = this.safeString(this.options, 'defaultType');
217
+ const marketId = this.safeString(ticker, 'market');
198
218
  return this.safeTicker({
199
- 'symbol': this.safeSymbol(undefined, market, undefined, defaultType),
219
+ 'symbol': this.safeSymbol(marketId, market, undefined, defaultType),
200
220
  'timestamp': undefined,
201
221
  'datetime': undefined,
202
222
  'high': this.safeString(ticker, 'high'),
203
223
  'low': this.safeString(ticker, 'low'),
204
224
  'bid': undefined,
205
- 'bidVolume': this.safeString(ticker, 'buy_total'),
225
+ 'bidVolume': this.safeString(ticker, 'volume_buy'),
206
226
  'ask': undefined,
207
- 'askVolume': this.safeString(ticker, 'sell_total'),
227
+ 'askVolume': this.safeString(ticker, 'volume_sell'),
208
228
  'vwap': undefined,
209
229
  'open': this.safeString(ticker, 'open'),
210
230
  'close': this.safeString(ticker, 'close'),
@@ -214,7 +234,7 @@ class coinex extends coinex$1 {
214
234
  'percentage': undefined,
215
235
  'average': undefined,
216
236
  'baseVolume': this.safeString(ticker, 'volume'),
217
- 'quoteVolume': this.safeString(ticker, 'deal'),
237
+ 'quoteVolume': this.safeString(ticker, 'value'),
218
238
  'info': ticker,
219
239
  }, market);
220
240
  }
@@ -223,78 +243,290 @@ class coinex extends coinex$1 {
223
243
  * @method
224
244
  * @name coinex#watchBalance
225
245
  * @description watch balance and get the amount of funds available for trading or funds locked in orders
246
+ * @see https://docs.coinex.com/api/v2/assets/balance/ws/spot_balance
247
+ * @see https://docs.coinex.com/api/v2/assets/balance/ws/futures_balance
226
248
  * @param {object} [params] extra parameters specific to the exchange API endpoint
227
249
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
228
250
  */
229
251
  await this.loadMarkets();
230
- await this.authenticate(params);
231
- const messageHash = 'balance';
232
252
  let type = undefined;
233
- [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params);
253
+ [type, params] = this.handleMarketTypeAndParams('watchBalance', undefined, params, 'spot');
254
+ await this.authenticate(type);
234
255
  const url = this.urls['api']['ws'][type];
235
- const currencies = Object.keys(this.currencies_by_id);
256
+ let currencies = Object.keys(this.currencies_by_id);
257
+ if (currencies === undefined) {
258
+ currencies = [];
259
+ }
260
+ let messageHash = 'balances';
261
+ if (type === 'spot') {
262
+ messageHash += ':spot';
263
+ }
264
+ else {
265
+ messageHash += ':swap';
266
+ }
236
267
  const subscribe = {
237
- 'method': 'asset.subscribe',
238
- 'params': currencies,
268
+ 'method': 'balance.subscribe',
269
+ 'params': { 'ccy_list': currencies },
239
270
  'id': this.requestId(),
240
271
  };
241
272
  const request = this.deepExtend(subscribe, params);
242
273
  return await this.watch(url, messageHash, request, messageHash);
243
274
  }
244
275
  handleBalance(client, message) {
276
+ //
277
+ // spot
245
278
  //
246
279
  // {
247
- // "method": "asset.update",
248
- // "params": [
249
- // {
250
- // "BTC": {
251
- // "available": "250",
252
- // "frozen": "10",
253
- // }
254
- // }
255
- // ],
280
+ // "method": "balance.update",
281
+ // "data": {
282
+ // "balance_list": [
283
+ // {
284
+ // "margin_market": "BTCUSDT",
285
+ // "ccy": "BTC",
286
+ // "available": "44.62207740",
287
+ // "frozen": "0.00000000",
288
+ // "updated_at": 1689152421692
289
+ // },
290
+ // ]
291
+ // },
256
292
  // "id": null
257
293
  // }
258
294
  //
259
- const params = this.safeValue(message, 'params', []);
260
- const first = this.safeValue(params, 0, {});
261
- this.balance['info'] = first;
262
- const currencies = Object.keys(first);
263
- for (let i = 0; i < currencies.length; i++) {
264
- const currencyId = currencies[i];
265
- const code = this.safeCurrencyCode(currencyId);
266
- const available = this.safeString(first[currencyId], 'available');
267
- const frozen = this.safeString(first[currencyId], 'frozen');
268
- const account = this.account();
269
- account['free'] = available;
270
- account['used'] = frozen;
295
+ // swap
296
+ //
297
+ // {
298
+ // "method": "balance.update",
299
+ // "data": {
300
+ // "balance_list": [
301
+ // {
302
+ // "ccy": "USDT",
303
+ // "available": "97.92470982756335000001",
304
+ // "frozen": "0.00000000000000000000",
305
+ // "margin": "0.61442700000000000000",
306
+ // "transferrable": "97.92470982756335000001",
307
+ // "unrealized_pnl": "-0.00807000000000000000",
308
+ // "equity": "97.92470982756335000001"
309
+ // },
310
+ // ]
311
+ // },
312
+ // "id": null
313
+ // }
314
+ //
315
+ if (this.balance === undefined) {
316
+ this.balance = {};
317
+ }
318
+ const data = this.safeDict(message, 'data', {});
319
+ const balances = this.safeList(data, 'balance_list', []);
320
+ const firstEntry = balances[0];
321
+ const updated = this.safeInteger(firstEntry, 'updated_at');
322
+ const unrealizedPnl = this.safeString(firstEntry, 'unrealized_pnl');
323
+ const isSpot = (updated !== undefined);
324
+ const isSwap = (unrealizedPnl !== undefined);
325
+ let info = undefined;
326
+ let account = undefined;
327
+ let rawBalances = [];
328
+ if (isSpot) {
329
+ account = 'spot';
330
+ for (let i = 0; i < balances.length; i++) {
331
+ rawBalances = this.arrayConcat(rawBalances, balances);
332
+ }
333
+ info = rawBalances;
334
+ }
335
+ if (isSwap) {
336
+ account = 'swap';
337
+ for (let i = 0; i < balances.length; i++) {
338
+ rawBalances = this.arrayConcat(rawBalances, balances);
339
+ }
340
+ info = rawBalances;
341
+ }
342
+ for (let i = 0; i < rawBalances.length; i++) {
343
+ const entry = rawBalances[i];
344
+ this.parseWsBalance(entry, account);
345
+ }
346
+ let messageHash = undefined;
347
+ if (account !== undefined) {
348
+ if (this.safeValue(this.balance, account) === undefined) {
349
+ this.balance[account] = {};
350
+ }
351
+ this.balance[account]['info'] = info;
352
+ this.balance[account] = this.safeBalance(this.balance[account]);
353
+ messageHash = 'balances:' + account;
354
+ client.resolve(this.balance[account], messageHash);
355
+ }
356
+ }
357
+ parseWsBalance(balance, accountType = undefined) {
358
+ //
359
+ // spot
360
+ //
361
+ // {
362
+ // "margin_market": "BTCUSDT",
363
+ // "ccy": "BTC",
364
+ // "available": "44.62207740",
365
+ // "frozen": "0.00000000",
366
+ // "updated_at": 1689152421692
367
+ // }
368
+ //
369
+ // swap
370
+ //
371
+ // {
372
+ // "ccy": "USDT",
373
+ // "available": "97.92470982756335000001",
374
+ // "frozen": "0.00000000000000000000",
375
+ // "margin": "0.61442700000000000000",
376
+ // "transferrable": "97.92470982756335000001",
377
+ // "unrealized_pnl": "-0.00807000000000000000",
378
+ // "equity": "97.92470982756335000001"
379
+ // }
380
+ //
381
+ const account = this.account();
382
+ const currencyId = this.safeString(balance, 'ccy');
383
+ const code = this.safeCurrencyCode(currencyId);
384
+ account['free'] = this.safeString(balance, 'available');
385
+ account['used'] = this.safeString(balance, 'frozen');
386
+ if (accountType !== undefined) {
387
+ if (this.safeValue(this.balance, accountType) === undefined) {
388
+ this.balance[accountType] = {};
389
+ }
390
+ this.balance[accountType][code] = account;
391
+ }
392
+ else {
271
393
  this.balance[code] = account;
272
- this.balance = this.safeBalance(this.balance);
273
394
  }
274
- const messageHash = 'balance';
275
- client.resolve(this.balance, messageHash);
395
+ }
396
+ async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
397
+ /**
398
+ * @method
399
+ * @name coinex#watchMyTrades
400
+ * @description watches information on multiple trades made by the user
401
+ * @see https://docs.coinex.com/api/v2/spot/deal/ws/user-deals
402
+ * @see https://docs.coinex.com/api/v2/futures/deal/ws/user-deals
403
+ * @param {string} [symbol] unified symbol of the market the trades were made in
404
+ * @param {int} [since] the earliest time in ms to watch trades
405
+ * @param {int} [limit] the maximum number of trade structures to retrieve
406
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
407
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
408
+ */
409
+ await this.loadMarkets();
410
+ let market = undefined;
411
+ if (symbol !== undefined) {
412
+ market = this.market(symbol);
413
+ symbol = market['symbol'];
414
+ }
415
+ let type = undefined;
416
+ [type, params] = this.handleMarketTypeAndParams('watchMyTrades', market, params, 'spot');
417
+ await this.authenticate(type);
418
+ const url = this.urls['api']['ws'][type];
419
+ const subscribedSymbols = [];
420
+ let messageHash = 'myTrades';
421
+ if (market !== undefined) {
422
+ messageHash += ':' + symbol;
423
+ subscribedSymbols.push(market['id']);
424
+ }
425
+ else {
426
+ if (type === 'spot') {
427
+ messageHash += ':spot';
428
+ }
429
+ else {
430
+ messageHash += ':swap';
431
+ }
432
+ }
433
+ const message = {
434
+ 'method': 'user_deals.subscribe',
435
+ 'params': { 'market_list': subscribedSymbols },
436
+ 'id': this.requestId(),
437
+ };
438
+ const request = this.deepExtend(message, params);
439
+ const trades = await this.watch(url, messageHash, request, messageHash);
440
+ if (this.newUpdates) {
441
+ limit = trades.getLimit(symbol, limit);
442
+ }
443
+ return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
444
+ }
445
+ handleMyTrades(client, message) {
446
+ //
447
+ // {
448
+ // "method": "user_deals.update",
449
+ // "data": {
450
+ // "deal_id": 3514376759,
451
+ // "created_at": 1689152421692,
452
+ // "market": "BTCUSDT",
453
+ // "side": "buy",
454
+ // "order_id": 8678890,
455
+ // "margin_market": "BTCUSDT",
456
+ // "price": "30718.42",
457
+ // "amount": "0.00000325",
458
+ // "role": "taker",
459
+ // "fee": "0.0299",
460
+ // "fee_ccy": "USDT"
461
+ // },
462
+ // "id": null
463
+ // }
464
+ //
465
+ const data = this.safeDict(message, 'data', {});
466
+ const marketId = this.safeString(data, 'market');
467
+ const isSpot = client.url.indexOf('spot') > -1;
468
+ const defaultType = isSpot ? 'spot' : 'swap';
469
+ const market = this.safeMarket(marketId, undefined, undefined, defaultType);
470
+ const symbol = market['symbol'];
471
+ const messageHash = 'myTrades:' + symbol;
472
+ const messageWithType = 'myTrades:' + market['type'];
473
+ let stored = this.safeValue(this.trades, symbol);
474
+ if (stored === undefined) {
475
+ const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
476
+ stored = new Cache.ArrayCache(limit);
477
+ this.trades[symbol] = stored;
478
+ }
479
+ const parsed = this.parseWsTrade(data, market);
480
+ stored.append(parsed);
481
+ this.trades[symbol] = stored;
482
+ client.resolve(this.trades[symbol], messageWithType);
483
+ client.resolve(this.trades[symbol], messageHash);
276
484
  }
277
485
  handleTrades(client, message) {
486
+ //
487
+ // spot
278
488
  //
279
489
  // {
280
490
  // "method": "deals.update",
281
- // "params": [
282
- // "BTCUSD",
283
- // [{
284
- // "type": "sell",
285
- // "time": 1496458040.059284,
286
- // "price ": "46444.74",
287
- // "id": 29433,
288
- // "amount": "0.00120000"
289
- // }]
290
- // ],
491
+ // "data": {
492
+ // "market": "BTCUSDT",
493
+ // "deal_list": [
494
+ // {
495
+ // "deal_id": 3514376759,
496
+ // "created_at": 1689152421692,
497
+ // "side": "buy",
498
+ // "price": "30718.42",
499
+ // "amount": "0.00000325"
500
+ // },
501
+ // ]
502
+ // },
291
503
  // "id": null
292
504
  // }
293
505
  //
294
- const params = this.safeValue(message, 'params', []);
295
- const marketId = this.safeString(params, 0);
296
- const trades = this.safeValue(params, 1, []);
297
- const defaultType = this.safeString(this.options, 'defaultType');
506
+ // swap
507
+ //
508
+ // {
509
+ // "method": "deals.update",
510
+ // "data": {
511
+ // "market": "BTCUSDT",
512
+ // "deal_list": [
513
+ // {
514
+ // "deal_id": 3514376759,
515
+ // "created_at": 1689152421692,
516
+ // "side": "buy",
517
+ // "price": "30718.42",
518
+ // "amount": "0.00000325"
519
+ // },
520
+ // ]
521
+ // },
522
+ // "id": null
523
+ // }
524
+ //
525
+ const data = this.safeDict(message, 'data', {});
526
+ const trades = this.safeList(data, 'deal_list', []);
527
+ const marketId = this.safeString(data, 'market');
528
+ const isSpot = client.url.indexOf('spot') > -1;
529
+ const defaultType = isSpot ? 'spot' : 'swap';
298
530
  const market = this.safeMarket(marketId, undefined, undefined, defaultType);
299
531
  const symbol = market['symbol'];
300
532
  const messageHash = 'trades:' + symbol;
@@ -313,133 +545,127 @@ class coinex extends coinex$1 {
313
545
  client.resolve(this.trades[symbol], messageHash);
314
546
  }
315
547
  parseWsTrade(trade, market = undefined) {
548
+ //
549
+ // spot watchTrades
316
550
  //
317
551
  // {
318
- // "type": "sell",
319
- // "time": 1496458040.059284,
320
- // "price ": "46444.74",
321
- // "id": 29433,
322
- // "amount": "0.00120000"
552
+ // "deal_id": 3514376759,
553
+ // "created_at": 1689152421692,
554
+ // "side": "buy",
555
+ // "price": "30718.42",
556
+ // "amount": "0.00000325"
323
557
  // }
324
558
  //
325
- const timestamp = this.safeTimestamp(trade, 'time');
326
- const defaultType = this.safeString(this.options, 'defaultType');
559
+ // swap watchTrades
560
+ //
561
+ // {
562
+ // "deal_id": 3514376759,
563
+ // "created_at": 1689152421692,
564
+ // "side": "buy",
565
+ // "price": "30718.42",
566
+ // "amount": "0.00000325"
567
+ // }
568
+ //
569
+ // spot and swap watchMyTrades
570
+ //
571
+ // {
572
+ // "deal_id": 3514376759,
573
+ // "created_at": 1689152421692,
574
+ // "market": "BTCUSDT",
575
+ // "side": "buy",
576
+ // "order_id": 8678890,
577
+ // "margin_market": "BTCUSDT",
578
+ // "price": "30718.42",
579
+ // "amount": "0.00000325",
580
+ // "role": "taker",
581
+ // "fee": "0.0299",
582
+ // "fee_ccy": "USDT"
583
+ // }
584
+ //
585
+ const timestamp = this.safeInteger(trade, 'created_at');
586
+ const isSpot = ('margin_market' in trade);
587
+ const defaultType = isSpot ? 'spot' : 'swap';
588
+ const marketId = this.safeString(trade, 'market');
589
+ market = this.safeMarket(marketId, market, undefined, defaultType);
590
+ let fee = {};
591
+ const feeCost = this.omitZero(this.safeString(trade, 'fee'));
592
+ if (feeCost !== undefined) {
593
+ const feeCurrencyId = this.safeString(trade, 'fee_ccy', market['quote']);
594
+ fee = {
595
+ 'currency': this.safeCurrencyCode(feeCurrencyId),
596
+ 'cost': feeCost,
597
+ };
598
+ }
327
599
  return this.safeTrade({
328
- 'id': this.safeString(trade, 'id'),
600
+ 'id': this.safeString(trade, 'deal_id'),
329
601
  'info': trade,
330
602
  'timestamp': timestamp,
331
603
  'datetime': this.iso8601(timestamp),
332
- 'symbol': this.safeSymbol(undefined, market, undefined, defaultType),
333
- 'order': undefined,
604
+ 'symbol': this.safeSymbol(marketId, market, undefined, defaultType),
605
+ 'order': this.safeString(trade, 'order_id'),
334
606
  'type': undefined,
335
- 'side': this.safeString(trade, 'type'),
336
- 'takerOrMaker': undefined,
607
+ 'side': this.safeString(trade, 'side'),
608
+ 'takerOrMaker': this.safeString(trade, 'role'),
337
609
  'price': this.safeString(trade, 'price'),
338
610
  'amount': this.safeString(trade, 'amount'),
339
611
  'cost': undefined,
340
- 'fee': undefined,
612
+ 'fee': fee,
341
613
  }, market);
342
614
  }
343
- handleOHLCV(client, message) {
344
- //
345
- // spot
346
- // {
347
- // "error": null,
348
- // "result": [
349
- // [
350
- // 1673846940,
351
- // "21148.74",
352
- // "21148.38",
353
- // "21148.75",
354
- // "21138.66",
355
- // "1.57060173",
356
- // "33214.9138778914"
357
- // ],
358
- // ]
359
- // "id": 1,
360
- // }
361
- // swap
362
- // {
363
- // "method": "kline.update",
364
- // "params": [
365
- // [
366
- // 1654019640, // timestamp
367
- // "32061.99", // open
368
- // "32061.28", // close
369
- // "32061.99", // high
370
- // "32061.28", // low
371
- // "0.1285", // amount base
372
- // "4119.943736" // amount quote
373
- // ]
374
- // ],
375
- // "id": null
376
- // }
377
- //
378
- const candles = this.safeValue2(message, 'params', 'result', []);
379
- const messageHash = 'ohlcv';
380
- const id = this.safeString(message, 'id');
381
- const ohlcvs = this.parseOHLCVs(candles);
382
- if (id !== undefined) {
383
- // spot subscription response
384
- client.resolve(ohlcvs, messageHash);
385
- return;
386
- }
387
- const keys = Object.keys(this.ohlcvs);
388
- const keysLength = keys.length;
389
- if (keysLength === 0) {
390
- this.ohlcvs['unknown'] = {};
391
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
392
- const stored = new Cache.ArrayCacheByTimestamp(limit);
393
- this.ohlcvs['unknown']['unknown'] = stored;
394
- }
395
- const ohlcv = this.ohlcvs['unknown']['unknown'];
396
- for (let i = 0; i < ohlcvs.length; i++) {
397
- const candle = ohlcvs[i];
398
- ohlcv.append(candle);
399
- }
400
- client.resolve(ohlcv, messageHash);
401
- }
402
615
  async watchTicker(symbol, params = {}) {
403
616
  /**
404
617
  * @method
405
618
  * @name coinex#watchTicker
406
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket007_state_subscribe
407
619
  * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
620
+ * @see https://docs.coinex.com/api/v2/spot/market/ws/market
621
+ * @see https://docs.coinex.com/api/v2/futures/market/ws/market-state
408
622
  * @param {string} symbol unified symbol of the market to fetch the ticker for
409
623
  * @param {object} [params] extra parameters specific to the exchange API endpoint
410
624
  * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
411
625
  */
626
+ await this.loadMarkets();
627
+ const market = this.market(symbol);
412
628
  const tickers = await this.watchTickers([symbol], params);
413
- return this.safeValue(tickers, symbol);
629
+ return tickers[market['symbol']];
414
630
  }
415
631
  async watchTickers(symbols = undefined, params = {}) {
416
632
  /**
417
633
  * @method
418
634
  * @name coinex#watchTickers
419
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket007_state_subscribe
420
635
  * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
636
+ * @see https://docs.coinex.com/api/v2/spot/market/ws/market
637
+ * @see https://docs.coinex.com/api/v2/futures/market/ws/market-state
421
638
  * @param {string[]} symbols unified symbol of the market to fetch the ticker for
422
639
  * @param {object} [params] extra parameters specific to the exchange API endpoint
423
640
  * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
424
641
  */
425
642
  await this.loadMarkets();
426
- symbols = this.marketSymbols(symbols);
643
+ const marketIds = this.marketIds(symbols);
644
+ let market = undefined;
645
+ const messageHashes = [];
646
+ const symbolsDefined = (symbols !== undefined);
647
+ if (symbolsDefined) {
648
+ for (let i = 0; i < symbols.length; i++) {
649
+ const symbol = symbols[i];
650
+ market = this.market(symbol);
651
+ messageHashes.push('tickers::' + market['symbol']);
652
+ }
653
+ }
654
+ else {
655
+ messageHashes.push('tickers');
656
+ }
427
657
  let type = undefined;
428
- [type, params] = this.handleMarketTypeAndParams('watchTickers', undefined, params);
658
+ [type, params] = this.handleMarketTypeAndParams('watchTickers', market, params);
429
659
  const url = this.urls['api']['ws'][type];
430
- let messageHash = 'tickers';
431
- if (symbols !== undefined) {
432
- messageHash = 'tickers::' + symbols.join(',');
433
- }
660
+ const subscriptionHashes = ['all@ticker'];
434
661
  const subscribe = {
435
662
  'method': 'state.subscribe',
663
+ 'params': { 'market_list': marketIds },
436
664
  'id': this.requestId(),
437
- 'params': [],
438
665
  };
439
- const request = this.deepExtend(subscribe, params);
440
- const newTickers = await this.watch(url, messageHash, request, messageHash);
666
+ const result = await this.watchMultiple(url, messageHashes, this.deepExtend(subscribe, params), subscriptionHashes);
441
667
  if (this.newUpdates) {
442
- return newTickers;
668
+ return result;
443
669
  }
444
670
  return this.filterByArray(this.tickers, 'symbol', symbols);
445
671
  }
@@ -447,179 +673,139 @@ class coinex extends coinex$1 {
447
673
  /**
448
674
  * @method
449
675
  * @name coinex#watchTrades
450
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket012_deal_subcribe
451
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures002_websocket019_deal_subcribe
452
676
  * @description get the list of most recent trades for a particular symbol
677
+ * @see https://docs.coinex.com/api/v2/spot/market/ws/market-deals
678
+ * @see https://docs.coinex.com/api/v2/futures/market/ws/market-deals
453
679
  * @param {string} symbol unified symbol of the market to fetch trades for
454
680
  * @param {int} [since] timestamp in ms of the earliest trade to fetch
455
681
  * @param {int} [limit] the maximum amount of trades to fetch
456
682
  * @param {object} [params] extra parameters specific to the exchange API endpoint
457
683
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
458
684
  */
685
+ params['callerMethodName'] = 'watchTrades';
686
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
687
+ }
688
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
689
+ /**
690
+ * @method
691
+ * @name coinex#watchTradesForSymbols
692
+ * @description watch the most recent trades for a list of symbols
693
+ * @see https://docs.coinex.com/api/v2/spot/market/ws/market-deals
694
+ * @see https://docs.coinex.com/api/v2/futures/market/ws/market-deals
695
+ * @param {string[]} symbols unified symbols of the markets to fetch trades for
696
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
697
+ * @param {int} [limit] the maximum amount of trades to fetch
698
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
699
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
700
+ */
459
701
  await this.loadMarkets();
460
- const market = this.market(symbol);
702
+ const subscribedSymbols = [];
703
+ const messageHashes = [];
704
+ let market = undefined;
705
+ let callerMethodName = undefined;
706
+ [callerMethodName, params] = this.handleParamString(params, 'callerMethodName', 'watchTradesForSymbols');
707
+ const symbolsDefined = (symbols !== undefined);
708
+ if (symbolsDefined) {
709
+ for (let i = 0; i < symbols.length; i++) {
710
+ const symbol = symbols[i];
711
+ market = this.market(symbol);
712
+ subscribedSymbols.push(market['id']);
713
+ messageHashes.push('trades:' + market['symbol']);
714
+ }
715
+ }
716
+ else {
717
+ messageHashes.push('trades');
718
+ }
461
719
  let type = undefined;
462
- [type, params] = this.handleMarketTypeAndParams('watchTrades', market, params);
720
+ [type, params] = this.handleMarketTypeAndParams(callerMethodName, market, params);
463
721
  const url = this.urls['api']['ws'][type];
464
- const messageHash = 'trades:' + symbol;
465
- const subscriptionHash = 'trades';
466
- const subscribedSymbols = this.safeValue(this.options, 'watchTradesSubscriptions', []);
467
- subscribedSymbols.push(market['id']);
468
- const message = {
722
+ const subscriptionHashes = ['trades'];
723
+ const subscribe = {
469
724
  'method': 'deals.subscribe',
470
- 'params': subscribedSymbols,
725
+ 'params': { 'market_list': subscribedSymbols },
471
726
  'id': this.requestId(),
472
727
  };
473
- this.options['watchTradesSubscriptions'] = subscribedSymbols;
474
- const request = this.deepExtend(message, params);
475
- const trades = await this.watch(url, messageHash, request, subscriptionHash);
728
+ const trades = await this.watchMultiple(url, messageHashes, this.deepExtend(subscribe, params), subscriptionHashes);
729
+ if (this.newUpdates) {
730
+ return trades;
731
+ }
476
732
  return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
477
733
  }
478
- async watchOrderBook(symbol, limit = undefined, params = {}) {
734
+ async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
479
735
  /**
480
736
  * @method
481
- * @name coinex#watchOrderBook
482
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket017_depth_subscribe_multi
483
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures002_websocket011_depth_subscribe_multi
737
+ * @name coinex#watchOrderBookForSymbols
484
738
  * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
485
- * @param {string} symbol unified symbol of the market to fetch the order book for
739
+ * @see https://docs.coinex.com/api/v2/spot/market/ws/market-depth
740
+ * @see https://docs.coinex.com/api/v2/futures/market/ws/market-depth
741
+ * @param {string[]} symbols unified array of symbols
486
742
  * @param {int} [limit] the maximum amount of order book entries to return
487
743
  * @param {object} [params] extra parameters specific to the exchange API endpoint
488
744
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
489
745
  */
490
746
  await this.loadMarkets();
491
- const market = this.market(symbol);
492
- symbol = market['symbol'];
747
+ const watchOrderBookSubscriptions = {};
748
+ const messageHashes = [];
749
+ let market = undefined;
493
750
  let type = undefined;
494
- [type, params] = this.handleMarketTypeAndParams('watchOrderBook', market, params);
495
- const url = this.urls['api']['ws'][type];
496
- const name = 'orderbook';
497
- const messageHash = name + ':' + symbol;
498
- const options = this.safeValue(this.options, 'watchOrderBook', {});
499
- const limits = this.safeValue(options, 'limits', []);
751
+ let callerMethodName = undefined;
752
+ [callerMethodName, params] = this.handleParamString(params, 'callerMethodName', 'watchOrderBookForSymbols');
753
+ [type, params] = this.handleMarketTypeAndParams(callerMethodName, undefined, params);
754
+ const options = this.safeDict(this.options, 'watchOrderBook', {});
755
+ const limits = this.safeList(options, 'limits', []);
500
756
  if (limit === undefined) {
501
- limit = this.safeValue(options, 'defaultLimit', 50);
757
+ limit = this.safeInteger(options, 'defaultLimit', 50);
502
758
  }
503
759
  if (!this.inArray(limit, limits)) {
504
- throw new errors.NotSupported(this.id + ' watchOrderBook() limit must be one of ' + limits.join(', '));
760
+ throw new errors.NotSupported(this.id + ' watchOrderBookForSymbols() limit must be one of ' + limits.join(', '));
505
761
  }
506
762
  const defaultAggregation = this.safeString(options, 'defaultAggregation', '0');
507
- const aggregations = this.safeValue(options, 'aggregations', []);
763
+ const aggregations = this.safeList(options, 'aggregations', []);
508
764
  const aggregation = this.safeString(params, 'aggregation', defaultAggregation);
509
765
  if (!this.inArray(aggregation, aggregations)) {
510
- throw new errors.NotSupported(this.id + ' watchOrderBook() aggregation must be one of ' + aggregations.join(', '));
766
+ throw new errors.NotSupported(this.id + ' watchOrderBookForSymbols() aggregation must be one of ' + aggregations.join(', '));
511
767
  }
512
768
  params = this.omit(params, 'aggregation');
513
- const watchOrderBookSubscriptions = this.safeValue(this.options, 'watchOrderBookSubscriptions', {});
514
- watchOrderBookSubscriptions[symbol] = [market['id'], limit, aggregation, true];
515
- const subscribe = {
516
- 'method': 'depth.subscribe_multi',
517
- 'id': this.requestId(),
518
- 'params': Object.values(watchOrderBookSubscriptions),
519
- };
520
- this.options['watchOrderBookSubscriptions'] = watchOrderBookSubscriptions;
521
- const subscriptionHash = this.hash(this.encode(this.json(watchOrderBookSubscriptions)), sha256.sha256);
522
- const request = this.deepExtend(subscribe, params);
523
- const orderbook = await this.watch(url, messageHash, request, subscriptionHash, request);
524
- return orderbook.limit();
525
- }
526
- async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
527
- /**
528
- * @method
529
- * @name coinex#watchOHLCV
530
- * @see https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures002_websocket023_kline_subscribe
531
- * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
532
- * @param {string} symbol unified symbol of the market to fetch OHLCV data for
533
- * @param {string} timeframe the length of time each candle represents
534
- * @param {int} [since] timestamp in ms of the earliest candle to fetch
535
- * @param {int} [limit] the maximum amount of candles to fetch
536
- * @param {object} [params] extra parameters specific to the exchange API endpoint
537
- * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
538
- */
539
- await this.loadMarkets();
540
- const market = this.market(symbol);
541
- symbol = market['symbol'];
542
- let type = undefined;
543
- [type, params] = this.handleMarketTypeAndParams('watchOHLCV', market, params);
544
- if (type !== 'swap') {
545
- throw new errors.NotSupported(this.id + ' watchOHLCV() is only supported for swap markets. Try using fetchOHLCV () instead');
769
+ const symbolsDefined = (symbols !== undefined);
770
+ if (symbolsDefined) {
771
+ for (let i = 0; i < symbols.length; i++) {
772
+ const symbol = symbols[i];
773
+ market = this.market(symbol);
774
+ messageHashes.push('orderbook:' + market['symbol']);
775
+ watchOrderBookSubscriptions[symbol] = [market['id'], limit, aggregation, true];
776
+ }
546
777
  }
547
- const url = this.urls['api']['ws'][type];
548
- const messageHash = 'ohlcv';
549
- const watchOHLCVWarning = this.safeBool(this.options, 'watchOHLCVWarning', true);
550
- const client = this.safeValue(this.clients, url, {});
551
- const clientSub = this.safeValue(client, 'subscriptions', {});
552
- const existingSubscription = this.safeValue(clientSub, messageHash);
553
- const subSymbol = this.safeString(existingSubscription, 'symbol');
554
- const subTimeframe = this.safeString(existingSubscription, 'timeframe');
555
- // due to nature of coinex response can only watch one symbol at a time
556
- if (watchOHLCVWarning && existingSubscription !== undefined && (subSymbol !== symbol || subTimeframe !== timeframe)) {
557
- throw new errors.ExchangeError(this.id + ' watchOHLCV() can only watch one symbol and timeframe at a time. To supress this warning set watchOHLCVWarning to false in options');
778
+ else {
779
+ messageHashes.push('orderbook');
558
780
  }
559
- const timeframes = this.safeValue(this.options, 'timeframes', {});
781
+ const marketList = Object.values(watchOrderBookSubscriptions);
560
782
  const subscribe = {
561
- 'method': 'kline.subscribe',
783
+ 'method': 'depth.subscribe',
784
+ 'params': { 'market_list': marketList },
562
785
  'id': this.requestId(),
563
- 'params': [
564
- market['id'],
565
- this.safeInteger(timeframes, timeframe),
566
- ],
567
786
  };
568
- const subscription = {
569
- 'symbol': symbol,
570
- 'timeframe': timeframe,
571
- };
572
- const request = this.deepExtend(subscribe, params);
573
- const ohlcvs = await this.watch(url, messageHash, request, messageHash, subscription);
787
+ const subscriptionHashes = this.hash(this.encode(this.json(watchOrderBookSubscriptions)), sha256.sha256);
788
+ const url = this.urls['api']['ws'][type];
789
+ const orderbooks = await this.watchMultiple(url, messageHashes, this.deepExtend(subscribe, params), subscriptionHashes);
574
790
  if (this.newUpdates) {
575
- limit = ohlcvs.getLimit(symbol, limit);
791
+ return orderbooks;
576
792
  }
577
- return this.filterBySinceLimit(ohlcvs, since, limit, 0);
793
+ return orderbooks.limit();
578
794
  }
579
- async fetchOHLCVWs(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
795
+ async watchOrderBook(symbol, limit = undefined, params = {}) {
580
796
  /**
581
797
  * @method
582
- * @name coinex#fetchOHLCV
583
- * @see https://viabtc.github.io/coinex_api_en_doc/spot/#docsspot004_websocket005_kline_query
584
- * @description query historical candlestick data containing the open, high, low, and close price, and the volume of a market
585
- * @param {string} symbol unified symbol of the market to query OHLCV data for
586
- * @param {string} timeframe the length of time each candle represents
587
- * @param {int|undefined} since timestamp in ms of the earliest candle to fetch
588
- * @param {int|undefined} limit the maximum amount of candles to fetch
589
- * @param {object} params extra parameters specific to the exchange API endpoint
590
- * @param {int|undefined} params.end the end time for spot markets, this.seconds () is set as default
591
- * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
798
+ * @name coinex#watchOrderBook
799
+ * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
800
+ * @see https://docs.coinex.com/api/v2/spot/market/ws/market-depth
801
+ * @see https://docs.coinex.com/api/v2/futures/market/ws/market-depth
802
+ * @param {string} symbol unified symbol of the market to fetch the order book for
803
+ * @param {int} [limit] the maximum amount of order book entries to return
804
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
805
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
592
806
  */
593
- await this.loadMarkets();
594
- const market = this.market(symbol);
595
- const [type, query] = this.handleMarketTypeAndParams('fetchOHLCV', market, params);
596
- const url = this.urls['api']['ws'][type];
597
- symbol = market['symbol'];
598
- const messageHash = 'ohlcv';
599
- const timeframes = this.safeValue(this.options, 'timeframes', {});
600
- timeframe = this.safeString(timeframes, timeframe, timeframe);
601
- if (since === undefined) {
602
- since = 1640995200; // January 1, 2022
603
- }
604
- const id = this.requestId();
605
- const subscribe = {
606
- 'method': 'kline.query',
607
- 'params': [
608
- market['id'],
609
- this.parseToInt(since / 1000),
610
- this.safeInteger(params, 'end', this.seconds()),
611
- this.parseToInt(timeframe),
612
- ],
613
- 'id': id,
614
- };
615
- const subscription = {
616
- 'id': id,
617
- 'future': messageHash,
618
- };
619
- const subscriptionHash = id;
620
- const request = this.deepExtend(subscribe, query);
621
- const ohlcvs = await this.watch(url, messageHash, request, subscriptionHash, subscription);
622
- return this.filterBySinceLimit(ohlcvs, since, limit, 0);
807
+ params['callerMethodName'] = 'watchOrderBook';
808
+ return await this.watchOrderBookForSymbols([symbol], limit, params);
623
809
  }
624
810
  handleDelta(bookside, delta) {
625
811
  const bidAsk = this.parseBidAsk(delta, 0, 1);
@@ -634,52 +820,54 @@ class coinex extends coinex$1 {
634
820
  //
635
821
  // {
636
822
  // "method": "depth.update",
637
- // "params": [
638
- // false,
639
- // {
823
+ // "data": {
824
+ // "market": "BTCUSDT",
825
+ // "is_full": true,
826
+ // "depth": {
640
827
  // "asks": [
641
- // ["46350.52", "1.07871851"],
642
- // ...
828
+ // [
829
+ // "30740.00",
830
+ // "0.31763545"
831
+ // ],
643
832
  // ],
644
833
  // "bids": [
645
- // ["46349.61", "0.04000000"],
646
- // ...
834
+ // [
835
+ // "30736.00",
836
+ // "0.04857373"
837
+ // ],
647
838
  // ],
648
- // "last": "46349.93",
649
- // "time": 1639987469166,
650
- // "checksum": 1533284725
651
- // },
652
- // "BTCUSDT"
653
- // ],
839
+ // "last": "30746.28",
840
+ // "updated_at": 1689152421692,
841
+ // "checksum": 2578768879
842
+ // }
843
+ // },
654
844
  // "id": null
655
845
  // }
656
846
  //
657
- const isSwap = client.url.indexOf('perpetual') >= 0;
658
- const marketType = isSwap ? 'swap' : 'spot';
659
- const params = this.safeValue(message, 'params', []);
660
- const fullOrderBook = this.safeValue(params, 0);
661
- let orderbook = this.safeValue(params, 1);
662
- const marketId = this.safeString(params, 2);
663
- const market = this.safeMarket(marketId, undefined, undefined, marketType);
847
+ const defaultType = this.safeString(this.options, 'defaultType');
848
+ const data = this.safeDict(message, 'data', {});
849
+ const depth = this.safeDict(data, 'depth', {});
850
+ const marketId = this.safeString(data, 'market');
851
+ const market = this.safeMarket(marketId, undefined, undefined, defaultType);
664
852
  const symbol = market['symbol'];
665
853
  const name = 'orderbook';
666
854
  const messageHash = name + ':' + symbol;
667
- const timestamp = this.safeInteger(orderbook, 'time');
855
+ const timestamp = this.safeInteger(depth, 'updated_at');
668
856
  const currentOrderBook = this.safeValue(this.orderbooks, symbol);
857
+ const fullOrderBook = this.safeBool(data, 'is_full', false);
669
858
  if (fullOrderBook) {
670
- const snapshot = this.parseOrderBook(orderbook, symbol, timestamp);
859
+ const snapshot = this.parseOrderBook(depth, symbol, timestamp);
671
860
  if (currentOrderBook === undefined) {
672
- orderbook = this.orderBook(snapshot);
673
- this.orderbooks[symbol] = orderbook;
861
+ this.orderbooks[symbol] = this.orderBook(snapshot);
674
862
  }
675
863
  else {
676
- orderbook = this.orderbooks[symbol];
864
+ const orderbook = this.orderbooks[symbol];
677
865
  orderbook.reset(snapshot);
678
866
  }
679
867
  }
680
868
  else {
681
- const asks = this.safeValue(orderbook, 'asks', []);
682
- const bids = this.safeValue(orderbook, 'bids', []);
869
+ const asks = this.safeList(depth, 'asks', []);
870
+ const bids = this.safeList(depth, 'bids', []);
683
871
  this.handleDeltas(currentOrderBook['asks'], asks);
684
872
  this.handleDeltas(currentOrderBook['bids'], bids);
685
873
  currentOrderBook['nonce'] = timestamp;
@@ -691,26 +879,59 @@ class coinex extends coinex$1 {
691
879
  client.resolve(this.orderbooks[symbol], messageHash);
692
880
  }
693
881
  async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
882
+ /**
883
+ * @method
884
+ * @name coinex#watchOrders
885
+ * @description watches information on multiple orders made by the user
886
+ * @see https://docs.coinex.com/api/v2/spot/order/ws/user-order
887
+ * @see https://docs.coinex.com/api/v2/futures/order/ws/user-order
888
+ * @param {string} symbol unified market symbol of the market orders were made in
889
+ * @param {int} [since] the earliest time in ms to fetch orders for
890
+ * @param {int} [limit] the maximum number of order structures to retrieve
891
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
892
+ * @param {bool} [params.trigger] if the orders to watch are trigger orders or not
893
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
894
+ */
694
895
  await this.loadMarkets();
695
- await this.authenticate(params);
896
+ const stop = this.safeBool2(params, 'trigger', 'stop');
897
+ params = this.omit(params, ['trigger', 'stop']);
696
898
  let messageHash = 'orders';
697
899
  let market = undefined;
698
- const [type, query] = this.handleMarketTypeAndParams('watchOrders', market, params);
699
- const message = {
700
- 'method': 'order.subscribe',
701
- 'id': this.requestId(),
702
- };
900
+ let marketList = undefined;
703
901
  if (symbol !== undefined) {
704
902
  market = this.market(symbol);
705
903
  symbol = market['symbol'];
706
- message['params'] = [market['id']];
904
+ }
905
+ let type = undefined;
906
+ [type, params] = this.handleMarketTypeAndParams('watchOrders', market, params, 'spot');
907
+ await this.authenticate(type);
908
+ if (symbol !== undefined) {
909
+ marketList = [market['id']];
707
910
  messageHash += ':' + symbol;
708
911
  }
709
912
  else {
710
- message['params'] = [];
913
+ marketList = [];
914
+ if (type === 'spot') {
915
+ messageHash += ':spot';
916
+ }
917
+ else {
918
+ messageHash += ':swap';
919
+ }
920
+ }
921
+ let method = undefined;
922
+ if (stop) {
923
+ method = 'stop.subscribe';
924
+ }
925
+ else {
926
+ method = 'order.subscribe';
711
927
  }
928
+ const message = {
929
+ 'method': method,
930
+ 'params': { 'market_list': marketList },
931
+ 'id': this.requestId(),
932
+ };
712
933
  const url = this.urls['api']['ws'][type];
713
- const request = this.deepExtend(message, query);
934
+ const request = this.deepExtend(message, params);
714
935
  const orders = await this.watch(url, messageHash, request, messageHash, request);
715
936
  if (this.newUpdates) {
716
937
  limit = orders.getLimit(symbol, limit);
@@ -719,94 +940,126 @@ class coinex extends coinex$1 {
719
940
  }
720
941
  handleOrders(client, message) {
721
942
  //
722
- // spot
943
+ // spot
723
944
  //
724
- // {
725
- // "method": "order.update",
726
- // "params": [
727
- // 1,
728
- // {
729
- // "id": 77782469357,
730
- // "type": 1,
731
- // "side": 2,
732
- // "user": 1849116,
733
- // "account": 0,
734
- // "option": 2,
735
- // "ctime": 1653961043.048967,
736
- // "mtime": 1653961043.048967,
737
- // "market": "BTCUSDT",
738
- // "source": "web",
739
- // "client_id": '',
740
- // "price": "1.00",
741
- // "amount": "1.00000000",
742
- // "taker_fee": "0.0020",
743
- // "maker_fee": "0.0020",
744
- // "left": "1.00000000",
745
- // "deal_stock": "0",
746
- // "deal_money": "0",
747
- // "money_fee": "0",
748
- // "stock_fee": "0",
749
- // "asset_fee": "0",
750
- // "fee_discount": "1",
751
- // "last_deal_amount": "0",
752
- // "last_deal_price": "0",
753
- // "last_deal_time": 0,
754
- // "last_deal_id": 0,
755
- // "last_role": 0,
756
- // "fee_asset": null,
757
- // "stop_id": 0
758
- // }
759
- // ],
760
- // "id": null
761
- // }
945
+ // {
946
+ // "method": "order.update",
947
+ // "data": {
948
+ // "event": "put",
949
+ // "order": {
950
+ // "order_id": 12750,
951
+ // "market": "BTCUSDT",
952
+ // "margin_market": "BTCUSDT",
953
+ // "type": "limit",
954
+ // "side": "buy",
955
+ // "price": "5999.00",
956
+ // "amount": "1.50000000",
957
+ // "unfill_amount": "1.50000000",
958
+ // "fill_value": "1.50000000",
959
+ // "taker_fee_rate": "0.0001",
960
+ // "maker_fee_rate": "0.0001",
961
+ // "base_ccy_fee": "0.0001",
962
+ // "quote_ccy_fee": "0.0001",
963
+ // "discount_ccy_fee": "0.0001",
964
+ // "last_fill_amount": "0",
965
+ // "last_fill_price": "0",
966
+ // "client_id": "buy1_1234",
967
+ // "created_at": 1689152421692,
968
+ // "updated_at": 1689152421692,
969
+ // }
970
+ // },
971
+ // "id": null
972
+ // }
762
973
  //
763
- // swap
974
+ // spot stop
975
+ //
976
+ // {
977
+ // "method": "stop.update",
978
+ // "data": {
979
+ // "event": 1,
980
+ // "stop": {
981
+ // "stop_id": 102067022299,
982
+ // "market": "BTCUSDT",
983
+ // "margin_market": "BTCUSDT",
984
+ // "type": "limit",
985
+ // "side": "buy",
986
+ // "price": "20000.00",
987
+ // "amount": "0.10000000",
988
+ // "trigger_price": "20000.00",
989
+ // "trigger_direction": "lower",
990
+ // "taker_fee_rate": "0.0016",
991
+ // "maker_fee_rate": "0.0016",
992
+ // "status": "active_success",
993
+ // "client_id": "",
994
+ // "created_at": 1689152996689,
995
+ // "updated_at": 1689152996689,
996
+ // }
997
+ // },
998
+ // "id": null
999
+ // }
1000
+ //
1001
+ // swap
1002
+ //
1003
+ // {
1004
+ // "method": "order.update",
1005
+ // "data": {
1006
+ // "event": "put",
1007
+ // "order": {
1008
+ // "order_id": 98388656341,
1009
+ // "stop_id": 0,
1010
+ // "market": "BTCUSDT",
1011
+ // "side": "buy",
1012
+ // "type": "limit",
1013
+ // "amount": "0.0010",
1014
+ // "price": "50000.00",
1015
+ // "unfilled_amount": "0.0010",
1016
+ // "filled_amount": "0",
1017
+ // "filled_value": "0",
1018
+ // "fee": "0",
1019
+ // "fee_ccy": "USDT",
1020
+ // "taker_fee_rate": "0.00046",
1021
+ // "maker_fee_rate": "0.00000000000000000000",
1022
+ // "client_id": "",
1023
+ // "last_filled_amount": "0.0010",
1024
+ // "last_filled_price": "30721.35",
1025
+ // "created_at": 1689145715129,
1026
+ // "updated_at": 1689145715129
1027
+ // }
1028
+ // },
1029
+ // "id": null
1030
+ // }
1031
+ //
1032
+ // swap stop
1033
+ //
1034
+ // {
1035
+ // "method": "stop.update",
1036
+ // "data": {
1037
+ // "event": "put",
1038
+ // "stop": {
1039
+ // "stop_id": 98389557871,
1040
+ // "market": "BTCUSDT",
1041
+ // "side": "sell",
1042
+ // "type": "limit",
1043
+ // "price": "20000.00",
1044
+ // "amount": "0.0100",
1045
+ // "trigger_price": "20000.00",
1046
+ // "trigger_direction": "higer",
1047
+ // "trigger_price_type": "index_price",
1048
+ // "taker_fee_rate": "0.00046",
1049
+ // "maker_fee_rate": "0.00026",
1050
+ // "client_id": "",
1051
+ // "created_at": 1689146382674,
1052
+ // "updated_at": 1689146382674
1053
+ // }
1054
+ // },
1055
+ // "id": null
1056
+ // }
764
1057
  //
765
- // {
766
- // "method": "order.update",
767
- // "params": [
768
- // 1,
769
- // {
770
- // "order_id": 23423462821,
771
- // "position_id": 0,
772
- // "stop_id": 0,
773
- // "market": "BTCUSDT",
774
- // "type": 1,
775
- // "side": 2,
776
- // "target": 0,
777
- // "effect_type": 1,
778
- // "user_id": 1849116,
779
- // "create_time": 1653961509.25049,
780
- // "update_time": 1653961509.25049,
781
- // "source": "web",
782
- // "price": "1.00",
783
- // "amount": "1.0000",
784
- // "taker_fee": "0.00050",
785
- // "maker_fee": "0.00030",
786
- // "left": "1.0000",
787
- // "deal_stock": "0.00000000000000000000",
788
- // "deal_fee": "0.00000000000000000000",
789
- // "deal_profit": "0.00000000000000000000",
790
- // "last_deal_amount": "0.00000000000000000000",
791
- // "last_deal_price": "0.00000000000000000000",
792
- // "last_deal_time": 0,
793
- // "last_deal_id": 0,
794
- // "last_deal_type": 0,
795
- // "last_deal_role": 0,
796
- // "client_id": '',
797
- // "fee_asset": '',
798
- // "fee_discount": "0.00000000000000000000",
799
- // "deal_asset_fee": "0.00000000000000000000",
800
- // "leverage": "3",
801
- // "position_type": 2
802
- // }
803
- // ],
804
- // "id": null
805
- // }
806
- //
807
- const params = this.safeValue(message, 'params', []);
808
- const order = this.safeValue(params, 1, {});
1058
+ const data = this.safeDict(message, 'data', {});
1059
+ const order = this.safeDict2(data, 'order', 'stop', {});
809
1060
  const parsedOrder = this.parseWsOrder(order);
1061
+ const symbol = parsedOrder['symbol'];
1062
+ const market = this.market(symbol);
810
1063
  if (this.orders === undefined) {
811
1064
  const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
812
1065
  this.orders = new Cache.ArrayCacheBySymbolById(limit);
@@ -814,138 +1067,110 @@ class coinex extends coinex$1 {
814
1067
  const orders = this.orders;
815
1068
  orders.append(parsedOrder);
816
1069
  let messageHash = 'orders';
817
- client.resolve(this.orders, messageHash);
818
- messageHash += ':' + parsedOrder['symbol'];
1070
+ const messageWithType = messageHash + ':' + market['type'];
1071
+ client.resolve(this.orders, messageWithType);
1072
+ messageHash += ':' + symbol;
819
1073
  client.resolve(this.orders, messageHash);
820
1074
  }
821
1075
  parseWsOrder(order, market = undefined) {
822
1076
  //
823
- // spot
1077
+ // spot
824
1078
  //
825
- // {
826
- // "id": 77782469357,
827
- // "type": 1,
828
- // "side": 2,
829
- // "user": 1849116,
830
- // "account": 0,
831
- // "option": 2,
832
- // "ctime": 1653961043.048967,
833
- // "mtime": 1653961043.048967,
834
- // "market": "BTCUSDT",
835
- // "source": "web",
836
- // "client_id": '',
837
- // "price": "1.00",
838
- // "amount": "1.00000000",
839
- // "taker_fee": "0.0020",
840
- // "maker_fee": "0.0020",
841
- // "left": "1.00000000",
842
- // "deal_stock": "0",
843
- // "deal_money": "0",
844
- // "money_fee": "0",
845
- // "stock_fee": "0",
846
- // "asset_fee": "0",
847
- // "fee_discount": "1",
848
- // "last_deal_amount": "0",
849
- // "last_deal_price": "0",
850
- // "last_deal_time": 0,
851
- // "last_deal_id": 0,
852
- // "last_role": 0,
853
- // "fee_asset": null,
854
- // "stop_id": 0
855
- // }
1079
+ // {
1080
+ // "order_id": 12750,
1081
+ // "market": "BTCUSDT",
1082
+ // "margin_market": "BTCUSDT",
1083
+ // "type": "limit",
1084
+ // "side": "buy",
1085
+ // "price": "5999.00",
1086
+ // "amount": "1.50000000",
1087
+ // "unfill_amount": "1.50000000",
1088
+ // "fill_value": "1.50000000",
1089
+ // "taker_fee_rate": "0.0001",
1090
+ // "maker_fee_rate": "0.0001",
1091
+ // "base_ccy_fee": "0.0001",
1092
+ // "quote_ccy_fee": "0.0001",
1093
+ // "discount_ccy_fee": "0.0001",
1094
+ // "last_fill_amount": "0",
1095
+ // "last_fill_price": "0",
1096
+ // "client_id": "buy1_1234",
1097
+ // "created_at": 1689152421692,
1098
+ // "updated_at": 1689152421692,
1099
+ // }
856
1100
  //
857
- // swap
1101
+ // spot stop
858
1102
  //
859
- // {
860
- // "order_id": 23423462821,
861
- // "position_id": 0,
862
- // "stop_id": 0,
863
- // "market": "BTCUSDT",
864
- // "type": 1,
865
- // "side": 2,
866
- // "target": 0,
867
- // "effect_type": 1,
868
- // "user_id": 1849116,
869
- // "create_time": 1653961509.25049,
870
- // "update_time": 1653961509.25049,
871
- // "source": "web",
872
- // "price": "1.00",
873
- // "amount": "1.0000",
874
- // "taker_fee": "0.00050",
875
- // "maker_fee": "0.00030",
876
- // "left": "1.0000",
877
- // "deal_stock": "0.00000000000000000000",
878
- // "deal_fee": "0.00000000000000000000",
879
- // "deal_profit": "0.00000000000000000000",
880
- // "last_deal_amount": "0.00000000000000000000",
881
- // "last_deal_price": "0.00000000000000000000",
882
- // "last_deal_time": 0,
883
- // "last_deal_id": 0,
884
- // "last_deal_type": 0,
885
- // "last_deal_role": 0,
886
- // "client_id": '',
887
- // "fee_asset": '',
888
- // "fee_discount": "0.00000000000000000000",
889
- // "deal_asset_fee": "0.00000000000000000000",
890
- // "leverage": "3",
891
- // "position_type": 2
892
- // }
893
- //
894
- // order.update_stop
895
- //
896
- // {
897
- // "id": 78006745870,
898
- // "type": 1,
899
- // "side": 2,
900
- // "user": 1849116,
901
- // "account": 1,
902
- // "option": 70,
903
- // "direction": 1,
904
- // "ctime": 1654171725.131976,
905
- // "mtime": 1654171725.131976,
906
- // "market": "BTCUSDT",
907
- // "source": "web",
908
- // "client_id": '',
909
- // "stop_price": "1.00",
910
- // "price": "1.00",
911
- // "amount": "1.00000000",
912
- // "taker_fee": "0.0020",
913
- // "maker_fee": "0.0020",
914
- // "fee_discount": "1",
915
- // "fee_asset": null,
916
- // "status": 0
917
- // }
918
- //
919
- const timestamp = this.safeTimestamp2(order, 'update_time', 'mtime');
1103
+ // {
1104
+ // "stop_id": 102067022299,
1105
+ // "market": "BTCUSDT",
1106
+ // "margin_market": "BTCUSDT",
1107
+ // "type": "limit",
1108
+ // "side": "buy",
1109
+ // "price": "20000.00",
1110
+ // "amount": "0.10000000",
1111
+ // "trigger_price": "20000.00",
1112
+ // "trigger_direction": "lower",
1113
+ // "taker_fee_rate": "0.0016",
1114
+ // "maker_fee_rate": "0.0016",
1115
+ // "status": "active_success",
1116
+ // "client_id": "",
1117
+ // "created_at": 1689152996689,
1118
+ // "updated_at": 1689152996689,
1119
+ // }
1120
+ //
1121
+ // swap
1122
+ //
1123
+ // {
1124
+ // "order_id": 98388656341,
1125
+ // "stop_id": 0,
1126
+ // "market": "BTCUSDT",
1127
+ // "side": "buy",
1128
+ // "type": "limit",
1129
+ // "amount": "0.0010",
1130
+ // "price": "50000.00",
1131
+ // "unfilled_amount": "0.0010",
1132
+ // "filled_amount": "0",
1133
+ // "filled_value": "0",
1134
+ // "fee": "0",
1135
+ // "fee_ccy": "USDT",
1136
+ // "taker_fee_rate": "0.00046",
1137
+ // "maker_fee_rate": "0.00000000000000000000",
1138
+ // "client_id": "",
1139
+ // "last_filled_amount": "0.0010",
1140
+ // "last_filled_price": "30721.35",
1141
+ // "created_at": 1689145715129,
1142
+ // "updated_at": 1689145715129
1143
+ // }
1144
+ //
1145
+ // swap stop
1146
+ //
1147
+ // {
1148
+ // "stop_id": 98389557871,
1149
+ // "market": "BTCUSDT",
1150
+ // "side": "sell",
1151
+ // "type": "limit",
1152
+ // "price": "20000.00",
1153
+ // "amount": "0.0100",
1154
+ // "trigger_price": "20000.00",
1155
+ // "trigger_direction": "higer",
1156
+ // "trigger_price_type": "index_price",
1157
+ // "taker_fee_rate": "0.00046",
1158
+ // "maker_fee_rate": "0.00026",
1159
+ // "client_id": "",
1160
+ // "created_at": 1689146382674,
1161
+ // "updated_at": 1689146382674
1162
+ // }
1163
+ //
1164
+ const timestamp = this.safeInteger(order, 'created_at');
920
1165
  const marketId = this.safeString(order, 'market');
921
- const typeCode = this.safeString(order, 'type');
922
- const type = this.safeString({
923
- '1': 'limit',
924
- '2': 'market',
925
- }, typeCode);
926
- const sideCode = this.safeString(order, 'side');
927
- const side = this.safeString({
928
- '1': 'sell',
929
- '2': 'buy',
930
- }, sideCode);
931
- const remaining = this.safeString(order, 'left');
932
- const amount = this.safeString(order, 'amount');
933
1166
  const status = this.safeString(order, 'status');
934
- const defaultType = this.safeString(this.options, 'defaultType');
1167
+ const isSpot = ('margin_market' in order);
1168
+ const defaultType = isSpot ? 'spot' : 'swap';
935
1169
  market = this.safeMarket(marketId, market, undefined, defaultType);
936
- let cost = this.safeString(order, 'deal_money');
937
- let filled = this.safeString(order, 'deal_stock');
938
- let average = undefined;
939
- if (market['swap']) {
940
- const leverage = this.safeString(order, 'leverage');
941
- cost = Precise["default"].stringDiv(filled, leverage);
942
- average = Precise["default"].stringDiv(filled, amount);
943
- filled = undefined;
944
- }
945
1170
  let fee = undefined;
946
- const feeCost = this.omitZero(this.safeString(order, 'money_fee'));
1171
+ const feeCost = this.omitZero(this.safeString2(order, 'fee', 'quote_ccy_fee'));
947
1172
  if (feeCost !== undefined) {
948
- const feeCurrencyId = this.safeString(order, 'fee_asset', market['quote']);
1173
+ const feeCurrencyId = this.safeString(order, 'fee_ccy', market['quote']);
949
1174
  fee = {
950
1175
  'currency': this.safeCurrencyCode(feeCurrencyId),
951
1176
  'cost': feeCost,
@@ -953,24 +1178,24 @@ class coinex extends coinex$1 {
953
1178
  }
954
1179
  return this.safeOrder({
955
1180
  'info': order,
956
- 'id': this.safeString2(order, 'order_id', 'id'),
1181
+ 'id': this.safeString2(order, 'order_id', 'stop_id'),
957
1182
  'clientOrderId': this.safeString(order, 'client_id'),
958
1183
  'datetime': this.iso8601(timestamp),
959
1184
  'timestamp': timestamp,
960
- 'lastTradeTimestamp': this.safeTimestamp(order, 'last_deal_time'),
1185
+ 'lastTradeTimestamp': this.safeInteger(order, 'updated_at'),
961
1186
  'symbol': market['symbol'],
962
- 'type': type,
1187
+ 'type': this.safeString(order, 'type'),
963
1188
  'timeInForce': undefined,
964
1189
  'postOnly': undefined,
965
- 'side': side,
1190
+ 'side': this.safeString(order, 'side'),
966
1191
  'price': this.safeString(order, 'price'),
967
- 'stopPrice': this.safeString(order, 'stop_price'),
968
- 'triggerPrice': this.safeString(order, 'stop_price'),
969
- 'amount': amount,
970
- 'filled': filled,
971
- 'remaining': remaining,
972
- 'cost': cost,
973
- 'average': average,
1192
+ 'stopPrice': this.safeString(order, 'trigger_price'),
1193
+ 'triggerPrice': this.safeString(order, 'trigger_price'),
1194
+ 'amount': this.safeString(order, 'amount'),
1195
+ 'filled': this.safeString2(order, 'filled_amount', 'fill_value'),
1196
+ 'remaining': this.safeString2(order, 'unfilled_amount', 'unfill_amount'),
1197
+ 'cost': undefined,
1198
+ 'average': undefined,
974
1199
  'status': this.parseWsOrderStatus(status),
975
1200
  'fee': fee,
976
1201
  'trades': undefined,
@@ -978,25 +1203,116 @@ class coinex extends coinex$1 {
978
1203
  }
979
1204
  parseWsOrderStatus(status) {
980
1205
  const statuses = {
981
- '0': 'pending',
982
- '1': 'ok',
1206
+ 'active_success': 'open',
1207
+ 'active_fail': 'canceled',
1208
+ 'cancel': 'canceled',
983
1209
  };
984
1210
  return this.safeString(statuses, status, status);
985
1211
  }
1212
+ async watchBidsAsks(symbols = undefined, params = {}) {
1213
+ /**
1214
+ * @method
1215
+ * @name coinex#watchBidsAsks
1216
+ * @description watches best bid & ask for symbols
1217
+ * @see https://docs.coinex.com/api/v2/spot/market/ws/market-bbo
1218
+ * @see https://docs.coinex.com/api/v2/futures/market/ws/market-bbo
1219
+ * @param {string[]} [symbols] unified symbol of the market to fetch the ticker for
1220
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1221
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1222
+ */
1223
+ await this.loadMarkets();
1224
+ const marketIds = this.marketIds(symbols);
1225
+ const messageHashes = [];
1226
+ let market = undefined;
1227
+ const symbolsDefined = (symbols !== undefined);
1228
+ if (symbolsDefined) {
1229
+ for (let i = 0; i < symbols.length; i++) {
1230
+ const symbol = symbols[i];
1231
+ market = this.market(symbol);
1232
+ messageHashes.push('bidsasks:' + market['symbol']);
1233
+ }
1234
+ }
1235
+ else {
1236
+ messageHashes.push('bidsasks');
1237
+ }
1238
+ let type = undefined;
1239
+ [type, params] = this.handleMarketTypeAndParams('watchBidsAsks', market, params);
1240
+ const url = this.urls['api']['ws'][type];
1241
+ const subscriptionHashes = ['all@bidsasks'];
1242
+ const subscribe = {
1243
+ 'method': 'bbo.subscribe',
1244
+ 'params': { 'market_list': marketIds },
1245
+ 'id': this.requestId(),
1246
+ };
1247
+ const result = await this.watchMultiple(url, messageHashes, this.deepExtend(subscribe, params), subscriptionHashes);
1248
+ if (this.newUpdates) {
1249
+ return result;
1250
+ }
1251
+ return this.filterByArray(this.bidsasks, 'symbol', symbols);
1252
+ }
1253
+ handleBidAsk(client, message) {
1254
+ //
1255
+ // {
1256
+ // "method": "bbo.update",
1257
+ // "data": {
1258
+ // "market": "BTCUSDT",
1259
+ // "updated_at": 1656660154,
1260
+ // "best_bid_price": "20000",
1261
+ // "best_bid_size": "0.1",
1262
+ // "best_ask_price": "20001",
1263
+ // "best_ask_size": "0.15"
1264
+ // },
1265
+ // "id": null
1266
+ // }
1267
+ //
1268
+ const data = this.safeDict(message, 'data', {});
1269
+ const parsedTicker = this.parseWsBidAsk(data);
1270
+ const symbol = parsedTicker['symbol'];
1271
+ this.bidsasks[symbol] = parsedTicker;
1272
+ const messageHash = 'bidsasks:' + symbol;
1273
+ client.resolve(parsedTicker, messageHash);
1274
+ }
1275
+ parseWsBidAsk(ticker, market = undefined) {
1276
+ //
1277
+ // {
1278
+ // "market": "BTCUSDT",
1279
+ // "updated_at": 1656660154,
1280
+ // "best_bid_price": "20000",
1281
+ // "best_bid_size": "0.1",
1282
+ // "best_ask_price": "20001",
1283
+ // "best_ask_size": "0.15"
1284
+ // }
1285
+ //
1286
+ const defaultType = this.safeString(this.options, 'defaultType');
1287
+ const marketId = this.safeString(ticker, 'market');
1288
+ market = this.safeMarket(marketId, market, undefined, defaultType);
1289
+ const timestamp = this.safeTimestamp(ticker, 'updated_at');
1290
+ return this.safeTicker({
1291
+ 'symbol': this.safeSymbol(marketId, market, undefined, defaultType),
1292
+ 'timestamp': timestamp,
1293
+ 'datetime': this.iso8601(timestamp),
1294
+ 'ask': this.safeNumber(ticker, 'best_ask_price'),
1295
+ 'askVolume': this.safeNumber(ticker, 'best_ask_size'),
1296
+ 'bid': this.safeNumber(ticker, 'best_bid_price'),
1297
+ 'bidVolume': this.safeNumber(ticker, 'best_bid_size'),
1298
+ 'info': ticker,
1299
+ }, market);
1300
+ }
986
1301
  handleMessage(client, message) {
987
- const error = this.safeValue(message, 'error');
1302
+ const method = this.safeString(message, 'method');
1303
+ const error = this.safeString(message, 'message');
988
1304
  if (error !== undefined) {
989
- throw new errors.ExchangeError(this.id + ' ' + this.json(error));
1305
+ this.handleErrors(undefined, undefined, client.url, method, undefined, this.json(error), message, undefined, undefined);
990
1306
  }
991
- const method = this.safeString(message, 'method');
992
1307
  const handlers = {
993
1308
  'state.update': this.handleTicker,
994
- 'asset.update': this.handleBalance,
1309
+ 'balance.update': this.handleBalance,
995
1310
  'deals.update': this.handleTrades,
1311
+ 'user_deals.update': this.handleMyTrades,
996
1312
  'depth.update': this.handleOrderBook,
997
1313
  'order.update': this.handleOrders,
998
- 'kline.update': this.handleOHLCV,
999
- 'order.update_stop': this.handleOrders,
1314
+ 'stop.update': this.handleOrders,
1315
+ 'bbo.update': this.handleBidAsk,
1000
1316
  };
1001
1317
  const handler = this.safeValue(handlers, method);
1002
1318
  if (handler !== undefined) {
@@ -1005,35 +1321,65 @@ class coinex extends coinex$1 {
1005
1321
  }
1006
1322
  this.handleSubscriptionStatus(client, message);
1007
1323
  }
1324
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
1325
+ if (response === undefined) {
1326
+ return undefined;
1327
+ }
1328
+ //
1329
+ // { "id": 1, "code": 20001, "message": "invalid argument" }
1330
+ // { "id": 2, "code": 21001, "message": "require auth" }
1331
+ // { "id": 1, "code": 21002, "message": "Signature Incorrect" }
1332
+ //
1333
+ const message = this.safeStringLower(response, 'message');
1334
+ const isErrorMessage = (message !== undefined) && (message !== 'ok');
1335
+ const errorCode = this.safeString(response, 'code');
1336
+ const isErrorCode = (errorCode !== undefined) && (errorCode !== '0');
1337
+ if (isErrorCode || isErrorMessage) {
1338
+ const feedback = this.id + ' ' + body;
1339
+ this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
1340
+ this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
1341
+ throw new errors.ExchangeError(feedback);
1342
+ }
1343
+ return undefined;
1344
+ }
1008
1345
  handleAuthenticationMessage(client, message) {
1346
+ //
1347
+ // success
1009
1348
  //
1010
1349
  // {
1011
- // "error": null,
1012
- // "result": {
1013
- // "status": "success"
1014
- // },
1015
- // "id": 1
1350
+ // "id": 1,
1351
+ // "code": 0,
1352
+ // "message": "OK"
1353
+ // }
1354
+ //
1355
+ // fail
1356
+ //
1357
+ // {
1358
+ // "id": 1,
1359
+ // "code": 21002,
1360
+ // "message": ""
1016
1361
  // }
1017
1362
  //
1018
- const messageHashSpot = 'authenticated:spot';
1019
- const messageHashSwap = 'authenticated:swap';
1020
- // client.resolve (message, messageHashSpot);
1021
- // client.resolve (message, messageHashSwap);
1022
- const spotFuture = this.safeValue(client.futures, messageHashSpot);
1023
- spotFuture.resolve(true);
1024
- const swapFutures = this.safeValue(client.futures, messageHashSwap);
1025
- swapFutures.resolve(true);
1026
- return message;
1363
+ const status = this.safeStringLower(message, 'message');
1364
+ const errorCode = this.safeString(message, 'code');
1365
+ const messageHash = 'authenticated';
1366
+ if ((status === 'ok') || (errorCode === '0')) {
1367
+ const future = this.safeValue(client.futures, messageHash);
1368
+ future.resolve(true);
1369
+ }
1370
+ else {
1371
+ const error = new errors.AuthenticationError(this.json(message));
1372
+ client.reject(error, messageHash);
1373
+ if (messageHash in client.subscriptions) {
1374
+ delete client.subscriptions[messageHash];
1375
+ }
1376
+ }
1027
1377
  }
1028
1378
  handleSubscriptionStatus(client, message) {
1029
1379
  const id = this.safeInteger(message, 'id');
1030
1380
  const subscription = this.safeValue(client.subscriptions, id);
1031
1381
  if (subscription !== undefined) {
1032
1382
  const futureIndex = this.safeString(subscription, 'future');
1033
- if (futureIndex === 'ohlcv') {
1034
- this.handleOHLCV(client, message);
1035
- return;
1036
- }
1037
1383
  const future = this.safeValue(client.futures, futureIndex);
1038
1384
  if (future !== undefined) {
1039
1385
  future.resolve(true);
@@ -1041,66 +1387,35 @@ class coinex extends coinex$1 {
1041
1387
  delete client.subscriptions[id];
1042
1388
  }
1043
1389
  }
1044
- async authenticate(params = {}) {
1045
- let type = undefined;
1046
- [type, params] = this.handleMarketTypeAndParams('authenticate', undefined, params);
1390
+ async authenticate(type) {
1047
1391
  const url = this.urls['api']['ws'][type];
1048
1392
  const client = this.client(url);
1049
1393
  const time = this.milliseconds();
1050
- const isSpot = (type === 'spot');
1051
- const spotMessageHash = 'authenticated:spot';
1052
- const swapMessageHash = 'authenticated:swap';
1053
- const messageHash = isSpot ? spotMessageHash : swapMessageHash;
1394
+ const timestamp = time.toString();
1395
+ const messageHash = 'authenticated';
1054
1396
  const future = client.future(messageHash);
1055
1397
  const authenticated = this.safeValue(client.subscriptions, messageHash);
1056
- if (type === 'spot') {
1057
- if (authenticated !== undefined) {
1058
- return await future;
1059
- }
1060
- const requestId = this.requestId();
1061
- const subscribe = {
1062
- 'id': requestId,
1063
- 'future': spotMessageHash,
1064
- };
1065
- const signData = 'access_id=' + this.apiKey + '&tonce=' + this.numberToString(time) + '&secret_key=' + this.secret;
1066
- const hash = this.hash(this.encode(signData), md5.md5);
1067
- const request = {
1068
- 'method': 'server.sign',
1069
- 'params': [
1070
- this.apiKey,
1071
- hash.toUpperCase(),
1072
- time,
1073
- ],
1074
- 'id': requestId,
1075
- };
1076
- this.watch(url, messageHash, request, requestId, subscribe);
1077
- client.subscriptions[messageHash] = true;
1078
- return await future;
1079
- }
1080
- else {
1081
- if (authenticated !== undefined) {
1082
- return await future;
1083
- }
1084
- const requestId = this.requestId();
1085
- const subscribe = {
1086
- 'id': requestId,
1087
- 'future': swapMessageHash,
1088
- };
1089
- const signData = 'access_id=' + this.apiKey + '&timestamp=' + this.numberToString(time) + '&secret_key=' + this.secret;
1090
- const hash = this.hash(this.encode(signData), sha256.sha256, 'hex');
1091
- const request = {
1092
- 'method': 'server.sign',
1093
- 'params': [
1094
- this.apiKey,
1095
- hash.toLowerCase(),
1096
- time,
1097
- ],
1098
- 'id': requestId,
1099
- };
1100
- this.watch(url, messageHash, request, requestId, subscribe);
1101
- client.subscriptions[messageHash] = true;
1398
+ if (authenticated !== undefined) {
1102
1399
  return await future;
1103
1400
  }
1401
+ const requestId = this.requestId();
1402
+ const subscribe = {
1403
+ 'id': requestId,
1404
+ 'future': messageHash,
1405
+ };
1406
+ const hmac = this.hmac(this.encode(timestamp), this.encode(this.secret), sha256.sha256, 'hex');
1407
+ const request = {
1408
+ 'id': requestId,
1409
+ 'method': 'server.sign',
1410
+ 'params': {
1411
+ 'access_id': this.apiKey,
1412
+ 'signed_str': hmac.toLowerCase(),
1413
+ 'timestamp': time,
1414
+ },
1415
+ };
1416
+ this.watch(url, messageHash, request, requestId, subscribe);
1417
+ client.subscriptions[messageHash] = true;
1418
+ return await future;
1104
1419
  }
1105
1420
  }
1106
1421