ccxt 4.5.44 → 4.5.46

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