ccxt 4.5.44 → 4.5.45

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 (81) hide show
  1. package/README.md +9 -12
  2. package/dist/ccxt.browser.min.js +3 -3
  3. package/dist/cjs/ccxt.js +1 -12
  4. package/dist/cjs/src/abstract/kucoinfutures.js +1 -1
  5. package/dist/cjs/src/base/Exchange.js +36 -3
  6. package/dist/cjs/src/base/functions/encode.js +2 -2
  7. package/dist/cjs/src/base/functions/generic.js +8 -2
  8. package/dist/cjs/src/bitrue.js +1 -1
  9. package/dist/cjs/src/bitteam.js +1 -1
  10. package/dist/cjs/src/btcbox.js +1 -1
  11. package/dist/cjs/src/cex.js +1 -0
  12. package/dist/cjs/src/gate.js +227 -168
  13. package/dist/cjs/src/grvt.js +3 -2
  14. package/dist/cjs/src/hyperliquid.js +16 -5
  15. package/dist/cjs/src/kraken.js +2 -2
  16. package/dist/cjs/src/krakenfutures.js +1 -5
  17. package/dist/cjs/src/kucoin.js +4729 -970
  18. package/dist/cjs/src/kucoinfutures.js +14 -3434
  19. package/dist/cjs/src/lbank.js +1 -1
  20. package/dist/cjs/src/poloniex.js +1 -1
  21. package/dist/cjs/src/pro/gate.js +37 -1
  22. package/dist/cjs/src/pro/kucoin.js +819 -178
  23. package/dist/cjs/src/pro/kucoinfutures.js +95 -1261
  24. package/dist/cjs/src/pro/mexc.js +10 -5
  25. package/dist/cjs/src/pro/okx.js +84 -39
  26. package/js/ccxt.d.ts +2 -14
  27. package/js/ccxt.js +2 -10
  28. package/js/src/abstract/kucoin.d.ts +46 -3
  29. package/js/src/abstract/kucoinfutures.d.ts +27 -12
  30. package/js/src/base/Exchange.d.ts +12 -1
  31. package/js/src/base/Exchange.js +36 -3
  32. package/js/src/base/functions/encode.js +2 -2
  33. package/js/src/base/functions/generic.js +9 -3
  34. package/js/src/bitrue.js +1 -1
  35. package/js/src/bitteam.js +1 -1
  36. package/js/src/btcbox.js +1 -1
  37. package/js/src/cex.js +2 -1
  38. package/js/src/gate.d.ts +125 -119
  39. package/js/src/gate.js +227 -168
  40. package/js/src/grvt.js +3 -2
  41. package/js/src/hyperliquid.d.ts +3 -1
  42. package/js/src/hyperliquid.js +16 -5
  43. package/js/src/kraken.js +2 -2
  44. package/js/src/krakenfutures.js +1 -5
  45. package/js/src/kucoin.d.ts +696 -100
  46. package/js/src/kucoin.js +4730 -971
  47. package/js/src/kucoinfutures.d.ts +4 -522
  48. package/js/src/kucoinfutures.js +14 -3434
  49. package/js/src/lbank.js +1 -1
  50. package/js/src/poloniex.js +1 -1
  51. package/js/src/pro/gate.d.ts +30 -1
  52. package/js/src/pro/gate.js +37 -1
  53. package/js/src/pro/kucoin.d.ts +70 -30
  54. package/js/src/pro/kucoin.js +821 -180
  55. package/js/src/pro/kucoinfutures.d.ts +17 -195
  56. package/js/src/pro/kucoinfutures.js +96 -1262
  57. package/js/src/pro/mexc.js +10 -5
  58. package/js/src/pro/okx.d.ts +1 -0
  59. package/js/src/pro/okx.js +84 -39
  60. package/package.json +1 -1
  61. package/dist/cjs/src/abstract/alp.js +0 -11
  62. package/dist/cjs/src/abstract/defx.js +0 -11
  63. package/dist/cjs/src/abstract/timex.js +0 -11
  64. package/dist/cjs/src/alp.js +0 -1059
  65. package/dist/cjs/src/defx.js +0 -2142
  66. package/dist/cjs/src/pro/defx.js +0 -866
  67. package/dist/cjs/src/timex.js +0 -1793
  68. package/js/src/abstract/alp.d.ts +0 -21
  69. package/js/src/abstract/alp.js +0 -5
  70. package/js/src/abstract/defx.d.ts +0 -72
  71. package/js/src/abstract/defx.js +0 -5
  72. package/js/src/abstract/timex.d.ts +0 -65
  73. package/js/src/abstract/timex.js +0 -5
  74. package/js/src/alp.d.ts +0 -209
  75. package/js/src/alp.js +0 -1052
  76. package/js/src/defx.d.ts +0 -348
  77. package/js/src/defx.js +0 -2135
  78. package/js/src/pro/defx.d.ts +0 -236
  79. package/js/src/pro/defx.js +0 -859
  80. package/js/src/timex.d.ts +0 -247
  81. package/js/src/timex.js +0 -1786
@@ -1,1293 +1,127 @@
1
1
  // ---------------------------------------------------------------------------
2
- import kucoinfuturesRest from '../kucoinfutures.js';
3
- import { ExchangeError, ArgumentsRequired } from '../base/errors.js';
4
- import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
5
- // ---------------------------------------------------------------------------
6
- export default class kucoinfutures extends kucoinfuturesRest {
2
+ import kucoin from './kucoin.js';
3
+ import { BadRequest } from '../base/errors.js';
4
+ // ---------------------------------------------------------------------------
5
+ export default class kucoinfutures extends kucoin {
7
6
  describe() {
8
7
  return this.deepExtend(super.describe(), {
8
+ 'id': 'kucoinfutures',
9
+ 'name': 'KuCoin Futures',
10
+ 'urls': {
11
+ 'logo': 'https://user-images.githubusercontent.com/1294454/147508995-9e35030a-d046-43a1-a006-6fabd981b554.jpg',
12
+ 'www': 'https://futures.kucoin.com/',
13
+ 'referral': 'https://futures.kucoin.com/?rcode=E5wkqe',
14
+ },
9
15
  'has': {
10
- 'ws': true,
11
- 'watchLiquidations': false,
12
- 'watchLiquidatinsForSymbols': false,
13
- 'watchMyLiquidations': undefined,
14
- 'watchMyLiquidationsForSymbols': undefined,
15
- 'watchTicker': true,
16
- 'watchTickers': true,
17
- 'watchBidsAsks': true,
18
- 'watchTrades': true,
19
- 'watchOHLCV': true,
20
- 'watchOrderBook': true,
21
- 'watchOrders': true,
22
- 'watchBalance': true,
23
- 'watchPosition': true,
24
- 'watchPositions': false,
25
- 'watchPositionForSymbols': false,
26
- 'watchTradesForSymbols': true,
27
- 'watchOrderBookForSymbols': true,
16
+ 'CORS': undefined,
17
+ 'spot': false,
18
+ 'margin': false,
19
+ 'swap': true,
20
+ 'future': true,
21
+ 'option': undefined,
22
+ 'fetchBidsAsks': true,
28
23
  },
29
24
  'options': {
30
- 'timeframes': {
31
- '1m': '1min',
32
- '3m': '1min',
33
- '5m': '5min',
34
- '15m': '15min',
35
- '30m': '30min',
36
- '1h': '1hour',
37
- '2h': '2hour',
38
- '4h': '4hour',
39
- '8h': '8hour',
40
- '12h': '12hour',
41
- '1d': '1day',
42
- '1w': '1week',
43
- '1M': '1month',
44
- },
45
- 'accountsByType': {
46
- 'swap': 'future',
47
- 'cross': 'margin',
48
- // 'spot': ,
49
- // 'margin': ,
50
- // 'main': ,
51
- // 'funding': ,
52
- // 'future': ,
53
- // 'mining': ,
54
- // 'trade': ,
55
- // 'contract': ,
56
- // 'pool': ,
25
+ 'fetchMarkets': {
26
+ 'types': ['swap', 'future', 'contract'],
27
+ 'fetchTickersFees': false,
57
28
  },
58
- 'tradesLimit': 1000,
59
- 'watchOrderBook': {
60
- 'snapshotDelay': 20,
61
- 'snapshotMaxRetries': 3,
62
- },
63
- 'watchPosition': {
64
- 'fetchPositionSnapshot': true,
65
- 'awaitPositionSnapshot': true, // whether to wait for the position snapshot before providing updates
66
- },
67
- },
68
- 'streaming': {
69
- // kucoin does not support built-in ws protocol-level ping-pong
70
- // instead it requires a custom json-based text ping-pong
71
- // https://docs.kucoin.com/#ping
72
- 'ping': this.ping,
29
+ 'defaultType': 'swap',
30
+ 'defaultAccountType': 'contract',
31
+ 'uta': false,
73
32
  },
74
33
  });
75
34
  }
76
- async negotiate(privateChannel, params = {}) {
77
- const connectId = privateChannel ? 'private' : 'public';
78
- const urls = this.safeValue(this.options, 'urls', {});
79
- let future = this.safeValue(urls, connectId);
80
- if (future !== undefined) {
81
- return await future;
82
- }
83
- // we store an awaitable to the url
84
- // so that multiple calls don't asynchronously
85
- // fetch different urls and overwrite each other
86
- urls[connectId] = this.spawn(this.negotiateHelper, privateChannel, params); // we have to wait here otherwsie in c# will not work
87
- this.options['urls'] = urls;
88
- future = urls[connectId];
89
- return await future;
90
- }
91
- async negotiateHelper(privateChannel, params = {}) {
92
- let response = undefined;
93
- const connectId = privateChannel ? 'private' : 'public';
94
- try {
95
- if (privateChannel) {
96
- response = await this.futuresPrivatePostBulletPrivate(params);
97
- //
98
- // {
99
- // "code": "200000",
100
- // "data": {
101
- // "instanceServers": [
102
- // {
103
- // "pingInterval": 50000,
104
- // "endpoint": "wss://push-private.kucoin.com/endpoint",
105
- // "protocol": "websocket",
106
- // "encrypt": true,
107
- // "pingTimeout": 10000
108
- // }
109
- // ],
110
- // "token": "2neAiuYvAU61ZDXANAGAsiL4-iAExhsBXZxftpOeh_55i3Ysy2q2LEsEWU64mdzUOPusi34M_wGoSf7iNyEWJ1UQy47YbpY4zVdzilNP-Bj3iXzrjjGlWtiYB9J6i9GjsxUuhPw3BlrzazF6ghq4Lzf7scStOz3KkxjwpsOBCH4=.WNQmhZQeUKIkh97KYgU0Lg=="
111
- // }
112
- // }
113
- //
114
- }
115
- else {
116
- response = await this.futuresPublicPostBulletPublic(params);
117
- }
118
- const data = this.safeValue(response, 'data', {});
119
- const instanceServers = this.safeValue(data, 'instanceServers', []);
120
- const firstInstanceServer = this.safeValue(instanceServers, 0);
121
- const pingInterval = this.safeInteger(firstInstanceServer, 'pingInterval');
122
- const endpoint = this.safeString(firstInstanceServer, 'endpoint');
123
- const token = this.safeString(data, 'token');
124
- const result = endpoint + '?' + this.urlencode({
125
- 'token': token,
126
- 'privateChannel': privateChannel,
127
- 'connectId': connectId,
128
- });
129
- const client = this.client(result);
130
- client.keepAlive = pingInterval;
131
- return result;
132
- }
133
- catch (e) {
134
- const future = this.safeValue(this.options['urls'], connectId);
135
- future.reject(e);
136
- delete this.options['urls'][connectId];
137
- }
138
- return undefined;
139
- }
140
- requestId() {
141
- this.lockId();
142
- const requestId = this.sum(this.safeInteger(this.options, 'requestId', 0), 1);
143
- this.options['requestId'] = requestId;
144
- this.unlockId();
145
- return requestId;
146
- }
147
- async subscribe(url, messageHash, subscriptionHash, subscription, params = {}) {
148
- const requestId = this.requestId().toString();
149
- const request = {
150
- 'id': requestId,
151
- 'type': 'subscribe',
152
- 'topic': subscriptionHash,
153
- 'response': true,
154
- };
155
- const message = this.extend(request, params);
156
- const subscriptionRequest = {
157
- 'id': requestId,
158
- };
159
- if (subscription === undefined) {
160
- subscription = subscriptionRequest;
161
- }
162
- else {
163
- subscription = this.extend(subscriptionRequest, subscription);
164
- }
165
- return await this.watch(url, messageHash, message, subscriptionHash, subscription);
166
- }
167
- async subscribeMultiple(url, messageHashes, topic, subscriptionHashes, subscriptionArgs, params = {}) {
168
- const requestId = this.requestId().toString();
169
- const request = {
170
- 'id': requestId,
171
- 'type': 'subscribe',
172
- 'topic': topic,
173
- 'response': true,
174
- };
175
- return await this.watchMultiple(url, messageHashes, this.extend(request, params), subscriptionHashes, subscriptionArgs);
176
- }
177
- async unSubscribeMultiple(url, messageHashes, topic, subscriptionHashes, params = {}, subscription = undefined) {
178
- const requestId = this.requestId().toString();
179
- const request = {
180
- 'id': requestId,
181
- 'type': 'unsubscribe',
182
- 'topic': topic,
183
- 'response': true,
184
- };
185
- const message = this.extend(request, params);
186
- if (subscription !== undefined) {
187
- subscription[requestId] = requestId;
188
- }
189
- const client = this.client(url);
190
- for (let i = 0; i < subscriptionHashes.length; i++) {
191
- const subscriptionHash = subscriptionHashes[i];
192
- if (!(subscriptionHash in client.subscriptions)) {
193
- client.subscriptions[requestId] = subscriptionHash;
194
- }
195
- }
196
- return await this.watchMultiple(url, messageHashes, message, subscriptionHashes, subscription);
197
- }
198
- /**
199
- * @method
200
- * @name kucoinfutures#watchTicker
201
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
202
- * @see https://www.kucoin.com/docs/websocket/futures-trading/public-channels/get-ticker
203
- * @param {string} symbol unified symbol of the market to fetch the ticker for
204
- * @param {object} [params] extra parameters specific to the exchange API endpoint
205
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
206
- */
207
- async watchTicker(symbol, params = {}) {
208
- await this.loadMarkets();
209
- const market = this.market(symbol);
210
- symbol = market['symbol'];
211
- params['callerMethodName'] = 'watchTicker';
212
- const tickers = await this.watchTickers([symbol], params);
213
- return tickers[symbol];
214
- }
215
35
  /**
216
36
  * @method
217
- * @name kucoinfutures#watchTickers
218
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
219
- * @param {string[]} symbols unified symbol of the market to fetch the ticker for
37
+ * @name kucoinfutures#fetchBidsAsks
38
+ * @description fetches the bid and ask price and volume for multiple markets
39
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
220
40
  * @param {object} [params] extra parameters specific to the exchange API endpoint
221
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
41
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/?id=ticker-structure}
222
42
  */
223
- async watchTickers(symbols = undefined, params = {}) {
224
- await this.loadMarkets();
225
- const ticker = await this.watchMultiRequest('watchTickers', '/contractMarket/ticker:', symbols, params);
226
- if (this.newUpdates) {
227
- const tickers = {};
228
- tickers[ticker['symbol']] = ticker;
229
- return tickers;
230
- }
231
- return this.filterByArray(this.tickers, 'symbol', symbols);
232
- }
233
- handleTicker(client, message) {
234
- //
235
- // ticker (v1)
236
- //
237
- // {
238
- // "subject": "ticker",
239
- // "topic": "/contractMarket/ticker:XBTUSDM",
240
- // "data": {
241
- // "symbol": "XBTUSDM", //Market of the symbol
242
- // "sequence": 45, //Sequence number which is used to judge the continuity of the pushed messages
243
- // "side": "sell", //Transaction side of the last traded taker order
244
- // "price": "3600.0", //Filled price
245
- // "size": 16, //Filled quantity
246
- // "tradeId": "5c9dcf4170744d6f5a3d32fb", //Order ID
247
- // "bestBidSize": 795, //Best bid size
248
- // "bestBidPrice": "3200.0", //Best bid
249
- // "bestAskPrice": "3600.0", //Best ask size
250
- // "bestAskSize": 284, //Best ask
251
- // "ts": 1553846081210004941 //Filled time - nanosecond
252
- // }
253
- // }
254
- //
255
- const data = this.safeValue(message, 'data', {});
256
- const marketId = this.safeValue(data, 'symbol');
257
- const market = this.safeMarket(marketId, undefined, '-');
258
- const ticker = this.parseTicker(data, market);
259
- this.tickers[market['symbol']] = ticker;
260
- client.resolve(ticker, this.getMessageHash('ticker', market['symbol']));
261
- }
262
- /**
263
- * @method
264
- * @name kucoinfutures#watchBidsAsks
265
- * @see https://www.kucoin.com/docs/websocket/futures-trading/public-channels/get-ticker-v2
266
- * @description watches best bid & ask for symbols
267
- * @param {string[]} symbols unified symbol of the market to fetch the ticker for
268
- * @param {object} [params] extra parameters specific to the exchange API endpoint
269
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/?id=ticker-structure}
270
- */
271
- async watchBidsAsks(symbols = undefined, params = {}) {
272
- const ticker = await this.watchMultiRequest('watchBidsAsks', '/contractMarket/tickerV2:', symbols, params);
273
- if (this.newUpdates) {
274
- const tickers = {};
275
- tickers[ticker['symbol']] = ticker;
276
- return tickers;
277
- }
278
- return this.filterByArray(this.bidsasks, 'symbol', symbols);
279
- }
280
- async watchMultiRequest(methodName, channelName, symbols = undefined, params = {}) {
281
- await this.loadMarkets();
282
- [methodName, params] = this.handleParamString(params, 'callerMethodName', methodName);
283
- const isBidsAsks = (methodName === 'watchBidsAsks');
284
- symbols = this.marketSymbols(symbols, undefined, false, true, false);
285
- const length = symbols.length;
286
- if (length > 100) {
287
- throw new ArgumentsRequired(this.id + ' ' + methodName + '() accepts a maximum of 100 symbols');
288
- }
289
- const messageHashes = [];
290
- for (let i = 0; i < symbols.length; i++) {
291
- const symbol = symbols[i];
292
- const market = this.market(symbol);
293
- const prefix = isBidsAsks ? 'bidask' : 'ticker';
294
- messageHashes.push(this.getMessageHash(prefix, market['symbol']));
295
- }
296
- const url = await this.negotiate(false);
297
- const marketIds = this.marketIds(symbols);
298
- const joined = marketIds.join(',');
299
- const requestId = this.requestId().toString();
43
+ async fetchBidsAsks(symbols = undefined, params = {}) {
300
44
  const request = {
301
- 'id': requestId,
302
- 'type': 'subscribe',
303
- 'topic': channelName + joined,
304
- 'response': true,
45
+ 'method': 'futuresPublicGetAllTickers',
305
46
  };
306
- const subscription = {
307
- 'id': requestId,
308
- };
309
- return await this.watchMultiple(url, messageHashes, this.extend(request, params), messageHashes, subscription);
310
- }
311
- handleBidAsk(client, message) {
312
- //
313
- // arrives one symbol dict
314
- //
315
- // {
316
- // "subject": "tickerV2",
317
- // "topic": "/contractMarket/tickerV2:XBTUSDM",
318
- // "data": {
319
- // "symbol": "XBTUSDM", //Market of the symbol
320
- // "bestBidSize": 795, // Best bid size
321
- // "bestBidPrice": 3200.0, // Best bid
322
- // "bestAskPrice": 3600.0, // Best ask
323
- // "bestAskSize": 284, // Best ask size
324
- // "ts": 1553846081210004941 // Filled time - nanosecond
325
- // }
326
- // }
327
- //
328
- const parsedTicker = this.parseWsBidAsk(message);
329
- const symbol = parsedTicker['symbol'];
330
- this.bidsasks[symbol] = parsedTicker;
331
- client.resolve(parsedTicker, this.getMessageHash('bidask', symbol));
332
- }
333
- parseWsBidAsk(ticker, market = undefined) {
334
- const data = this.safeDict(ticker, 'data', {});
335
- const marketId = this.safeString(data, 'symbol');
336
- market = this.safeMarket(marketId, market);
337
- const symbol = this.safeString(market, 'symbol');
338
- const timestamp = this.safeIntegerProduct(data, 'ts', 0.000001);
339
- return this.safeTicker({
340
- 'symbol': symbol,
341
- 'timestamp': timestamp,
342
- 'datetime': this.iso8601(timestamp),
343
- 'ask': this.safeNumber(data, 'bestAskPrice'),
344
- 'askVolume': this.safeNumber(data, 'bestAskSize'),
345
- 'bid': this.safeNumber(data, 'bestBidPrice'),
346
- 'bidVolume': this.safeNumber(data, 'bestBidSize'),
347
- 'info': ticker,
348
- }, market);
349
- }
350
- /**
351
- * @method
352
- * @name kucoinfutures#watchPosition
353
- * @description watch open positions for a specific symbol
354
- * @see https://docs.kucoin.com/futures/#position-change-events
355
- * @param {string|undefined} symbol unified market symbol
356
- * @param {object} params extra parameters specific to the exchange API endpoint
357
- * @returns {object} a [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
358
- */
359
- async watchPosition(symbol = undefined, params = {}) {
360
- if (symbol === undefined) {
361
- throw new ArgumentsRequired(this.id + ' watchPosition() requires a symbol argument');
362
- }
363
- await this.loadMarkets();
364
- const url = await this.negotiate(true);
365
- const market = this.market(symbol);
366
- const topic = '/contract/position:' + market['id'];
367
- const request = {
368
- 'privateChannel': true,
369
- };
370
- const messageHash = 'position:' + market['symbol'];
371
- const client = this.client(url);
372
- this.setPositionCache(client, symbol);
373
- const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', true);
374
- const awaitPositionSnapshot = this.handleOption('watchPosition', 'awaitPositionSnapshot', true);
375
- const currentPosition = this.getCurrentPosition(symbol);
376
- if (fetchPositionSnapshot && awaitPositionSnapshot && currentPosition === undefined) {
377
- const snapshot = await client.future('fetchPositionSnapshot:' + symbol);
378
- return snapshot;
379
- }
380
- return await this.subscribe(url, messageHash, topic, undefined, this.extend(request, params));
381
- }
382
- getCurrentPosition(symbol) {
383
- if (this.positions === undefined) {
384
- return undefined;
385
- }
386
- const cache = this.positions.hashmap;
387
- const symbolCache = this.safeValue(cache, symbol, {});
388
- const values = Object.values(symbolCache);
389
- return this.safeValue(values, 0);
390
- }
391
- setPositionCache(client, symbol) {
392
- const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', false);
393
- if (fetchPositionSnapshot) {
394
- const messageHash = 'fetchPositionSnapshot:' + symbol;
395
- if (!(messageHash in client.futures)) {
396
- client.future(messageHash);
397
- this.spawn(this.loadPositionSnapshot, client, messageHash, symbol);
398
- }
399
- }
400
- }
401
- async loadPositionSnapshot(client, messageHash, symbol) {
402
- const position = await this.fetchPosition(symbol);
403
- this.positions = new ArrayCacheBySymbolById();
404
- const cache = this.positions;
405
- cache.append(position);
406
- // don't remove the future from the .futures cache
407
- if (messageHash in client.futures) {
408
- const future = client.futures[messageHash];
409
- future.resolve(cache);
410
- client.resolve(position, 'position:' + symbol);
411
- }
412
- }
413
- handlePosition(client, message) {
414
- //
415
- // Position Changes Caused Operations
416
- // {
417
- // "type": "message",
418
- // "userId": "5c32d69203aa676ce4b543c7", // Deprecated, will detele later
419
- // "channelType": "private",
420
- // "topic": "/contract/position:XBTUSDM",
421
- // "subject": "position.change",
422
- // "data": {
423
- // "realisedGrossPnl": 0E-8, //Accumulated realised profit and loss
424
- // "symbol": "XBTUSDM", //Symbol
425
- // "crossMode": false, //Cross mode or not
426
- // "liquidationPrice": 1000000.0, //Liquidation price
427
- // "posLoss": 0E-8, //Manually added margin amount
428
- // "avgEntryPrice": 7508.22, //Average entry price
429
- // "unrealisedPnl": -0.00014735, //Unrealised profit and loss
430
- // "markPrice": 7947.83, //Mark price
431
- // "posMargin": 0.00266779, //Position margin
432
- // "autoDeposit": false, //Auto deposit margin or not
433
- // "riskLimit": 100000, //Risk limit
434
- // "unrealisedCost": 0.00266375, //Unrealised value
435
- // "posComm": 0.00000392, //Bankruptcy cost
436
- // "posMaint": 0.00001724, //Maintenance margin
437
- // "posCost": 0.00266375, //Position value
438
- // "maintMarginReq": 0.005, //Maintenance margin rate
439
- // "bankruptPrice": 1000000.0, //Bankruptcy price
440
- // "realisedCost": 0.00000271, //Currently accumulated realised position value
441
- // "markValue": 0.00251640, //Mark value
442
- // "posInit": 0.00266375, //Position margin
443
- // "realisedPnl": -0.00000253, //Realised profit and losts
444
- // "maintMargin": 0.00252044, //Position margin
445
- // "realLeverage": 1.06, //Leverage of the order
446
- // "changeReason": "positionChange", //changeReason:marginChange、positionChange、liquidation、autoAppendMarginStatusChange、adl
447
- // "currentCost": 0.00266375, //Current position value
448
- // "openingTimestamp": 1558433191000, //Open time
449
- // "currentQty": -20, //Current position
450
- // "delevPercentage": 0.52, //ADL ranking percentile
451
- // "currentComm": 0.00000271, //Current commission
452
- // "realisedGrossCost": 0E-8, //Accumulated reliased gross profit value
453
- // "isOpen": true, //Opened position or not
454
- // "posCross": 1.2E-7, //Manually added margin
455
- // "currentTimestamp": 1558506060394, //Current timestamp
456
- // "unrealisedRoePcnt": -0.0553, //Rate of return on investment
457
- // "unrealisedPnlPcnt": -0.0553, //Position profit and loss ratio
458
- // "settleCurrency": "XBT" //Currency used to clear and settle the trades
459
- // }
460
- // }
461
- // Position Changes Caused by Mark Price
462
- // {
463
- // "userId": "5cd3f1a7b7ebc19ae9558591", // Deprecated, will detele later
464
- // "topic": "/contract/position:XBTUSDM",
465
- // "subject": "position.change",
466
- // "data": {
467
- // "markPrice": 7947.83, //Mark price
468
- // "markValue": 0.00251640, //Mark value
469
- // "maintMargin": 0.00252044, //Position margin
470
- // "realLeverage": 10.06, //Leverage of the order
471
- // "unrealisedPnl": -0.00014735, //Unrealised profit and lost
472
- // "unrealisedRoePcnt": -0.0553, //Rate of return on investment
473
- // "unrealisedPnlPcnt": -0.0553, //Position profit and loss ratio
474
- // "delevPercentage": 0.52, //ADL ranking percentile
475
- // "currentTimestamp": 1558087175068, //Current timestamp
476
- // "settleCurrency": "XBT" //Currency used to clear and settle the trades
477
- // }
478
- // }
479
- // Funding Settlement
480
- // {
481
- // "userId": "xbc453tg732eba53a88ggyt8c", // Deprecated, will detele later
482
- // "topic": "/contract/position:XBTUSDM",
483
- // "subject": "position.settlement",
484
- // "data": {
485
- // "fundingTime": 1551770400000, //Funding time
486
- // "qty": 100, //Position siz
487
- // "markPrice": 3610.85, //Settlement price
488
- // "fundingRate": -0.002966, //Funding rate
489
- // "fundingFee": -296, //Funding fees
490
- // "ts": 1547697294838004923, //Current time (nanosecond)
491
- // "settleCurrency": "XBT" //Currency used to clear and settle the trades
492
- // }
493
- // }
494
- // Adjustmet result of risk limit level
495
- // {
496
- // "userId": "xbc453tg732eba53a88ggyt8c",
497
- // "topic": "/contract/position:ADAUSDTM",
498
- // "subject": "position.adjustRiskLimit",
499
- // "data": {
500
- // "success": true, // Successful or not
501
- // "riskLimitLevel": 1, // Current risk limit level
502
- // "msg": "" // Failure reason
503
- // }
504
- // }
505
- //
506
- const topic = this.safeString(message, 'topic', '');
507
- const parts = topic.split(':');
508
- const marketId = this.safeString(parts, 1);
509
- const symbol = this.safeSymbol(marketId, undefined, '');
510
- const cache = this.positions;
511
- const currentPosition = this.getCurrentPosition(symbol);
512
- const messageHash = 'position:' + symbol;
513
- const data = this.safeValue(message, 'data', {});
514
- const newPosition = this.parsePosition(data);
515
- const keys = Object.keys(newPosition);
516
- for (let i = 0; i < keys.length; i++) {
517
- const key = keys[i];
518
- if (newPosition[key] === undefined) {
519
- delete newPosition[key];
520
- }
521
- }
522
- const position = this.extend(currentPosition, newPosition);
523
- cache.append(position);
524
- client.resolve(position, messageHash);
525
- }
526
- /**
527
- * @method
528
- * @name kucoinfutures#watchTrades
529
- * @description get the list of most recent trades for a particular symbol
530
- * @see https://docs.kucoin.com/futures/#execution-data
531
- * @param {string} symbol unified symbol of the market to fetch trades for
532
- * @param {int} [since] timestamp in ms of the earliest trade to fetch
533
- * @param {int} [limit] the maximum amount of trades to fetch
534
- * @param {object} [params] extra parameters specific to the exchange API endpoint
535
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
536
- */
537
- async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
538
- return await this.watchTradesForSymbols([symbol], since, limit, params);
47
+ return await this.fetchTickers(symbols, this.extend(request, params));
539
48
  }
540
49
  /**
541
50
  * @method
542
- * @name kucoinfutures#watchTradesForSymbols
543
- * @description get the list of most recent trades for a particular symbol
544
- * @param {string[]} symbols
545
- * @param {int} [since] timestamp in ms of the earliest trade to fetch
546
- * @param {int} [limit] the maximum amount of trades to fetch
51
+ * @name kucoinfutures#transfer
52
+ * @description transfer currency internally between wallets on the same account
53
+ * @param {string} code unified currency code
54
+ * @param {float} amount amount to transfer
55
+ * @param {string} fromAccount account to transfer from
56
+ * @param {string} toAccount account to transfer to
547
57
  * @param {object} [params] extra parameters specific to the exchange API endpoint
548
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
58
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/?id=transfer-structure}
549
59
  */
550
- async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
551
- const symbolsLength = symbols.length;
552
- if (symbolsLength === 0) {
553
- throw new ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
554
- }
60
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
555
61
  await this.loadMarkets();
556
- symbols = this.marketSymbols(symbols);
557
- const url = await this.negotiate(false);
558
- symbols = this.marketSymbols(symbols);
559
- const marketIds = this.marketIds(symbols);
560
- const topic = '/contractMarket/execution:' + marketIds.join(',');
561
- const subscriptionHashes = [];
562
- const messageHashes = [];
563
- for (let i = 0; i < symbols.length; i++) {
564
- const symbol = symbols[i];
565
- const marketId = marketIds[i];
566
- messageHashes.push('trades:' + symbol);
567
- subscriptionHashes.push('/contractMarket/execution:' + marketId);
568
- }
569
- const trades = await this.subscribeMultiple(url, messageHashes, topic, subscriptionHashes, undefined, params);
570
- if (this.newUpdates) {
571
- const first = this.safeValue(trades, 0);
572
- const tradeSymbol = this.safeString(first, 'symbol');
573
- limit = trades.getLimit(tradeSymbol, limit);
574
- }
575
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
576
- }
577
- /**
578
- * @method
579
- * @name kucoinfutures#unWatchTrades
580
- * @description unWatches trades stream
581
- * @see https://docs.kucoin.com/futures/#execution-data
582
- * @param {string} symbol unified symbol of the market to fetch trades for
583
- * @param {object} [params] extra parameters specific to the exchange API endpoint
584
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
585
- */
586
- async unWatchTrades(symbol, params = {}) {
587
- return await this.unWatchTradesForSymbols([symbol], params);
588
- }
589
- /**
590
- * @method
591
- * @name kucoinfutures#unWatchTradesForSymbols
592
- * @description get the list of most recent trades for a particular symbol
593
- * @param {string[]} symbols
594
- * @param {object} [params] extra parameters specific to the exchange API endpoint
595
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/?id=public-trades}
596
- */
597
- async unWatchTradesForSymbols(symbols, params = {}) {
598
- await this.loadMarkets();
599
- symbols = this.marketSymbols(symbols, undefined, false);
600
- const url = await this.negotiate(false);
601
- symbols = this.marketSymbols(symbols);
602
- const marketIds = this.marketIds(symbols);
603
- const topic = '/contractMarket/execution:' + marketIds.join(',');
604
- const subscriptionHashes = [];
605
- const messageHashes = [];
606
- for (let i = 0; i < symbols.length; i++) {
607
- const symbol = symbols[i];
608
- messageHashes.push('unsubscribe:trades:' + symbol);
609
- subscriptionHashes.push('trades:' + symbol);
610
- }
611
- const subscription = {
612
- 'messageHashes': messageHashes,
613
- 'subMessageHashes': subscriptionHashes,
614
- 'topic': 'trades',
615
- 'unsubscribe': true,
616
- 'symbols': symbols,
617
- };
618
- return await this.unSubscribeMultiple(url, messageHashes, topic, messageHashes, params, subscription);
619
- }
620
- handleTrade(client, message) {
621
- //
622
- // {
623
- // "type": "message",
624
- // "topic": "/contractMarket/execution:ADAUSDTM",
625
- // "subject": "match",
626
- // "data": {
627
- // "makerUserId": "62286a4d720edf0001e81961",
628
- // "symbol": "ADAUSDTM",
629
- // "sequence": 41320766,
630
- // "side": "sell",
631
- // "size": 2,
632
- // "price": 0.35904,
633
- // "takerOrderId": "636dd9da9857ba00010cfa44",
634
- // "makerOrderId": "636dd9c8df149d0001e62bc8",
635
- // "takerUserId": "6180be22b6ab210001fa3371",
636
- // "tradeId": "636dd9da0000d400d477eca7",
637
- // "ts": 1668143578987357700
638
- // }
639
- // }
640
- //
641
- const data = this.safeValue(message, 'data', {});
642
- const trade = this.parseTrade(data);
643
- const symbol = trade['symbol'];
644
- let trades = this.safeValue(this.trades, symbol);
645
- if (trades === undefined) {
646
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
647
- trades = new ArrayCache(limit);
648
- this.trades[symbol] = trades;
649
- }
650
- trades.append(trade);
651
- const messageHash = 'trades:' + symbol;
652
- client.resolve(trades, messageHash);
653
- return message;
654
- }
655
- /**
656
- * @method
657
- * @name kucoinfutures#watchOHLCV
658
- * @see https://www.kucoin.com/docs/websocket/futures-trading/public-channels/klines
659
- * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
660
- * @param {string} symbol unified symbol of the market to fetch OHLCV data for
661
- * @param {string} timeframe the length of time each candle represents
662
- * @param {int} [since] timestamp in ms of the earliest candle to fetch
663
- * @param {int} [limit] the maximum amount of candles to fetch
664
- * @param {object} [params] extra parameters specific to the exchange API endpoint
665
- * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
666
- */
667
- async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
668
- await this.loadMarkets();
669
- symbol = this.symbol(symbol);
670
- const url = await this.negotiate(false);
671
- const marketId = this.marketId(symbol);
672
- const timeframes = this.safeDict(this.options, 'timeframes');
673
- const timeframeId = this.safeString(timeframes, timeframe, timeframe);
674
- const topic = '/contractMarket/limitCandle:' + marketId + '_' + timeframeId;
675
- const messageHash = 'ohlcv::' + symbol + '_' + timeframe;
676
- const ohlcv = await this.subscribe(url, messageHash, topic, undefined, params);
677
- if (this.newUpdates) {
678
- limit = ohlcv.getLimit(symbol, limit);
679
- }
680
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
681
- }
682
- handleOHLCV(client, message) {
683
- //
684
- // {
685
- // "topic":"/contractMarket/limitCandle:LTCUSDTM_1min",
686
- // "type":"message",
687
- // "data":{
688
- // "symbol":"LTCUSDTM",
689
- // "candles":[
690
- // "1715470980",
691
- // "81.38",
692
- // "81.38",
693
- // "81.38",
694
- // "81.38",
695
- // "61.0",
696
- // "61"
697
- // ],
698
- // "time":1715470994801
699
- // },
700
- // "subject":"candle.stick"
701
- // }
702
- //
703
- const topic = this.safeString(message, 'topic');
704
- const parts = topic.split('_');
705
- const timeframeId = this.safeString(parts, 1);
706
- const data = this.safeDict(message, 'data');
707
- const timeframes = this.safeDict(this.options, 'timeframes');
708
- const timeframe = this.findTimeframe(timeframeId, timeframes);
709
- const marketId = this.safeString(data, 'symbol');
710
- const symbol = this.safeSymbol(marketId);
711
- const messageHash = 'ohlcv::' + symbol + '_' + timeframe;
712
- const ohlcv = this.safeList(data, 'candles');
713
- const parsed = [
714
- this.safeInteger(ohlcv, 0),
715
- this.safeNumber(ohlcv, 1),
716
- this.safeNumber(ohlcv, 3),
717
- this.safeNumber(ohlcv, 4),
718
- this.safeNumber(ohlcv, 2),
719
- this.safeNumber(ohlcv, 6), // Note value 5 is incorrect and will be fixed in subsequent versions of kucoin
720
- ];
721
- this.ohlcvs[symbol] = this.safeDict(this.ohlcvs, symbol, {});
722
- if (!(timeframe in this.ohlcvs[symbol])) {
723
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
724
- this.ohlcvs[symbol][timeframe] = new ArrayCacheByTimestamp(limit);
725
- }
726
- const stored = this.ohlcvs[symbol][timeframe];
727
- stored.append(parsed);
728
- client.resolve(stored, messageHash);
729
- }
730
- /**
731
- * @method
732
- * @name kucoinfutures#watchOrderBook
733
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
734
- * 1. After receiving the websocket Level 2 data flow, cache the data.
735
- * 2. Initiate a REST request to get the snapshot data of Level 2 order book.
736
- * 3. Playback the cached Level 2 data flow.
737
- * 4. Apply the new Level 2 data flow to the local snapshot to ensure that the sequence of the new Level 2 update lines up with the sequence of the previous Level 2 data. Discard all the message prior to that sequence, and then playback the change to snapshot.
738
- * 5. Update the level2 full data based on sequence according to the size. If the price is 0, ignore the messages and update the sequence. If the size=0, update the sequence and remove the price of which the size is 0 out of level 2. For other cases, please update the price.
739
- * 6. If the sequence of the newly pushed message does not line up to the sequence of the last message, you could pull through REST Level 2 message request to get the updated messages. Please note that the difference between the start and end parameters cannot exceed 500.
740
- * @see https://docs.kucoin.com/futures/#level-2-market-data
741
- * @param {string} symbol unified symbol of the market to fetch the order book for
742
- * @param {int} [limit] the maximum amount of order book entries to return
743
- * @param {object} [params] extra parameters specific to the exchange API endpoint
744
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
745
- */
746
- async watchOrderBook(symbol, limit = undefined, params = {}) {
747
- return await this.watchOrderBookForSymbols([symbol], limit, params);
748
- }
749
- /**
750
- * @method
751
- * @name kucoinfutures#watchOrderBookForSymbols
752
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
753
- * @see https://docs.kucoin.com/futures/#level-2-market-data
754
- * @param {string[]} symbols unified array of symbols
755
- * @param {int} [limit] the maximum amount of order book entries to return
756
- * @param {object} [params] extra parameters specific to the exchange API endpoint
757
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
758
- */
759
- async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
760
- const symbolsLength = symbols.length;
761
- if (symbolsLength === 0) {
762
- throw new ArgumentsRequired(this.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols');
763
- }
764
- if (limit !== undefined) {
765
- if ((limit !== 20) && (limit !== 100)) {
766
- throw new ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
767
- }
768
- }
769
- await this.loadMarkets();
770
- symbols = this.marketSymbols(symbols);
771
- const marketIds = this.marketIds(symbols);
772
- const url = await this.negotiate(false);
773
- const topic = '/contractMarket/level2:' + marketIds.join(',');
774
- const subscriptionArgs = {
775
- 'limit': limit,
776
- };
777
- const subscriptionHashes = [];
778
- const messageHashes = [];
779
- for (let i = 0; i < symbols.length; i++) {
780
- const symbol = symbols[i];
781
- const marketId = marketIds[i];
782
- messageHashes.push('orderbook:' + symbol);
783
- subscriptionHashes.push('/contractMarket/level2:' + marketId);
784
- }
785
- const orderbook = await this.subscribeMultiple(url, messageHashes, topic, subscriptionHashes, subscriptionArgs, params);
786
- return orderbook.limit();
787
- }
788
- /**
789
- * @method
790
- * @name kucoinfutures#unWatchOrderBook
791
- * @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
792
- * @see https://docs.kucoin.com/futures/#level-2-market-data
793
- * @param {string} symbol unified symbol of the market to fetch the order book for
794
- * @param {object} [params] extra parameters specific to the exchange API endpoint
795
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
796
- */
797
- async unWatchOrderBook(symbol, params = {}) {
798
- return await this.unWatchOrderBookForSymbols([symbol], params);
799
- }
800
- /**
801
- * @method
802
- * @name kucoinfutures#unWatchOrderBookForSymbols
803
- * @description unWatches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
804
- * @param {string[]} symbols unified array of symbols
805
- * @param {object} [params] extra parameters specific to the exchange API endpoint
806
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/?id=order-book-structure} indexed by market symbols
807
- */
808
- async unWatchOrderBookForSymbols(symbols, params = {}) {
809
- await this.loadMarkets();
810
- symbols = this.marketSymbols(symbols);
811
- const marketIds = this.marketIds(symbols);
812
- const url = await this.negotiate(false);
813
- const topic = '/contractMarket/level2:' + marketIds.join(',');
814
- const subscriptionHashes = [];
815
- const messageHashes = [];
816
- for (let i = 0; i < symbols.length; i++) {
817
- const symbol = symbols[i];
818
- messageHashes.push('unsubscribe:orderbook:' + symbol);
819
- subscriptionHashes.push('orderbook:' + symbol);
820
- }
821
- const subscription = {
822
- 'messageHashes': messageHashes,
823
- 'symbols': symbols,
824
- 'unsubscribe': true,
825
- 'topic': 'orderbook',
826
- 'subMessageHashes': subscriptionHashes,
827
- };
828
- return await this.unSubscribeMultiple(url, messageHashes, topic, messageHashes, params, subscription);
829
- }
830
- handleDelta(orderbook, delta) {
831
- orderbook['nonce'] = this.safeInteger(delta, 'sequence');
832
- const timestamp = this.safeInteger(delta, 'timestamp');
833
- orderbook['timestamp'] = timestamp;
834
- orderbook['datetime'] = this.iso8601(timestamp);
835
- const change = this.safeValue(delta, 'change', {});
836
- const splitChange = change.split(',');
837
- const price = this.safeNumber(splitChange, 0);
838
- const side = this.safeString(splitChange, 1);
839
- const quantity = this.safeNumber(splitChange, 2);
840
- const type = (side === 'buy') ? 'bids' : 'asks';
841
- const value = [price, quantity];
842
- if (type === 'bids') {
843
- const storedBids = orderbook['bids'];
844
- storedBids.storeArray(value);
845
- }
846
- else {
847
- const storedAsks = orderbook['asks'];
848
- storedAsks.storeArray(value);
849
- }
850
- }
851
- handleDeltas(bookside, deltas) {
852
- for (let i = 0; i < deltas.length; i++) {
853
- this.handleDelta(bookside, deltas[i]);
854
- }
855
- }
856
- handleOrderBook(client, message) {
857
- //
858
- // initial snapshot is fetched with ccxt's fetchOrderBook
859
- // the feed does not include a snapshot, just the deltas
860
- //
861
- // {
862
- // "type": "message",
863
- // "topic": "/contractMarket/level2:ADAUSDTM",
864
- // "subject": "level2",
865
- // "data": {
866
- // "sequence": 1668059586457,
867
- // "change": "0.34172,sell,456", // type, side, quantity
868
- // "timestamp": 1668573023223
869
- // }
870
- // }
871
- //
872
- const data = this.safeValue(message, 'data');
873
- const topic = this.safeString(message, 'topic');
874
- const topicParts = topic.split(':');
875
- const marketId = this.safeString(topicParts, 1);
876
- const symbol = this.safeSymbol(marketId, undefined, '-');
877
- const messageHash = 'orderbook:' + symbol;
878
- if (!(symbol in this.orderbooks)) {
879
- const subscriptionArgs = this.safeDict(client.subscriptions, topic, {});
880
- const limit = this.safeInteger(subscriptionArgs, 'limit');
881
- this.orderbooks[symbol] = this.orderBook({}, limit);
882
- }
883
- const storedOrderBook = this.orderbooks[symbol];
884
- const nonce = this.safeInteger(storedOrderBook, 'nonce');
885
- const deltaEnd = this.safeInteger(data, 'sequence');
886
- if (nonce === undefined) {
887
- const cacheLength = storedOrderBook.cache.length;
888
- const topicPartsNew = topic.split(':');
889
- const topicSymbol = this.safeString(topicPartsNew, 1);
890
- const topicChannel = this.safeString(topicPartsNew, 0);
891
- const subscriptions = Object.keys(client.subscriptions);
892
- let subscription = undefined;
893
- for (let i = 0; i < subscriptions.length; i++) {
894
- const key = subscriptions[i];
895
- if ((key.indexOf(topicSymbol) >= 0) && (key.indexOf(topicChannel) >= 0)) {
896
- subscription = client.subscriptions[key];
897
- break;
898
- }
899
- }
900
- const limit = this.safeInteger(subscription, 'limit');
901
- const snapshotDelay = this.handleOption('watchOrderBook', 'snapshotDelay', 5);
902
- if (cacheLength === snapshotDelay) {
903
- this.spawn(this.loadOrderBook, client, messageHash, symbol, limit, {});
904
- }
905
- storedOrderBook.cache.push(data);
906
- return;
907
- }
908
- else if (nonce >= deltaEnd) {
909
- return;
910
- }
911
- this.handleDelta(storedOrderBook, data);
912
- client.resolve(storedOrderBook, messageHash);
913
- }
914
- getCacheIndex(orderbook, cache) {
915
- const firstDelta = this.safeValue(cache, 0);
916
- const nonce = this.safeInteger(orderbook, 'nonce');
917
- const firstDeltaStart = this.safeInteger(firstDelta, 'sequence');
918
- if (nonce < firstDeltaStart - 1) {
919
- return -1;
920
- }
921
- for (let i = 0; i < cache.length; i++) {
922
- const delta = cache[i];
923
- const deltaStart = this.safeInteger(delta, 'sequence');
924
- if (nonce < deltaStart - 1) {
925
- return i;
926
- }
927
- }
928
- return cache.length;
929
- }
930
- handleSystemStatus(client, message) {
931
- //
932
- // todo: answer the question whether handleSystemStatus should be renamed
933
- // and unified as handleStatus for any usage pattern that
934
- // involves system status and maintenance updates
935
- //
936
- // {
937
- // "id": "1578090234088", // connectId
938
- // "type": "welcome",
939
- // }
940
- //
941
- return message;
942
- }
943
- /**
944
- * @method
945
- * @name kucoinfutures#watchOrders
946
- * @description watches information on multiple orders made by the user
947
- * @see https://docs.kucoin.com/futures/#trade-orders-according-to-the-market
948
- * @param {string} symbol unified market symbol of the market orders were made in
949
- * @param {int} [since] the earliest time in ms to fetch orders for
950
- * @param {int} [limit] the maximum number of order structures to retrieve
951
- * @param {object} [params] extra parameters specific to the exchange API endpoint
952
- * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/?id=order-structure}
953
- */
954
- async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
955
- await this.loadMarkets();
956
- const url = await this.negotiate(true);
957
- const topic = '/contractMarket/tradeOrders';
958
- const request = {
959
- 'privateChannel': true,
960
- };
961
- let messageHash = 'orders';
962
- if (symbol !== undefined) {
963
- const market = this.market(symbol);
964
- symbol = market['symbol'];
965
- messageHash = messageHash + ':' + symbol;
966
- }
967
- const orders = await this.subscribe(url, messageHash, topic, undefined, this.extend(request, params));
968
- if (this.newUpdates) {
969
- limit = orders.getLimit(symbol, limit);
970
- }
971
- return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
972
- }
973
- parseWsOrderStatus(status) {
974
- const statuses = {
975
- 'open': 'open',
976
- 'filled': 'closed',
977
- 'match': 'open',
978
- 'update': 'open',
979
- 'canceled': 'canceled',
980
- };
981
- return this.safeString(statuses, status, status);
982
- }
983
- parseWsOrder(order, market = undefined) {
984
- //
985
- // "symbol": "XCAD-USDT",
986
- // {
987
- // "orderType": "limit",
988
- // "side": "buy",
989
- // "orderId": "6249167327218b000135e749",
990
- // "type": "canceled",
991
- // "orderTime": 1648957043065280224,
992
- // "size": "100.452",
993
- // "filledSize": "0",
994
- // "price": "2.9635",
995
- // "clientOid": "buy-XCAD-USDT-1648957043010159",
996
- // "remainSize": "0",
997
- // "status": "done",
998
- // "ts": 1648957054031001037
999
- // }
1000
- //
1001
- const id = this.safeString(order, 'orderId');
1002
- const clientOrderId = this.safeString(order, 'clientOid');
1003
- const orderType = this.safeStringLower(order, 'orderType');
1004
- const price = this.safeString(order, 'price');
1005
- const filled = this.safeString(order, 'filledSize');
1006
- const amount = this.safeString(order, 'size');
1007
- const rawType = this.safeString(order, 'type');
1008
- const status = this.parseWsOrderStatus(rawType);
1009
- const timestamp = this.safeIntegerProduct(order, 'orderTime', 0.000001);
1010
- const marketId = this.safeString(order, 'symbol');
1011
- market = this.safeMarket(marketId, market);
1012
- const symbol = market['symbol'];
1013
- const side = this.safeStringLower(order, 'side');
1014
- return this.safeOrder({
1015
- 'info': order,
1016
- 'symbol': symbol,
1017
- 'id': id,
1018
- 'clientOrderId': clientOrderId,
1019
- 'timestamp': timestamp,
1020
- 'datetime': this.iso8601(timestamp),
1021
- 'lastTradeTimestamp': undefined,
1022
- 'type': orderType,
1023
- 'timeInForce': undefined,
1024
- 'postOnly': undefined,
1025
- 'side': side,
1026
- 'price': price,
1027
- 'stopPrice': undefined,
1028
- 'amount': amount,
1029
- 'cost': undefined,
1030
- 'average': undefined,
1031
- 'filled': filled,
1032
- 'remaining': undefined,
1033
- 'status': status,
1034
- 'fee': undefined,
1035
- 'trades': undefined,
1036
- }, market);
1037
- }
1038
- handleOrder(client, message) {
1039
- const messageHash = 'orders';
1040
- const data = this.safeValue(message, 'data');
1041
- const parsed = this.parseWsOrder(data);
1042
- const symbol = this.safeString(parsed, 'symbol');
1043
- const orderId = this.safeString(parsed, 'id');
1044
- if (symbol !== undefined) {
1045
- if (this.orders === undefined) {
1046
- const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
1047
- this.orders = new ArrayCacheBySymbolById(limit);
1048
- }
1049
- const cachedOrders = this.orders;
1050
- const orders = this.safeValue(cachedOrders.hashmap, symbol, {});
1051
- const order = this.safeValue(orders, orderId);
1052
- if (order !== undefined) {
1053
- // todo add others to calculate average etc
1054
- const stopPrice = this.safeValue(order, 'stopPrice');
1055
- if (stopPrice !== undefined) {
1056
- parsed['stopPrice'] = stopPrice;
1057
- }
1058
- if (order['status'] === 'closed') {
1059
- parsed['status'] = 'closed';
1060
- }
1061
- }
1062
- cachedOrders.append(parsed);
1063
- client.resolve(this.orders, messageHash);
1064
- const symbolSpecificMessageHash = messageHash + ':' + symbol;
1065
- client.resolve(this.orders, symbolSpecificMessageHash);
1066
- }
1067
- }
1068
- /**
1069
- * @method
1070
- * @name kucoinfutures#watchBalance
1071
- * @description watch balance and get the amount of funds available for trading or funds locked in orders
1072
- * @see https://docs.kucoin.com/futures/#account-balance-events
1073
- * @param {object} [params] extra parameters specific to the exchange API endpoint
1074
- * @returns {object} a [balance structure]{@link https://docs.ccxt.com/?id=balance-structure}
1075
- */
1076
- async watchBalance(params = {}) {
1077
- await this.loadMarkets();
1078
- const url = await this.negotiate(true);
1079
- const topic = '/contractAccount/wallet';
62
+ const currency = this.currency(code);
63
+ const amountToPrecision = this.currencyToPrecision(code, amount);
1080
64
  const request = {
1081
- 'privateChannel': true,
65
+ 'currency': this.safeString(currency, 'id'),
66
+ 'amount': amountToPrecision,
1082
67
  };
1083
- const subscription = {
1084
- 'method': this.handleBalanceSubscription,
1085
- };
1086
- const messageHash = 'balance';
1087
- return await this.subscribe(url, messageHash, topic, subscription, this.extend(request, params));
1088
- }
1089
- handleBalance(client, message) {
1090
- //
1091
- // {
1092
- // "id": "6375553193027a0001f6566f",
1093
- // "type": "message",
1094
- // "topic": "/contractAccount/wallet",
1095
- // "userId": "613a896885d8660006151f01",
1096
- // "channelType": "private",
1097
- // "subject": "availableBalance.change",
1098
- // "data": {
1099
- // "currency": "USDT",
1100
- // "holdBalance": "0.0000000000",
1101
- // "availableBalance": "14.0350281903",
1102
- // "timestamp": "1668633905657"
1103
- // }
1104
- // }
1105
- //
1106
- const data = this.safeValue(message, 'data', {});
1107
- this.balance['info'] = data;
1108
- const currencyId = this.safeString(data, 'currency');
1109
- const code = this.safeCurrencyCode(currencyId);
1110
- const account = this.account();
1111
- account['free'] = this.safeString(data, 'availableBalance');
1112
- account['used'] = this.safeString(data, 'holdBalance');
1113
- this.balance[code] = account;
1114
- this.balance = this.safeBalance(this.balance);
1115
- client.resolve(this.balance, 'balance');
1116
- }
1117
- handleBalanceSubscription(client, message, subscription) {
1118
- this.spawn(this.fetchBalanceSnapshot, client, message);
1119
- }
1120
- async fetchBalanceSnapshot(client, message) {
1121
- await this.loadMarkets();
1122
- this.checkRequiredCredentials();
1123
- const messageHash = 'balance';
1124
- const selectedType = this.safeString2(this.options, 'watchBalance', 'defaultType', 'swap'); // spot, margin, main, funding, future, mining, trade, contract, pool
1125
- const params = {
1126
- 'type': selectedType,
1127
- };
1128
- const snapshot = await this.fetchBalance(params);
1129
- //
1130
- // {
1131
- // "info": {
1132
- // "code": "200000",
1133
- // "data": {
1134
- // "accountEquity": 0.0350281903,
1135
- // "unrealisedPNL": 0,
1136
- // "marginBalance": 0.0350281903,
1137
- // "positionMargin": 0,
1138
- // "orderMargin": 0,
1139
- // "frozenFunds": 0,
1140
- // "availableBalance": 0.0350281903,
1141
- // "currency": "USDT"
1142
- // }
1143
- // },
1144
- // "timestamp": undefined,
1145
- // "datetime": undefined,
1146
- // "USDT": {
1147
- // "free": 0.0350281903,
1148
- // "used": 0,
1149
- // "total": 0.0350281903
1150
- // },
1151
- // "free": {
1152
- // "USDT": 0.0350281903
1153
- // },
1154
- // "used": {
1155
- // "USDT": 0
1156
- // },
1157
- // "total": {
1158
- // "USDT": 0.0350281903
1159
- // }
1160
- // }
1161
- //
1162
- const keys = Object.keys(snapshot);
1163
- for (let i = 0; i < keys.length; i++) {
1164
- const code = keys[i];
1165
- if (code !== 'free' && code !== 'used' && code !== 'total' && code !== 'timestamp' && code !== 'datetime' && code !== 'info') {
1166
- this.balance[code] = snapshot[code];
1167
- }
1168
- }
1169
- this.balance['info'] = this.safeValue(snapshot, 'info', {});
1170
- client.resolve(this.balance, messageHash);
1171
- }
1172
- handleSubject(client, message) {
1173
- //
1174
- // {
1175
- // "type": "message",
1176
- // "topic": "/contractMarket/level2:ADAUSDTM",
1177
- // "subject": "level2",
1178
- // "data": {
1179
- // "sequence": 1668059586457,
1180
- // "change": "0.34172,sell,456", // type, side, quantity
1181
- // "timestamp": 1668573023223
1182
- // }
1183
- // }
1184
- //
1185
- const subject = this.safeString(message, 'subject');
1186
- const methods = {
1187
- 'level2': this.handleOrderBook,
1188
- 'ticker': this.handleTicker,
1189
- 'candle.stick': this.handleOHLCV,
1190
- 'tickerV2': this.handleBidAsk,
1191
- 'availableBalance.change': this.handleBalance,
1192
- 'match': this.handleTrade,
1193
- 'orderChange': this.handleOrder,
1194
- 'orderUpdated': this.handleOrder,
1195
- 'position.change': this.handlePosition,
1196
- 'position.settlement': this.handlePosition,
1197
- 'position.adjustRiskLimit': this.handlePosition,
1198
- };
1199
- const method = this.safeValue(methods, subject);
1200
- if (method !== undefined) {
1201
- method.call(this, client, message);
1202
- }
1203
- }
1204
- getMessageHash(elementName, symbol = undefined) {
1205
- // elementName can be 'ticker', 'bidask', ...
1206
- if (symbol !== undefined) {
1207
- return elementName + '@' + symbol;
68
+ const toAccountString = this.parseTransferType(toAccount);
69
+ let response = undefined;
70
+ if (toAccountString === 'TRADE' || toAccountString === 'MAIN') {
71
+ request['recAccountType'] = toAccountString;
72
+ response = await this.futuresPrivatePostTransferOut(this.extend(request, params));
73
+ //
74
+ // {
75
+ // "code": "200000",
76
+ // "data": {
77
+ // "applyId": "6738754373ceee00011ec3f8",
78
+ // "bizNo": "6738754373ceee00011ec3f7",
79
+ // "payAccountType": "CONTRACT",
80
+ // "payTag": "DEFAULT",
81
+ // "remark": "",
82
+ // "recAccountType": "MAIN",
83
+ // "recTag": "DEFAULT",
84
+ // "recRemark": "",
85
+ // "recSystem": "KUCOIN",
86
+ // "status": "PROCESSING",
87
+ // "currency": "USDT",
88
+ // "amount": "5",
89
+ // "fee": "0",
90
+ // "sn": 1519769124846692,
91
+ // "reason": "",
92
+ // "createdAt": 1731753283000,
93
+ // "updatedAt": 1731753283000
94
+ // }
95
+ // }
96
+ //
97
+ }
98
+ else if (toAccount === 'future' || toAccount === 'swap' || toAccount === 'contract') {
99
+ request['payAccountType'] = this.parseTransferType(fromAccount);
100
+ response = await this.futuresPrivatePostTransferIn(this.extend(request, params));
101
+ //
102
+ // {
103
+ // "code": "200000",
104
+ // "data": {
105
+ // "applyId": "5bffb63303aa675e8bbe18f9" // Transfer-out request ID
106
+ // }
107
+ // }
108
+ //
1208
109
  }
1209
110
  else {
1210
- return elementName + 's@all';
1211
- }
1212
- }
1213
- ping(client) {
1214
- // kucoin does not support built-in ws protocol-level ping-pong
1215
- // instead it requires a custom json-based text ping-pong
1216
- // https://docs.kucoin.com/#ping
1217
- const id = this.requestId().toString();
1218
- return {
1219
- 'id': id,
1220
- 'type': 'ping',
1221
- };
1222
- }
1223
- handlePong(client, message) {
1224
- // https://docs.kucoin.com/#ping
1225
- client.lastPong = this.milliseconds();
1226
- return message;
1227
- }
1228
- handleErrorMessage(client, message) {
1229
- //
1230
- // {
1231
- // "id": "64d8732c856851144bded10d",
1232
- // "type": "error",
1233
- // "code": 401,
1234
- // "data": "token is expired"
1235
- // }
1236
- //
1237
- const data = this.safeString(message, 'data', '');
1238
- if (data === 'token is expired') {
1239
- let type = 'public';
1240
- if (client.url.indexOf('connectId=private') >= 0) {
1241
- type = 'private';
1242
- }
1243
- this.options['urls'][type] = undefined;
1244
- }
1245
- this.handleErrors(1, '', client.url, '', {}, data, message, {}, {});
1246
- return true;
1247
- }
1248
- handleSubscriptionStatus(client, message) {
1249
- //
1250
- // {
1251
- // "id": "1578090438322",
1252
- // "type": "ack"
1253
- // }
1254
- //
1255
- const id = this.safeString(message, 'id');
1256
- if (!(id in client.subscriptions)) {
1257
- return;
1258
- }
1259
- const subscriptionHash = this.safeString(client.subscriptions, id);
1260
- const subscription = this.safeValue(client.subscriptions, subscriptionHash);
1261
- delete client.subscriptions[id];
1262
- const method = this.safeValue(subscription, 'method');
1263
- if (method !== undefined) {
1264
- method.call(this, client, message, subscription);
1265
- }
1266
- const isUnSub = this.safeBool(subscription, 'unsubscribe', false);
1267
- if (isUnSub) {
1268
- const messageHashes = this.safeList(subscription, 'messageHashes', []);
1269
- const subMessageHashes = this.safeList(subscription, 'subMessageHashes', []);
1270
- for (let i = 0; i < messageHashes.length; i++) {
1271
- const messageHash = messageHashes[i];
1272
- const subHash = subMessageHashes[i];
1273
- this.cleanUnsubscription(client, subHash, messageHash);
1274
- }
1275
- this.cleanCache(subscription);
111
+ throw new BadRequest(this.id + ' transfer() only supports transfers between future/swap, spot and funding accounts');
1276
112
  }
113
+ const data = this.safeDict(response, 'data', {});
114
+ return this.extend(this.parseTransfer(data, currency), {
115
+ 'amount': this.parseNumber(amountToPrecision),
116
+ 'fromAccount': fromAccount,
117
+ 'toAccount': toAccount,
118
+ });
1277
119
  }
1278
- handleMessage(client, message) {
1279
- const type = this.safeString(message, 'type');
1280
- const methods = {
1281
- // 'heartbeat': this.handleHeartbeat,
1282
- 'welcome': this.handleSystemStatus,
1283
- 'message': this.handleSubject,
1284
- 'pong': this.handlePong,
1285
- 'error': this.handleErrorMessage,
1286
- 'ack': this.handleSubscriptionStatus,
120
+ parseTransferType(transferType) {
121
+ const transferTypes = {
122
+ 'spot': 'TRADE',
123
+ 'funding': 'MAIN',
1287
124
  };
1288
- const method = this.safeValue(methods, type);
1289
- if (method !== undefined) {
1290
- method.call(this, client, message);
1291
- }
125
+ return this.safeStringUpper(transferTypes, transferType, transferType);
1292
126
  }
1293
127
  }