ccxt 4.3.84 → 4.3.86

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 (71) hide show
  1. package/README.md +7 -5
  2. package/dist/ccxt.browser.min.js +15 -15
  3. package/dist/cjs/ccxt.js +7 -1
  4. package/dist/cjs/src/abstract/hashkey.js +9 -0
  5. package/dist/cjs/src/base/Exchange.js +1 -1
  6. package/dist/cjs/src/base/errors.js +8 -1
  7. package/dist/cjs/src/binance.js +4 -2
  8. package/dist/cjs/src/bitfinex.js +2 -2
  9. package/dist/cjs/src/bitmex.js +4 -0
  10. package/dist/cjs/src/bybit.js +15 -14
  11. package/dist/cjs/src/cryptocom.js +117 -2
  12. package/dist/cjs/src/hashkey.js +4328 -0
  13. package/dist/cjs/src/hyperliquid.js +85 -65
  14. package/dist/cjs/src/indodax.js +37 -9
  15. package/dist/cjs/src/kraken.js +29 -1
  16. package/dist/cjs/src/krakenfutures.js +12 -10
  17. package/dist/cjs/src/kucoinfutures.js +5 -0
  18. package/dist/cjs/src/mexc.js +2 -2
  19. package/dist/cjs/src/pro/ascendex.js +45 -5
  20. package/dist/cjs/src/pro/binance.js +1 -1
  21. package/dist/cjs/src/pro/bingx.js +13 -12
  22. package/dist/cjs/src/pro/bitget.js +113 -4
  23. package/dist/cjs/src/pro/hashkey.js +839 -0
  24. package/dist/cjs/src/pro/hyperliquid.js +123 -0
  25. package/dist/cjs/src/pro/mexc.js +13 -7
  26. package/dist/cjs/src/pro/okx.js +25 -4
  27. package/dist/cjs/src/pro/woo.js +1 -0
  28. package/dist/cjs/src/pro/woofipro.js +1 -0
  29. package/dist/cjs/src/pro/xt.js +1 -0
  30. package/js/ccxt.d.ts +9 -3
  31. package/js/ccxt.js +7 -3
  32. package/js/src/abstract/cryptocom.d.ts +2 -0
  33. package/js/src/abstract/hashkey.d.ts +70 -0
  34. package/js/src/abstract/hashkey.js +11 -0
  35. package/js/src/abstract/kucoinfutures.d.ts +2 -0
  36. package/js/src/base/Exchange.js +1 -1
  37. package/js/src/base/errorHierarchy.d.ts +1 -0
  38. package/js/src/base/errorHierarchy.js +1 -0
  39. package/js/src/base/errors.d.ts +5 -1
  40. package/js/src/base/errors.js +8 -2
  41. package/js/src/binance.js +4 -2
  42. package/js/src/bitfinex.js +2 -2
  43. package/js/src/bitmex.js +4 -0
  44. package/js/src/bybit.js +16 -15
  45. package/js/src/cryptocom.d.ts +5 -1
  46. package/js/src/cryptocom.js +117 -2
  47. package/js/src/hashkey.d.ts +178 -0
  48. package/js/src/hashkey.js +4329 -0
  49. package/js/src/hyperliquid.d.ts +3 -0
  50. package/js/src/hyperliquid.js +85 -65
  51. package/js/src/indodax.js +37 -9
  52. package/js/src/kraken.js +29 -1
  53. package/js/src/krakenfutures.js +12 -10
  54. package/js/src/kucoinfutures.js +5 -0
  55. package/js/src/mexc.js +2 -2
  56. package/js/src/pro/ascendex.d.ts +2 -0
  57. package/js/src/pro/ascendex.js +45 -5
  58. package/js/src/pro/binance.js +1 -1
  59. package/js/src/pro/bingx.js +13 -12
  60. package/js/src/pro/bitget.d.ts +4 -0
  61. package/js/src/pro/bitget.js +113 -4
  62. package/js/src/pro/hashkey.d.ts +34 -0
  63. package/js/src/pro/hashkey.js +840 -0
  64. package/js/src/pro/hyperliquid.d.ts +7 -1
  65. package/js/src/pro/hyperliquid.js +123 -0
  66. package/js/src/pro/mexc.js +13 -7
  67. package/js/src/pro/okx.js +25 -4
  68. package/js/src/pro/woo.js +1 -0
  69. package/js/src/pro/woofipro.js +1 -0
  70. package/js/src/pro/xt.js +1 -0
  71. package/package.json +1 -1
@@ -0,0 +1,4329 @@
1
+ // ----------------------------------------------------------------------------
2
+
3
+ // PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ // https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+ // EDIT THE CORRESPONDENT .ts FILE INSTEAD
6
+
7
+ // ---------------------------------------------------------------------------
8
+ import Exchange from './abstract/hashkey.js';
9
+ import { AccountNotEnabled, AccountSuspended, ArgumentsRequired, AuthenticationError, BadRequest, BadSymbol, ContractUnavailable, DDoSProtection, DuplicateOrderId, ExchangeError, ExchangeNotAvailable, InsufficientFunds, InvalidAddress, InvalidNonce, InvalidOrder, NotSupported, OperationFailed, OperationRejected, OrderImmediatelyFillable, OrderNotFillable, OrderNotFound, PermissionDenied, RateLimitExceeded, RequestTimeout } from './base/errors.js';
10
+ import { Precise } from './base/Precise.js';
11
+ import { TICK_SIZE } from './base/functions/number.js';
12
+ import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
13
+ // ---------------------------------------------------------------------------
14
+ /**
15
+ * @class hashkey
16
+ * @augments Exchange
17
+ */
18
+ export default class hashkey extends Exchange {
19
+ describe() {
20
+ return this.deepExtend(super.describe(), {
21
+ 'id': 'hashkey',
22
+ 'name': 'HashKey Global',
23
+ 'countries': ['BM'],
24
+ 'rateLimit': 100,
25
+ 'version': 'v1',
26
+ 'certified': true,
27
+ 'pro': true,
28
+ 'hostname': '/api-glb',
29
+ 'has': {
30
+ 'CORS': undefined,
31
+ 'spot': true,
32
+ 'margin': false,
33
+ 'swap': false,
34
+ 'future': false,
35
+ 'option': false,
36
+ 'addMargin': false,
37
+ 'cancelAllOrders': true,
38
+ 'cancelAllOrdersAfter': false,
39
+ 'cancelOrder': true,
40
+ 'cancelOrders': true,
41
+ 'cancelWithdraw': false,
42
+ 'closePosition': false,
43
+ 'createConvertTrade': false,
44
+ 'createDepositAddress': false,
45
+ 'createMarketBuyOrderWithCost': true,
46
+ 'createMarketOrder': true,
47
+ 'createMarketOrderWithCost': false,
48
+ 'createMarketSellOrderWithCost': false,
49
+ 'createOrder': true,
50
+ 'createOrderWithTakeProfitAndStopLoss': false,
51
+ 'createReduceOnlyOrder': true,
52
+ 'createStopLimitOrder': true,
53
+ 'createStopLossOrder': false,
54
+ 'createStopMarketOrder': true,
55
+ 'createStopOrder': true,
56
+ 'createTakeProfitOrder': false,
57
+ 'createTrailingAmountOrder': false,
58
+ 'createTrailingPercentOrder': false,
59
+ 'createTriggerOrder': true,
60
+ 'fetchAccounts': true,
61
+ 'fetchBalance': true,
62
+ 'fetchCanceledAndClosedOrders': true,
63
+ 'fetchCanceledOrders': true,
64
+ 'fetchClosedOrder': true,
65
+ 'fetchClosedOrders': false,
66
+ 'fetchConvertCurrencies': false,
67
+ 'fetchConvertQuote': false,
68
+ 'fetchConvertTrade': false,
69
+ 'fetchConvertTradeHistory': false,
70
+ 'fetchCurrencies': true,
71
+ 'fetchDepositAddress': true,
72
+ 'fetchDeposits': true,
73
+ 'fetchDepositsWithdrawals': false,
74
+ 'fetchFundingHistory': false,
75
+ 'fetchFundingRate': true,
76
+ 'fetchFundingRateHistory': true,
77
+ 'fetchFundingRates': true,
78
+ 'fetchIndexOHLCV': false,
79
+ 'fetchLedger': true,
80
+ 'fetchLeverage': true,
81
+ 'fetchLeverageTiers': true,
82
+ 'fetchMarginAdjustmentHistory': false,
83
+ 'fetchMarginMode': false,
84
+ 'fetchMarkets': true,
85
+ 'fetchMarkOHLCV': false,
86
+ 'fetchMyTrades': true,
87
+ 'fetchOHLCV': true,
88
+ 'fetchOpenInterestHistory': false,
89
+ 'fetchOpenOrder': false,
90
+ 'fetchOpenOrders': true,
91
+ 'fetchOrder': true,
92
+ 'fetchOrderBook': true,
93
+ 'fetchOrders': false,
94
+ 'fetchOrderTrades': false,
95
+ 'fetchPosition': false,
96
+ 'fetchPositionHistory': false,
97
+ 'fetchPositionMode': false,
98
+ 'fetchPositions': true,
99
+ 'fetchPositionsForSymbol': true,
100
+ 'fetchPositionsHistory': false,
101
+ 'fetchPremiumIndexOHLCV': false,
102
+ 'fetchStatus': true,
103
+ 'fetchTicker': true,
104
+ 'fetchTickers': true,
105
+ 'fetchTime': true,
106
+ 'fetchTrades': true,
107
+ 'fetchTradingFee': true,
108
+ 'fetchTradingFees': true,
109
+ 'fetchTransactions': false,
110
+ 'fetchTransfers': false,
111
+ 'fetchWithdrawals': true,
112
+ 'reduceMargin': false,
113
+ 'sandbox': false,
114
+ 'setLeverage': true,
115
+ 'setMargin': false,
116
+ 'setPositionMode': false,
117
+ 'transfer': true,
118
+ 'withdraw': true,
119
+ },
120
+ 'timeframes': {
121
+ '1m': '1m',
122
+ '3m': '3m',
123
+ '5m': '5m',
124
+ '15m': '15m',
125
+ '30m': '30m',
126
+ '1h': '1h',
127
+ '2h': '2h',
128
+ '4h': '4h',
129
+ '6h': '6h',
130
+ '8h': '8h',
131
+ '12h': '12h',
132
+ '1d': '1d',
133
+ '1w': '1w',
134
+ '1M': '1M',
135
+ },
136
+ 'urls': {
137
+ 'logo': 'https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98',
138
+ 'api': {
139
+ 'public': 'https://api-glb.hashkey.com',
140
+ 'private': 'https://api-glb.hashkey.com',
141
+ },
142
+ 'test': {
143
+ 'public': 'https://api-glb.sim.hashkeydev.com',
144
+ 'private': 'https://api-glb.sim.hashkeydev.com',
145
+ },
146
+ 'www': 'https://global.hashkey.com/',
147
+ 'doc': 'https://hashkeyglobal-apidoc.readme.io/',
148
+ 'fees': 'https://support.global.hashkey.com/hc/en-us/articles/13199900083612-HashKey-Global-Fee-Structure',
149
+ 'referral': '',
150
+ },
151
+ 'api': {
152
+ 'public': {
153
+ 'get': {
154
+ 'api/v1/exchangeInfo': 5,
155
+ 'quote/v1/depth': 1,
156
+ 'quote/v1/trades': 1,
157
+ 'quote/v1/klines': 1,
158
+ 'quote/v1/ticker/24hr': 1,
159
+ 'quote/v1/ticker/price': 1,
160
+ 'quote/v1/ticker/bookTicker': 1,
161
+ 'quote/v1/depth/merged': 1,
162
+ 'quote/v1/markPrice': 1,
163
+ 'quote/v1/index': 1,
164
+ 'api/v1/futures/fundingRate': 1,
165
+ 'api/v1/futures/historyFundingRate': 1,
166
+ 'api/v1/ping': 1,
167
+ 'api/v1/time': 1,
168
+ },
169
+ },
170
+ 'private': {
171
+ 'get': {
172
+ 'api/v1/spot/order': 1,
173
+ 'api/v1/spot/openOrders': 1,
174
+ 'api/v1/spot/tradeOrders': 5,
175
+ 'api/v1/futures/leverage': 1,
176
+ 'api/v1/futures/order': 1,
177
+ 'api/v1/futures/openOrders': 1,
178
+ 'api/v1/futures/userTrades': 1,
179
+ 'api/v1/futures/positions': 1,
180
+ 'api/v1/futures/historyOrders': 1,
181
+ 'api/v1/futures/balance': 1,
182
+ 'api/v1/futures/liquidationAssignStatus': 1,
183
+ 'api/v1/futures/riskLimit': 1,
184
+ 'api/v1/futures/commissionRate': 1,
185
+ 'api/v1/futures/getBestOrder': 1,
186
+ 'api/v1/account/vipInfo': 1,
187
+ 'api/v1/account': 1,
188
+ 'api/v1/account/trades': 5,
189
+ 'api/v1/account/type': 5,
190
+ 'api/v1/account/checkApiKey': 1,
191
+ 'api/v1/account/balanceFlow': 5,
192
+ 'api/v1/spot/subAccount/openOrders': 1,
193
+ 'api/v1/spot/subAccount/tradeOrders': 1,
194
+ 'api/v1/subAccount/trades': 1,
195
+ 'api/v1/futures/subAccount/openOrders': 1,
196
+ 'api/v1/futures/subAccount/historyOrders': 1,
197
+ 'api/v1/futures/subAccount/userTrades': 1,
198
+ 'api/v1/account/deposit/address': 1,
199
+ 'api/v1/account/depositOrders': 1,
200
+ 'api/v1/account/withdrawOrders': 1,
201
+ },
202
+ 'post': {
203
+ 'api/v1/userDataStream': 1,
204
+ 'api/v1/spot/orderTest': 1,
205
+ 'api/v1/spot/order': 1,
206
+ 'api/v1.1/spot/order': 1,
207
+ 'api/v1/spot/batchOrders': 5,
208
+ 'api/v1/futures/leverage': 1,
209
+ 'api/v1/futures/order': 1,
210
+ 'api/v1/futures/position/trading-stop': 3,
211
+ 'api/v1/futures/batchOrders': 5,
212
+ 'api/v1/account/assetTransfer': 1,
213
+ 'api/v1/account/authAddress': 1,
214
+ 'api/v1/account/withdraw': 1,
215
+ },
216
+ 'put': {
217
+ 'api/v1/userDataStream': 1,
218
+ },
219
+ 'delete': {
220
+ 'api/v1/spot/order': 1,
221
+ 'api/v1/spot/openOrders': 5,
222
+ 'api/v1/spot/cancelOrderByIds': 5,
223
+ 'api/v1/futures/order': 1,
224
+ 'api/v1/futures/batchOrders': 1,
225
+ 'api/v1/futures/cancelOrderByIds': 1,
226
+ 'api/v1/userDataStream': 1,
227
+ },
228
+ },
229
+ },
230
+ 'fees': {
231
+ 'trading': {
232
+ 'spot': {
233
+ 'tierBased': true,
234
+ 'percentage': true,
235
+ 'feeSide': 'get',
236
+ 'maker': this.parseNumber('0.0012'),
237
+ 'taker': this.parseNumber('0.0012'),
238
+ 'tiers': {
239
+ 'maker': [
240
+ [this.parseNumber('0'), this.parseNumber('0.0012')],
241
+ [this.parseNumber('1000000'), this.parseNumber('0.00080')],
242
+ [this.parseNumber('5000000'), this.parseNumber('0.00070')],
243
+ [this.parseNumber('10000000'), this.parseNumber('0.00060')],
244
+ [this.parseNumber('50000000'), this.parseNumber('0.00040')],
245
+ [this.parseNumber('200000000'), this.parseNumber('0.00030')],
246
+ [this.parseNumber('400000000'), this.parseNumber('0.00010')],
247
+ [this.parseNumber('800000000'), this.parseNumber('0.00')],
248
+ ],
249
+ 'taker': [
250
+ [this.parseNumber('0'), this.parseNumber('0.0012')],
251
+ [this.parseNumber('1000000'), this.parseNumber('0.00090')],
252
+ [this.parseNumber('5000000'), this.parseNumber('0.00085')],
253
+ [this.parseNumber('10000000'), this.parseNumber('0.00075')],
254
+ [this.parseNumber('50000000'), this.parseNumber('0.00065')],
255
+ [this.parseNumber('200000000'), this.parseNumber('0.00045')],
256
+ [this.parseNumber('400000000'), this.parseNumber('0.00040')],
257
+ [this.parseNumber('800000000'), this.parseNumber('0.00035')],
258
+ ],
259
+ },
260
+ },
261
+ 'swap': {
262
+ 'tierBased': true,
263
+ 'percentage': true,
264
+ 'feeSide': 'get',
265
+ 'maker': this.parseNumber('0.00025'),
266
+ 'taker': this.parseNumber('0.00060'),
267
+ 'tiers': {
268
+ 'maker': [
269
+ [this.parseNumber('0'), this.parseNumber('0.00025')],
270
+ [this.parseNumber('1000000'), this.parseNumber('0.00016')],
271
+ [this.parseNumber('5000000'), this.parseNumber('0.00014')],
272
+ [this.parseNumber('10000000'), this.parseNumber('0.00012')],
273
+ [this.parseNumber('50000000'), this.parseNumber('0.000080')],
274
+ [this.parseNumber('200000000'), this.parseNumber('0.000060')],
275
+ [this.parseNumber('400000000'), this.parseNumber('0.000020')],
276
+ [this.parseNumber('800000000'), this.parseNumber('0.00')],
277
+ ],
278
+ 'taker': [
279
+ [this.parseNumber('0'), this.parseNumber('0.00060')],
280
+ [this.parseNumber('1000000'), this.parseNumber('0.00050')],
281
+ [this.parseNumber('5000000'), this.parseNumber('0.00045')],
282
+ [this.parseNumber('10000000'), this.parseNumber('0.00040')],
283
+ [this.parseNumber('50000000'), this.parseNumber('0.00035')],
284
+ [this.parseNumber('200000000'), this.parseNumber('0.00030')],
285
+ [this.parseNumber('400000000'), this.parseNumber('0.00025')],
286
+ [this.parseNumber('800000000'), this.parseNumber('0.00020')],
287
+ ],
288
+ },
289
+ },
290
+ },
291
+ },
292
+ 'options': {
293
+ 'broker': '10000700011',
294
+ 'recvWindow': undefined,
295
+ 'sandboxMode': false,
296
+ 'networks': {
297
+ 'BTC': 'BTC',
298
+ 'ERC20': 'ETH',
299
+ 'AVAX': 'AvalancheC',
300
+ 'SOL': 'Solana',
301
+ 'MATIC': 'Polygon',
302
+ 'ATOM': 'Cosmos',
303
+ 'DOT': 'Polkadot',
304
+ 'LTC': 'LTC',
305
+ 'OPTIMISM': 'Optimism',
306
+ 'ARB': 'Arbitrum',
307
+ 'DOGE': 'Dogecoin',
308
+ 'TRC20': 'Tron',
309
+ 'ZKSYNC': 'zkSync',
310
+ 'TON': 'TON',
311
+ 'KLAYTN': 'Klaytn',
312
+ 'MERLINCHAIN': 'Merlin Chain',
313
+ },
314
+ 'networksById': {
315
+ 'BTC': 'BTC',
316
+ 'Bitcoin': 'BTC',
317
+ 'ETH': 'ERC20',
318
+ 'ERC20': 'ERC20',
319
+ 'AvalancheC': 'AVAX',
320
+ 'AVAX C-Chain': 'AVAX',
321
+ 'Solana': 'SOL',
322
+ 'Cosmos': 'ATOM',
323
+ 'Arbitrum': 'ARB',
324
+ 'Polygon': 'MATIC',
325
+ 'Optimism': 'OPTIMISM',
326
+ 'Polkadot': 'DOT',
327
+ 'LTC': 'LTC',
328
+ 'Litecoin': 'LTC',
329
+ 'Dogecoin': 'DOGE',
330
+ 'Merlin Chain': 'MERLINCHAIN',
331
+ 'zkSync': 'ZKSYNC',
332
+ 'TRC20': 'TRC20',
333
+ 'Tron': 'TRC20',
334
+ 'TON': 'TON',
335
+ 'BSC(BEP20)': 'BSC',
336
+ 'Klaytn': 'KLAYTN',
337
+ },
338
+ 'defaultNetwork': 'ERC20',
339
+ },
340
+ 'commonCurrencies': {},
341
+ 'exceptions': {
342
+ 'exact': {
343
+ '0001': BadRequest,
344
+ '0002': AuthenticationError,
345
+ '0003': RateLimitExceeded,
346
+ '0102': AuthenticationError,
347
+ '0103': AuthenticationError,
348
+ '0104': PermissionDenied,
349
+ '0201': ExchangeError,
350
+ '0202': PermissionDenied,
351
+ '0206': BadRequest,
352
+ '0207': BadRequest,
353
+ '0209': BadRequest,
354
+ '0210': BadRequest,
355
+ '0211': OrderNotFound,
356
+ '0401': InsufficientFunds,
357
+ '0402': BadRequest,
358
+ '-1000': ExchangeError,
359
+ '-1001': ExchangeError,
360
+ '-100010': BadSymbol,
361
+ '-100012': BadSymbol,
362
+ '-1002': AuthenticationError,
363
+ '-1004': BadRequest,
364
+ '-1005': PermissionDenied,
365
+ '-1006': ExchangeError,
366
+ '-1007': RequestTimeout,
367
+ '-1014': InvalidOrder,
368
+ '-1015': InvalidOrder,
369
+ '-1020': OperationRejected,
370
+ '-1021': InvalidNonce,
371
+ '-1024': BadRequest,
372
+ '-1101': ExchangeNotAvailable,
373
+ '-1115': InvalidOrder,
374
+ '-1117': InvalidOrder,
375
+ '-1123': InvalidOrder,
376
+ '-1124': InvalidOrder,
377
+ '-1126': InvalidOrder,
378
+ '-1129': BadRequest,
379
+ '-1130': BadRequest,
380
+ '-1132': BadRequest,
381
+ '-1133': BadRequest,
382
+ '-1135': BadRequest,
383
+ '-1136': BadRequest,
384
+ '-1138': InvalidOrder,
385
+ '-1137': InvalidOrder,
386
+ '-1139': OrderImmediatelyFillable,
387
+ '-1140': InvalidOrder,
388
+ '-1141': DuplicateOrderId,
389
+ '-1142': OrderNotFillable,
390
+ '-1143': OrderNotFound,
391
+ '-1144': OperationRejected,
392
+ '-1145': NotSupported,
393
+ '-1146': RequestTimeout,
394
+ '-1147': RequestTimeout,
395
+ '-1148': InvalidOrder,
396
+ '-1149': OperationRejected,
397
+ '-1150': OperationFailed,
398
+ '-1151': OperationRejected,
399
+ '-1152': AccountNotEnabled,
400
+ '-1153': InvalidOrder,
401
+ '-1154': InvalidOrder,
402
+ '-1155': OperationRejected,
403
+ '-1156': OperationFailed,
404
+ '-1157': OperationFailed,
405
+ '-1158': OperationFailed,
406
+ '-1159': AccountNotEnabled,
407
+ '-1160': AccountNotEnabled,
408
+ '-1161': OperationFailed,
409
+ '-1162': ContractUnavailable,
410
+ '-1163': InvalidAddress,
411
+ '-1164': OperationFailed,
412
+ '-1165': ArgumentsRequired,
413
+ '-1166': OperationRejected,
414
+ '-1167': BadRequest,
415
+ '-1168': BadRequest,
416
+ '-1169': PermissionDenied,
417
+ '-1170': PermissionDenied,
418
+ '-1171': PermissionDenied,
419
+ '-1172': BadRequest,
420
+ '-1173': BadRequest,
421
+ '-1174': PermissionDenied,
422
+ '-1175': BadRequest,
423
+ '-1176': BadRequest,
424
+ '-1177': InvalidOrder,
425
+ '-1178': AccountNotEnabled,
426
+ '-1179': AccountSuspended,
427
+ '-1181': ExchangeError,
428
+ '-1193': OperationRejected,
429
+ '-1194': OperationRejected,
430
+ '-1195': BadRequest,
431
+ '-1196': BadRequest,
432
+ '-1200': BadRequest,
433
+ '-1201': BadRequest,
434
+ '-1202': BadRequest,
435
+ '-1203': BadRequest,
436
+ '-1204': BadRequest,
437
+ '-1205': AccountNotEnabled,
438
+ '-1206': BadRequest,
439
+ '-1207': BadRequest,
440
+ '-1208': BadRequest,
441
+ '-1209': BadRequest,
442
+ '-2001': ExchangeNotAvailable,
443
+ '-2002': OperationFailed,
444
+ '-2003': OperationFailed,
445
+ '-2004': OperationFailed,
446
+ '-2005': RequestTimeout,
447
+ '-2010': OperationRejected,
448
+ '-2011': OperationRejected,
449
+ '-2016': OperationRejected,
450
+ '-2017': OperationRejected,
451
+ '-2018': OperationRejected,
452
+ '-2019': PermissionDenied,
453
+ '-2020': PermissionDenied,
454
+ '-2021': PermissionDenied,
455
+ '-2022': OperationRejected,
456
+ '-2023': AuthenticationError,
457
+ '-2024': AccountNotEnabled,
458
+ '-2025': AccountNotEnabled,
459
+ '-2026': BadRequest,
460
+ '-2027': OperationRejected,
461
+ '-2028': OperationRejected,
462
+ '-2029': OperationRejected,
463
+ '-2030': InsufficientFunds,
464
+ '-2031': NotSupported,
465
+ '-2032': OperationRejected,
466
+ '-2033': OperationFailed,
467
+ '-2034': InsufficientFunds,
468
+ '-2035': OperationRejected,
469
+ '-2036': NotSupported,
470
+ '-2037': ExchangeError,
471
+ '-2038': InsufficientFunds,
472
+ '-2039': NotSupported,
473
+ '-2040': ExchangeNotAvailable,
474
+ '-2041': BadRequest,
475
+ '-2042': OperationRejected,
476
+ '-2043': OperationRejected,
477
+ '-2044': BadRequest,
478
+ '-2045': BadRequest,
479
+ '-2046': BadRequest,
480
+ '-2048': BadRequest,
481
+ '-2049': BadRequest,
482
+ '-2050': BadRequest,
483
+ '-2051': OperationRejected,
484
+ '-2052': OperationRejected,
485
+ '-2053': OperationRejected,
486
+ '-2054': BadRequest,
487
+ '-2055': BadRequest,
488
+ '-2056': BadRequest,
489
+ '-2057': BadRequest,
490
+ '-3117': PermissionDenied,
491
+ '-3143': PermissionDenied,
492
+ '-3144': PermissionDenied,
493
+ '-3145': DDoSProtection,
494
+ '-4001': BadRequest,
495
+ '-4002': BadRequest,
496
+ '-4003': InsufficientFunds,
497
+ '-4004': BadRequest,
498
+ '-4005': BadRequest,
499
+ '-4006': AccountNotEnabled,
500
+ '-4007': NotSupported,
501
+ '-4008': AccountNotEnabled,
502
+ '-4009': PermissionDenied,
503
+ '-4010': PermissionDenied,
504
+ '-4011': ExchangeError,
505
+ '-4012': ExchangeError,
506
+ '-4013': OperationFailed, // Withdraw repeatly
507
+ },
508
+ 'broad': {},
509
+ },
510
+ 'precisionMode': TICK_SIZE,
511
+ });
512
+ }
513
+ async fetchTime(params = {}) {
514
+ /**
515
+ * @method
516
+ * @name hashkey#fetchTime
517
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
518
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/check-server-time
519
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
520
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
521
+ */
522
+ const response = await this.publicGetApiV1Time(params);
523
+ //
524
+ // {
525
+ // "serverTime": 1721661553214
526
+ // }
527
+ //
528
+ return this.safeInteger(response, 'serverTime');
529
+ }
530
+ async fetchStatus(params = {}) {
531
+ /**
532
+ * @method
533
+ * @name hashkey#fetchStatus
534
+ * @description the latest known information on the availability of the exchange API
535
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/test-connectivity
536
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
537
+ * @returns {object} a [status structure]{@link https://docs.ccxt.com/#/?id=exchange-status-structure}
538
+ */
539
+ const response = await this.publicGetApiV1Ping(params);
540
+ //
541
+ // {}
542
+ //
543
+ return {
544
+ 'status': 'ok',
545
+ 'updated': undefined,
546
+ 'eta': undefined,
547
+ 'url': undefined,
548
+ 'info': response,
549
+ };
550
+ }
551
+ async fetchMarkets(params = {}) {
552
+ /**
553
+ * @method
554
+ * @name hashkey#fetchMarkets
555
+ * @description retrieves data on all markets for the exchange
556
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/exchangeinfo
557
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
558
+ * @param {string} [params.symbol] the id of the market to fetch
559
+ * @returns {object[]} an array of objects representing market data
560
+ */
561
+ let symbol = undefined;
562
+ const request = {};
563
+ [symbol, params] = this.handleOptionAndParams(params, 'fetchMarkets', 'symbol');
564
+ if (symbol !== undefined) {
565
+ request['symbol'] = symbol;
566
+ }
567
+ const response = await this.publicGetApiV1ExchangeInfo(this.extend(request, params));
568
+ //
569
+ // {
570
+ // "timezone": "UTC",
571
+ // "serverTime": "1721661653952",
572
+ // "brokerFilters": [],
573
+ // "symbols": [
574
+ // {
575
+ // "symbol": "BTCUSDT",
576
+ // "symbolName": "BTCUSDT",
577
+ // "status": "TRADING",
578
+ // "baseAsset": "BTC",
579
+ // "baseAssetName": "BTC",
580
+ // "baseAssetPrecision": "0.00001",
581
+ // "quoteAsset": "USDT",
582
+ // "quoteAssetName": "USDT",
583
+ // "quotePrecision": "0.0000001",
584
+ // "retailAllowed": true,
585
+ // "piAllowed": true,
586
+ // "corporateAllowed": true,
587
+ // "omnibusAllowed": true,
588
+ // "icebergAllowed": false,
589
+ // "isAggregate": false,
590
+ // "allowMargin": false,
591
+ // "filters": [
592
+ // {
593
+ // "minPrice": "0.01",
594
+ // "maxPrice": "100000.00000000",
595
+ // "tickSize": "0.01",
596
+ // "filterType": "PRICE_FILTER"
597
+ // },
598
+ // {
599
+ // "minQty": "0.00001",
600
+ // "maxQty": "8",
601
+ // "stepSize": "0.00001",
602
+ // "marketOrderMinQty": "0.00001",
603
+ // "marketOrderMaxQty": "4",
604
+ // "filterType": "LOT_SIZE"
605
+ // },
606
+ // {
607
+ // "minNotional": "1",
608
+ // "filterType": "MIN_NOTIONAL"
609
+ // },
610
+ // {
611
+ // "minAmount": "1",
612
+ // "maxAmount": "400000",
613
+ // "minBuyPrice": "0",
614
+ // "marketOrderMinAmount": "1",
615
+ // "marketOrderMaxAmount": "200000",
616
+ // "filterType": "TRADE_AMOUNT"
617
+ // },
618
+ // {
619
+ // "maxSellPrice": "0",
620
+ // "buyPriceUpRate": "0.1",
621
+ // "sellPriceDownRate": "0.1",
622
+ // "filterType": "LIMIT_TRADING"
623
+ // },
624
+ // {
625
+ // "buyPriceUpRate": "0.1",
626
+ // "sellPriceDownRate": "0.1",
627
+ // "filterType": "MARKET_TRADING"
628
+ // },
629
+ // {
630
+ // "noAllowMarketStartTime": "1710485700000",
631
+ // "noAllowMarketEndTime": "1710486000000",
632
+ // "limitOrderStartTime": "0",
633
+ // "limitOrderEndTime": "0",
634
+ // "limitMinPrice": "0",
635
+ // "limitMaxPrice": "0",
636
+ // "filterType": "OPEN_QUOTE"
637
+ // }
638
+ // ]
639
+ // }
640
+ // ],
641
+ // "options": [],
642
+ // "contracts": [
643
+ // {
644
+ // "filters": [
645
+ // {
646
+ // "minPrice": "0.1",
647
+ // "maxPrice": "100000.00000000",
648
+ // "tickSize": "0.1",
649
+ // "filterType": "PRICE_FILTER"
650
+ // },
651
+ // {
652
+ // "minQty": "0.001",
653
+ // "maxQty": "10",
654
+ // "stepSize": "0.001",
655
+ // "marketOrderMinQty": "0",
656
+ // "marketOrderMaxQty": "0",
657
+ // "filterType": "LOT_SIZE"
658
+ // },
659
+ // {
660
+ // "minNotional": "0",
661
+ // "filterType": "MIN_NOTIONAL"
662
+ // },
663
+ // {
664
+ // "maxSellPrice": "999999",
665
+ // "buyPriceUpRate": "0.05",
666
+ // "sellPriceDownRate": "0.05",
667
+ // "maxEntrustNum": 200,
668
+ // "maxConditionNum": 200,
669
+ // "filterType": "LIMIT_TRADING"
670
+ // },
671
+ // {
672
+ // "buyPriceUpRate": "0.05",
673
+ // "sellPriceDownRate": "0.05",
674
+ // "filterType": "MARKET_TRADING"
675
+ // },
676
+ // {
677
+ // "noAllowMarketStartTime": "0",
678
+ // "noAllowMarketEndTime": "0",
679
+ // "limitOrderStartTime": "0",
680
+ // "limitOrderEndTime": "0",
681
+ // "limitMinPrice": "0",
682
+ // "limitMaxPrice": "0",
683
+ // "filterType": "OPEN_QUOTE"
684
+ // }
685
+ // ],
686
+ // "exchangeId": "301",
687
+ // "symbol": "BTCUSDT-PERPETUAL",
688
+ // "symbolName": "BTCUSDT-PERPETUAL",
689
+ // "status": "TRADING",
690
+ // "baseAsset": "BTCUSDT-PERPETUAL",
691
+ // "baseAssetPrecision": "0.001",
692
+ // "quoteAsset": "USDT",
693
+ // "quoteAssetPrecision": "0.1",
694
+ // "icebergAllowed": false,
695
+ // "inverse": false,
696
+ // "index": "USDT",
697
+ // "marginToken": "USDT",
698
+ // "marginPrecision": "0.0001",
699
+ // "contractMultiplier": "0.001",
700
+ // "underlying": "BTC",
701
+ // "riskLimits": [
702
+ // {
703
+ // "riskLimitId": "200000722",
704
+ // "quantity": "1000.00",
705
+ // "initialMargin": "0.10",
706
+ // "maintMargin": "0.005",
707
+ // "isWhite": false
708
+ // },
709
+ // {
710
+ // "riskLimitId": "200000723",
711
+ // "quantity": "2000.00",
712
+ // "initialMargin": "0.10",
713
+ // "maintMargin": "0.01",
714
+ // "isWhite": false
715
+ // }
716
+ // ]
717
+ // }
718
+ // ],
719
+ // "coins": [
720
+ // {
721
+ // "orgId": "9001",
722
+ // "coinId": "BTC",
723
+ // "coinName": "BTC",
724
+ // "coinFullName": "Bitcoin",
725
+ // "allowWithdraw": true,
726
+ // "allowDeposit": true,
727
+ // "tokenType": "CHAIN_TOKEN",
728
+ // "chainTypes": [
729
+ // {
730
+ // "chainType": "Bitcoin",
731
+ // "withdrawFee": "0",
732
+ // "minWithdrawQuantity": "0.002",
733
+ // "maxWithdrawQuantity": "0",
734
+ // "minDepositQuantity": "0.0005",
735
+ // "allowDeposit": true,
736
+ // "allowWithdraw": true
737
+ // }
738
+ // ]
739
+ // }
740
+ // ]
741
+ // }
742
+ //
743
+ const spotMarkets = this.safeList(response, 'symbols', []);
744
+ const swapMarkets = this.safeList(response, 'contracts', []);
745
+ let markets = this.arrayConcat(spotMarkets, swapMarkets);
746
+ if (this.isEmpty(markets)) {
747
+ markets = [response]; // if user provides params.symbol the exchange returns a single object insted of list of objects
748
+ }
749
+ return this.parseMarkets(markets);
750
+ }
751
+ parseMarket(market) {
752
+ // spot
753
+ // {
754
+ // "symbol": "BTCUSDT",
755
+ // "symbolName": "BTCUSDT",
756
+ // "status": "TRADING",
757
+ // "baseAsset": "BTC",
758
+ // "baseAssetName": "BTC",
759
+ // "baseAssetPrecision": "0.00001",
760
+ // "quoteAsset": "USDT",
761
+ // "quoteAssetName": "USDT",
762
+ // "quotePrecision": "0.0000001",
763
+ // "retailAllowed": true,
764
+ // "piAllowed": true,
765
+ // "corporateAllowed": true,
766
+ // "omnibusAllowed": true,
767
+ // "icebergAllowed": false,
768
+ // "isAggregate": false,
769
+ // "allowMargin": false,
770
+ // "filters": [
771
+ // {
772
+ // "minPrice": "0.01",
773
+ // "maxPrice": "100000.00000000",
774
+ // "tickSize": "0.01",
775
+ // "filterType": "PRICE_FILTER"
776
+ // },
777
+ // {
778
+ // "minQty": "0.00001",
779
+ // "maxQty": "8",
780
+ // "stepSize": "0.00001",
781
+ // "marketOrderMinQty": "0.00001",
782
+ // "marketOrderMaxQty": "4",
783
+ // "filterType": "LOT_SIZE"
784
+ // },
785
+ // {
786
+ // "minNotional": "1",
787
+ // "filterType": "MIN_NOTIONAL"
788
+ // },
789
+ // {
790
+ // "minAmount": "1",
791
+ // "maxAmount": "400000",
792
+ // "minBuyPrice": "0",
793
+ // "marketOrderMinAmount": "1",
794
+ // "marketOrderMaxAmount": "200000",
795
+ // "filterType": "TRADE_AMOUNT"
796
+ // },
797
+ // {
798
+ // "maxSellPrice": "0",
799
+ // "buyPriceUpRate": "0.1",
800
+ // "sellPriceDownRate": "0.1",
801
+ // "filterType": "LIMIT_TRADING"
802
+ // },
803
+ // {
804
+ // "buyPriceUpRate": "0.1",
805
+ // "sellPriceDownRate": "0.1",
806
+ // "filterType": "MARKET_TRADING"
807
+ // },
808
+ // {
809
+ // "noAllowMarketStartTime": "1710485700000",
810
+ // "noAllowMarketEndTime": "1710486000000",
811
+ // "limitOrderStartTime": "0",
812
+ // "limitOrderEndTime": "0",
813
+ // "limitMinPrice": "0",
814
+ // "limitMaxPrice": "0",
815
+ // "filterType": "OPEN_QUOTE"
816
+ // }
817
+ // ]
818
+ // }
819
+ //
820
+ // swap
821
+ // {
822
+ // "filters": [
823
+ // {
824
+ // "minPrice": "0.1",
825
+ // "maxPrice": "100000.00000000",
826
+ // "tickSize": "0.1",
827
+ // "filterType": "PRICE_FILTER"
828
+ // },
829
+ // {
830
+ // "minQty": "0.001",
831
+ // "maxQty": "10",
832
+ // "stepSize": "0.001",
833
+ // "marketOrderMinQty": "0",
834
+ // "marketOrderMaxQty": "0",
835
+ // "filterType": "LOT_SIZE"
836
+ // },
837
+ // {
838
+ // "minNotional": "0",
839
+ // "filterType": "MIN_NOTIONAL"
840
+ // },
841
+ // {
842
+ // "maxSellPrice": "999999",
843
+ // "buyPriceUpRate": "0.05",
844
+ // "sellPriceDownRate": "0.05",
845
+ // "maxEntrustNum": 200,
846
+ // "maxConditionNum": 200,
847
+ // "filterType": "LIMIT_TRADING"
848
+ // },
849
+ // {
850
+ // "buyPriceUpRate": "0.05",
851
+ // "sellPriceDownRate": "0.05",
852
+ // "filterType": "MARKET_TRADING"
853
+ // },
854
+ // {
855
+ // "noAllowMarketStartTime": "0",
856
+ // "noAllowMarketEndTime": "0",
857
+ // "limitOrderStartTime": "0",
858
+ // "limitOrderEndTime": "0",
859
+ // "limitMinPrice": "0",
860
+ // "limitMaxPrice": "0",
861
+ // "filterType": "OPEN_QUOTE"
862
+ // }
863
+ // ],
864
+ // "exchangeId": "301",
865
+ // "symbol": "BTCUSDT-PERPETUAL",
866
+ // "symbolName": "BTCUSDT-PERPETUAL",
867
+ // "status": "TRADING",
868
+ // "baseAsset": "BTCUSDT-PERPETUAL",
869
+ // "baseAssetPrecision": "0.001",
870
+ // "quoteAsset": "USDT",
871
+ // "quoteAssetPrecision": "0.1",
872
+ // "icebergAllowed": false,
873
+ // "inverse": false,
874
+ // "index": "USDT",
875
+ // "marginToken": "USDT",
876
+ // "marginPrecision": "0.0001",
877
+ // "contractMultiplier": "0.001",
878
+ // "underlying": "BTC",
879
+ // "riskLimits": [
880
+ // {
881
+ // "riskLimitId": "200000722",
882
+ // "quantity": "1000.00",
883
+ // "initialMargin": "0.10",
884
+ // "maintMargin": "0.005",
885
+ // "isWhite": false
886
+ // },
887
+ // {
888
+ // "riskLimitId": "200000723",
889
+ // "quantity": "2000.00",
890
+ // "initialMargin": "0.10",
891
+ // "maintMargin": "0.01",
892
+ // "isWhite": false
893
+ // }
894
+ // ]
895
+ // }
896
+ //
897
+ const marketId = this.safeString(market, 'symbol');
898
+ const quoteId = this.safeString(market, 'quoteAsset');
899
+ const quote = this.safeCurrencyCode(quoteId);
900
+ const settleId = this.safeString(market, 'marginToken');
901
+ const settle = this.safeCurrencyCode(settleId);
902
+ let baseId = this.safeString(market, 'baseAsset');
903
+ let marketType = 'spot';
904
+ let isSpot = true;
905
+ let isSwap = false;
906
+ let suffix = '';
907
+ const parts = marketId.split('-');
908
+ const secondPart = this.safeString(parts, 1);
909
+ if (secondPart === 'PERPETUAL') {
910
+ marketType = 'swap';
911
+ isSpot = false;
912
+ isSwap = true;
913
+ baseId = this.safeString(market, 'underlying');
914
+ suffix += ':' + settleId;
915
+ }
916
+ const base = this.safeCurrencyCode(baseId);
917
+ const symbol = base + '/' + quote + suffix;
918
+ const status = this.safeString(market, 'status');
919
+ const active = status === 'TRADING';
920
+ let isLinear = undefined;
921
+ let subType = undefined;
922
+ const isInverse = this.safeBool(market, 'inverse');
923
+ if (isInverse !== undefined) {
924
+ if (isInverse) {
925
+ isLinear = false;
926
+ subType = 'inverse';
927
+ }
928
+ else {
929
+ isLinear = true;
930
+ subType = 'linear';
931
+ }
932
+ }
933
+ const filtersList = this.safeList(market, 'filters', []);
934
+ const filters = this.indexBy(filtersList, 'filterType');
935
+ const priceFilter = this.safeDict(filters, 'PRICE_FILTER', {});
936
+ const amountFilter = this.safeDict(filters, 'LOT_SIZE', {});
937
+ const costFilter = this.safeDict(filters, 'MIN_NOTIONAL', {});
938
+ const minCostString = this.omitZero(this.safeString(costFilter, 'min_notional'));
939
+ const contractSizeString = this.safeString(market, 'contractMultiplier');
940
+ let amountPrecisionString = this.safeString(amountFilter, 'stepSize');
941
+ let amountMinLimitString = this.safeString(amountFilter, 'minQty');
942
+ let amountMaxLimitString = this.safeString(amountFilter, 'maxQty');
943
+ let minLeverage = undefined;
944
+ let maxLeverage = undefined;
945
+ if (isSwap) {
946
+ amountPrecisionString = Precise.stringDiv(amountPrecisionString, contractSizeString);
947
+ amountMinLimitString = Precise.stringDiv(amountMinLimitString, contractSizeString);
948
+ amountMaxLimitString = Precise.stringDiv(amountMaxLimitString, contractSizeString);
949
+ const riskLimits = this.safeList(market, 'riskLimits');
950
+ if (riskLimits !== undefined) {
951
+ const first = this.safeDict(riskLimits, 0);
952
+ const arrayLength = riskLimits.length;
953
+ const last = this.safeDict(riskLimits, arrayLength - 1);
954
+ let minInitialMargin = this.safeString(first, 'initialMargin');
955
+ let maxInitialMargin = this.safeString(last, 'initialMargin');
956
+ if (Precise.stringGt(minInitialMargin, maxInitialMargin)) {
957
+ [minInitialMargin, maxInitialMargin] = [maxInitialMargin, minInitialMargin];
958
+ }
959
+ minLeverage = this.parseToInt(Precise.stringDiv('1', maxInitialMargin));
960
+ maxLeverage = this.parseToInt(Precise.stringDiv('1', minInitialMargin));
961
+ }
962
+ }
963
+ const tradingFees = this.safeDict(this.fees, 'trading');
964
+ const fees = isSpot ? this.safeDict(tradingFees, 'spot') : this.safeDict(tradingFees, 'swap');
965
+ return this.safeMarketStructure({
966
+ 'id': marketId,
967
+ 'symbol': symbol,
968
+ 'base': base,
969
+ 'quote': quote,
970
+ 'baseId': baseId,
971
+ 'quoteId': quoteId,
972
+ 'active': active,
973
+ 'type': marketType,
974
+ 'subType': subType,
975
+ 'spot': isSpot,
976
+ 'margin': this.safeBool(market, 'allowMargin'),
977
+ 'swap': isSwap,
978
+ 'future': false,
979
+ 'option': false,
980
+ 'contract': isSwap,
981
+ 'settle': settle,
982
+ 'settleId': settleId,
983
+ 'contractSize': this.parseNumber(contractSizeString),
984
+ 'linear': isLinear,
985
+ 'inverse': isInverse,
986
+ 'taker': this.safeNumber(fees, 'taker'),
987
+ 'maker': this.safeNumber(fees, 'maker'),
988
+ 'percentage': this.safeBool(fees, 'percentage'),
989
+ 'tierBased': this.safeBool(fees, 'tierBased'),
990
+ 'feeSide': this.safeString(fees, 'feeSide'),
991
+ 'expiry': undefined,
992
+ 'expiryDatetime': undefined,
993
+ 'strike': undefined,
994
+ 'optionType': undefined,
995
+ 'precision': {
996
+ 'amount': this.parseNumber(amountPrecisionString),
997
+ 'price': this.safeNumber(priceFilter, 'tickSize'),
998
+ },
999
+ 'limits': {
1000
+ 'amount': {
1001
+ 'min': this.parseNumber(amountMinLimitString),
1002
+ 'max': this.parseNumber(amountMaxLimitString),
1003
+ },
1004
+ 'price': {
1005
+ 'min': this.safeNumber(priceFilter, 'minPrice'),
1006
+ 'max': this.safeNumber(priceFilter, 'maxPrice'),
1007
+ },
1008
+ 'leverage': {
1009
+ 'min': minLeverage,
1010
+ 'max': maxLeverage,
1011
+ },
1012
+ 'cost': {
1013
+ 'min': this.parseNumber(minCostString),
1014
+ 'max': undefined,
1015
+ },
1016
+ },
1017
+ 'created': undefined,
1018
+ 'info': market,
1019
+ });
1020
+ }
1021
+ async fetchCurrencies(params = {}) {
1022
+ /**
1023
+ * @method
1024
+ * @name hashkey#fetchCurrencies
1025
+ * @description fetches all available currencies on an exchange
1026
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/exchangeinfo
1027
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1028
+ * @returns {object} an associative dictionary of currencies
1029
+ */
1030
+ const response = await this.publicGetApiV1ExchangeInfo(params);
1031
+ const coins = this.safeList(response, 'coins');
1032
+ //
1033
+ // {
1034
+ // ...
1035
+ // "coins": [
1036
+ // {
1037
+ // "orgId": "9001",
1038
+ // "coinId": "BTC",
1039
+ // "coinName": "BTC",
1040
+ // "coinFullName": "Bitcoin",
1041
+ // "allowWithdraw": true,
1042
+ // "allowDeposit": true,
1043
+ // "tokenType": "CHAIN_TOKEN",
1044
+ // "chainTypes": [
1045
+ // {
1046
+ // "chainType": "Bitcoin",
1047
+ // "withdrawFee": "0",
1048
+ // "minWithdrawQuantity": "0.002",
1049
+ // "maxWithdrawQuantity": "0",
1050
+ // "minDepositQuantity": "0.0005",
1051
+ // "allowDeposit": true,
1052
+ // "allowWithdraw": true
1053
+ // }
1054
+ // ]
1055
+ // }
1056
+ // ]
1057
+ // }
1058
+ //
1059
+ const result = {};
1060
+ for (let i = 0; i < coins.length; i++) {
1061
+ const currecy = coins[i];
1062
+ const currencyId = this.safeString(currecy, 'coinId');
1063
+ const code = this.safeCurrencyCode(currencyId);
1064
+ const allowWithdraw = this.safeBool(currecy, 'allowWithdraw');
1065
+ const allowDeposit = this.safeBool(currecy, 'allowDeposit');
1066
+ const networks = this.safeList(currecy, 'chainTypes');
1067
+ const networksById = this.safeDict(this.options, 'networksById');
1068
+ const parsedNetworks = {};
1069
+ for (let j = 0; j < networks.length; j++) {
1070
+ const network = networks[j];
1071
+ const networkId = this.safeString(network, 'chainType');
1072
+ const networkName = this.safeString(networksById, networkId, networkId);
1073
+ const maxWithdrawQuantity = this.omitZero(this.safeString(network, 'maxWithdrawQuantity'));
1074
+ const networkDeposit = this.safeBool(network, 'allowDeposit');
1075
+ const networkWithdraw = this.safeBool(network, 'allowWithdraw');
1076
+ parsedNetworks[networkName] = {
1077
+ 'id': networkId,
1078
+ 'network': networkName,
1079
+ 'limits': {
1080
+ 'withdraw': {
1081
+ 'min': this.safeNumber(network, 'minWithdrawQuantity'),
1082
+ 'max': this.parseNumber(maxWithdrawQuantity),
1083
+ },
1084
+ 'deposit': {
1085
+ 'min': this.safeNumber(network, 'minDepositQuantity'),
1086
+ 'max': undefined,
1087
+ },
1088
+ },
1089
+ 'active': networkDeposit && networkWithdraw,
1090
+ 'deposit': networkDeposit,
1091
+ 'withdraw': networkWithdraw,
1092
+ 'fee': this.safeNumber(network, 'withdrawFee'),
1093
+ 'precision': undefined,
1094
+ 'info': network,
1095
+ };
1096
+ }
1097
+ result[code] = {
1098
+ 'id': currencyId,
1099
+ 'code': code,
1100
+ 'precision': undefined,
1101
+ 'type': this.parseCurrencyType(this.safeString(currecy, 'tokenType')),
1102
+ 'name': this.safeString(currecy, 'coinFullName'),
1103
+ 'active': allowWithdraw && allowDeposit,
1104
+ 'deposit': allowDeposit,
1105
+ 'withdraw': allowWithdraw,
1106
+ 'fee': undefined,
1107
+ 'limits': {
1108
+ 'deposit': {
1109
+ 'min': undefined,
1110
+ 'max': undefined,
1111
+ },
1112
+ 'withdraw': {
1113
+ 'min': undefined,
1114
+ 'max': undefined,
1115
+ },
1116
+ },
1117
+ 'networks': parsedNetworks,
1118
+ 'info': currecy,
1119
+ };
1120
+ }
1121
+ return result;
1122
+ }
1123
+ parseCurrencyType(type) {
1124
+ const types = {
1125
+ 'CHAIN_TOKEN': 'crypto',
1126
+ 'ERC20_TOKEN': 'crypto',
1127
+ 'BSC_TOKEN': 'crypto',
1128
+ 'REAL_MONEY': 'fiat',
1129
+ };
1130
+ return this.safeString(types, type);
1131
+ }
1132
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
1133
+ /**
1134
+ * @method
1135
+ * @name hashkey#fetchOrderBook
1136
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
1137
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-order-book
1138
+ * @param {string} symbol unified symbol of the market to fetch the order book for
1139
+ * @param {int} [limit] the maximum amount of order book entries to return (maximum value is 200)
1140
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1141
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
1142
+ */
1143
+ await this.loadMarkets();
1144
+ const market = this.market(symbol);
1145
+ const request = {
1146
+ 'symbol': market['id'],
1147
+ };
1148
+ if (limit !== undefined) {
1149
+ request['limit'] = limit;
1150
+ }
1151
+ const response = await this.publicGetQuoteV1Depth(this.extend(request, params));
1152
+ //
1153
+ // {
1154
+ // "t": 1721681436393,
1155
+ // "b": [
1156
+ // ["67902.49", "0.00112"],
1157
+ // ["67901.08", "0.01014"]
1158
+ // ...
1159
+ // ],
1160
+ // "a": [
1161
+ // ["67905.99", "0.87134"],
1162
+ // ["67906", "0.57361"]
1163
+ // ...
1164
+ // ]
1165
+ // }
1166
+ //
1167
+ const timestamp = this.safeInteger(response, 't');
1168
+ return this.parseOrderBook(response, symbol, timestamp, 'b', 'a');
1169
+ }
1170
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
1171
+ /**
1172
+ * @method
1173
+ * @name hashkey#fetchTrades
1174
+ * @description get the list of most recent trades for a particular symbol
1175
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-recent-trade-list
1176
+ * @param {string} symbol unified symbol of the market to fetch trades for
1177
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
1178
+ * @param {int} [limit] the maximum amount of trades to fetch (maximum value is 100)
1179
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1180
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
1181
+ */
1182
+ await this.loadMarkets();
1183
+ const market = this.market(symbol);
1184
+ const request = {
1185
+ 'symbol': market['id'],
1186
+ };
1187
+ if (limit !== undefined) {
1188
+ request['limit'] = limit;
1189
+ }
1190
+ const response = await this.publicGetQuoteV1Trades(this.extend(request, params));
1191
+ //
1192
+ // [
1193
+ // {
1194
+ // "t": 1721682745779,
1195
+ // "p": "67835.99",
1196
+ // "q": "0.00017",
1197
+ // "ibm": true
1198
+ // },
1199
+ // ...
1200
+ // ]
1201
+ //
1202
+ return this.parseTrades(response, market, since, limit);
1203
+ }
1204
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1205
+ /**
1206
+ * @method
1207
+ * @name hashkey#fetchMyTrades
1208
+ * @description fetch all trades made by the user
1209
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-account-trade-list
1210
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/query-futures-trades
1211
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-user
1212
+ * @param {string} symbol *is mandatory for swap markets* unified market symbol
1213
+ * @param {int} [since] the earliest time in ms to fetch trades for
1214
+ * @param {int} [limit] the maximum amount of trades to fetch (default 200, max 500)
1215
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1216
+ * @param {string} [params.type] 'spot' or 'swap' - the type of the market to fetch trades for (default 'spot')
1217
+ * @param {int} [params.until] the latest time in ms to fetch trades for, only supports the last 30 days timeframe
1218
+ * @param {string} [params.fromId] srarting trade id
1219
+ * @param {string} [params.toId] ending trade id
1220
+ * @param {string} [params.clientOrderId] *spot markets only* filter trades by orderId
1221
+ * @param {string} [params.accountId] account id to fetch the orders from
1222
+ * @returns {Trade[]} a list of [trade structures]{@link https://github.com/ccxt/ccxt/wiki/Manual#trade-structure}
1223
+ */
1224
+ const methodName = 'fetchMyTrades';
1225
+ await this.loadMarkets();
1226
+ const request = {};
1227
+ let market = undefined;
1228
+ if (symbol !== undefined) {
1229
+ market = this.market(symbol);
1230
+ }
1231
+ let marketType = 'spot';
1232
+ [marketType, params] = this.handleMarketTypeAndParams(methodName, market, params);
1233
+ if (since !== undefined) {
1234
+ request['startTime'] = since;
1235
+ }
1236
+ if (limit !== undefined) {
1237
+ request['limit'] = limit;
1238
+ }
1239
+ let until = undefined;
1240
+ [until, params] = this.handleOptionAndParams(params, methodName, 'until');
1241
+ if (until !== undefined) {
1242
+ request['endTime'] = until;
1243
+ }
1244
+ let accountId = undefined;
1245
+ [accountId, params] = this.handleOptionAndParams(params, methodName, 'accountId');
1246
+ let response = undefined;
1247
+ if (marketType === 'spot') {
1248
+ if (market !== undefined) {
1249
+ request['symbol'] = market['id'];
1250
+ }
1251
+ let clientOrderId = undefined;
1252
+ [clientOrderId, params] = this.handleOptionAndParams(params, methodName, 'clientOrderId');
1253
+ if (clientOrderId !== undefined) {
1254
+ request['clientOrderId'] = clientOrderId;
1255
+ }
1256
+ if (accountId !== undefined) {
1257
+ request['accountId'] = accountId;
1258
+ }
1259
+ response = await this.privateGetApiV1AccountTrades(this.extend(request, params));
1260
+ //
1261
+ // [
1262
+ // {
1263
+ // "id": "1739352552862964736",
1264
+ // "clientOrderId": "1722082982086472",
1265
+ // "ticketId": "1739352552795029504",
1266
+ // "symbol": "ETHUSDT",
1267
+ // "symbolName": "ETHUSDT",
1268
+ // "orderId": "1739352552762301440",
1269
+ // "matchOrderId": "0",
1270
+ // "price": "3289.96",
1271
+ // "qty": "0.001",
1272
+ // "commission": "0.0000012",
1273
+ // "commissionAsset": "ETH",
1274
+ // "time": "1722082982097",
1275
+ // "isBuyer": true,
1276
+ // "isMaker": false,
1277
+ // "fee": {
1278
+ // "feeCoinId": "ETH",
1279
+ // "feeCoinName": "ETH",
1280
+ // "fee": "0.0000012"
1281
+ // },
1282
+ // "feeCoinId": "ETH",
1283
+ // "feeAmount": "0.0000012",
1284
+ // "makerRebate": "0"
1285
+ // },
1286
+ // ...
1287
+ // ]
1288
+ //
1289
+ }
1290
+ else if (marketType === 'swap') {
1291
+ if (symbol === undefined) {
1292
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a symbol argument for swap markets');
1293
+ }
1294
+ request['symbol'] = market['id'];
1295
+ if (accountId !== undefined) {
1296
+ request['subAccountId'] = accountId;
1297
+ response = await this.privateGetApiV1FuturesSubAccountUserTrades(this.extend(request, params));
1298
+ }
1299
+ else {
1300
+ response = await this.privateGetApiV1FuturesUserTrades(this.extend(request, params));
1301
+ //
1302
+ // [
1303
+ // {
1304
+ // "time": "1722429951648",
1305
+ // "tradeId": "1742263144691139328",
1306
+ // "orderId": "1742263144028363776",
1307
+ // "symbol": "ETHUSDT-PERPETUAL",
1308
+ // "price": "3327.54",
1309
+ // "quantity": "4",
1310
+ // "commissionAsset": "USDT",
1311
+ // "commission": "0.00798609",
1312
+ // "makerRebate": "0",
1313
+ // "type": "LIMIT",
1314
+ // "side": "BUY_OPEN",
1315
+ // "realizedPnl": "0",
1316
+ // "isMarker": false
1317
+ // }
1318
+ // ]
1319
+ //
1320
+ }
1321
+ }
1322
+ else {
1323
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets');
1324
+ }
1325
+ return this.parseTrades(response, market, since, limit);
1326
+ }
1327
+ parseTrade(trade, market = undefined) {
1328
+ //
1329
+ // fetchTrades
1330
+ //
1331
+ // {
1332
+ // "t": 1721682745779,
1333
+ // "p": "67835.99",
1334
+ // "q": "0.00017",
1335
+ // "ibm": true
1336
+ // }
1337
+ //
1338
+ // fetchMyTrades spot
1339
+ //
1340
+ // {
1341
+ // "id": "1739352552862964736",
1342
+ // "clientOrderId": "1722082982086472",
1343
+ // "ticketId": "1739352552795029504",
1344
+ // "symbol": "ETHUSDT",
1345
+ // "symbolName": "ETHUSDT",
1346
+ // "orderId": "1739352552762301440",
1347
+ // "matchOrderId": "0",
1348
+ // "price": "3289.96",
1349
+ // "qty": "0.001",
1350
+ // "commission": "0.0000012",
1351
+ // "commissionAsset": "ETH",
1352
+ // "time": "1722082982097",
1353
+ // "isBuyer": true,
1354
+ // "isMaker": false,
1355
+ // "fee": {
1356
+ // "feeCoinId": "ETH",
1357
+ // "feeCoinName": "ETH",
1358
+ // "fee": "0.0000012"
1359
+ // },
1360
+ // "feeCoinId": "ETH",
1361
+ // "feeAmount": "0.0000012",
1362
+ // "makerRebate": "0"
1363
+ // }
1364
+ //
1365
+ // fetchMyTrades swap
1366
+ // {
1367
+ // "time": "1722429951648",
1368
+ // "tradeId": "1742263144691139328",
1369
+ // "orderId": "1742263144028363776",
1370
+ // "symbol": "ETHUSDT-PERPETUAL",
1371
+ // "price": "3327.54",
1372
+ // "quantity": "4",
1373
+ // "commissionAsset": "USDT",
1374
+ // "commission": "0.00798609",
1375
+ // "makerRebate": "0",
1376
+ // "type": "LIMIT",
1377
+ // "side": "BUY_OPEN",
1378
+ // "realizedPnl": "0",
1379
+ // "isMarker": false
1380
+ // }
1381
+ const timestamp = this.safeInteger2(trade, 't', 'time');
1382
+ const marketId = this.safeString(trade, 'symbol');
1383
+ market = this.safeMarket(marketId, market);
1384
+ let side = this.safeStringLower(trade, 'side'); // swap trades have side param
1385
+ if (side !== undefined) {
1386
+ side = this.safeString(side.split('_'), 0);
1387
+ }
1388
+ const isBuyer = this.safeBool(trade, 'isBuyer');
1389
+ if (isBuyer !== undefined) {
1390
+ side = isBuyer ? 'buy' : 'sell';
1391
+ }
1392
+ let takerOrMaker = undefined;
1393
+ const isMaker = this.safeBoolN(trade, ['isMaker', 'isMarker', 'ibm']);
1394
+ if (isMaker !== undefined) {
1395
+ takerOrMaker = isMaker ? 'maker' : 'taker';
1396
+ }
1397
+ let feeCost = this.safeString(trade, 'commission');
1398
+ let feeCurrncyId = this.safeString(trade, 'commissionAsset');
1399
+ const feeInfo = this.safeDict(trade, 'fee');
1400
+ let fee = undefined;
1401
+ if (feeInfo !== undefined) {
1402
+ feeCost = this.safeString(feeInfo, 'fee');
1403
+ feeCurrncyId = this.safeString(feeInfo, 'feeCoinId');
1404
+ }
1405
+ if (feeCost !== undefined) {
1406
+ fee = {
1407
+ 'cost': this.parseNumber(feeCost),
1408
+ 'currency': this.safeCurrencyCode(feeCurrncyId),
1409
+ };
1410
+ }
1411
+ return this.safeTrade({
1412
+ 'id': this.safeString2(trade, 'id', 'tradeId'),
1413
+ 'timestamp': timestamp,
1414
+ 'datetime': this.iso8601(timestamp),
1415
+ 'symbol': market['symbol'],
1416
+ 'side': side,
1417
+ 'price': this.safeString2(trade, 'p', 'price'),
1418
+ 'amount': this.safeStringN(trade, ['q', 'qty', 'quantity']),
1419
+ 'cost': undefined,
1420
+ 'takerOrMaker': takerOrMaker,
1421
+ 'type': undefined,
1422
+ 'order': this.safeString(trade, 'orderId'),
1423
+ 'fee': fee,
1424
+ 'info': trade,
1425
+ }, market);
1426
+ }
1427
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
1428
+ /**
1429
+ * @method
1430
+ * @name hashkey#fetchOHLCV
1431
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-kline
1432
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1433
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
1434
+ * @param {string} timeframe the length of time each candle represents
1435
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
1436
+ * @param {int} [limit] the maximum amount of candles to fetch
1437
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1438
+ * @param {int} [params.until] timestamp in ms of the latest candle to fetch
1439
+ * @param {boolean} [params.paginate] default false, when true will automatically paginate by calling this endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1440
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
1441
+ */
1442
+ const methodName = 'fetchOHLCV';
1443
+ await this.loadMarkets();
1444
+ let paginate = false;
1445
+ [paginate, params] = this.handleOptionAndParams(params, methodName, 'paginate');
1446
+ if (paginate) {
1447
+ return await this.fetchPaginatedCallDeterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000);
1448
+ }
1449
+ const market = this.market(symbol);
1450
+ timeframe = this.safeString(this.timeframes, timeframe, timeframe);
1451
+ const request = {
1452
+ 'symbol': market['id'],
1453
+ 'interval': timeframe,
1454
+ };
1455
+ if (since !== undefined) {
1456
+ request['startTime'] = since;
1457
+ }
1458
+ if (limit !== undefined) {
1459
+ request['limit'] = limit;
1460
+ }
1461
+ let until = undefined;
1462
+ [until, params] = this.handleOptionAndParams(params, methodName, 'until');
1463
+ if (until !== undefined) {
1464
+ request['endTime'] = until;
1465
+ }
1466
+ const response = await this.publicGetQuoteV1Klines(this.extend(request, params));
1467
+ //
1468
+ // [
1469
+ // [
1470
+ // 1721684280000,
1471
+ // "67832.49",
1472
+ // "67862.5",
1473
+ // "67832.49",
1474
+ // "67861.44",
1475
+ // "0.01122",0,
1476
+ // "761.2763533",68,
1477
+ // "0.00561",
1478
+ // "380.640643"
1479
+ // ],
1480
+ // ...
1481
+ // ]
1482
+ //
1483
+ return this.parseOHLCVs(response, market, timeframe, since, limit);
1484
+ }
1485
+ parseOHLCV(ohlcv, market = undefined) {
1486
+ //
1487
+ // [
1488
+ // 1721684280000,
1489
+ // "67832.49",
1490
+ // "67862.5",
1491
+ // "67832.49",
1492
+ // "67861.44",
1493
+ // "0.01122",0,
1494
+ // "761.2763533",68,
1495
+ // "0.00561",
1496
+ // "380.640643"
1497
+ // ]
1498
+ //
1499
+ return [
1500
+ this.safeInteger(ohlcv, 0),
1501
+ this.safeNumber(ohlcv, 1),
1502
+ this.safeNumber(ohlcv, 2),
1503
+ this.safeNumber(ohlcv, 3),
1504
+ this.safeNumber(ohlcv, 4),
1505
+ this.safeNumber(ohlcv, 5),
1506
+ ];
1507
+ }
1508
+ async fetchTicker(symbol, params = {}) {
1509
+ /**
1510
+ * @method
1511
+ * @name hashkey#fetchTicker
1512
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1513
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-24hr-ticker-price-change
1514
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
1515
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1516
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1517
+ */
1518
+ await this.loadMarkets();
1519
+ const market = this.market(symbol);
1520
+ const request = {
1521
+ 'symbol': market['id'],
1522
+ };
1523
+ const response = await this.publicGetQuoteV1Ticker24hr(this.extend(request, params));
1524
+ //
1525
+ // [
1526
+ // {
1527
+ // "t": 1721685896846,
1528
+ // "s": "BTCUSDT-PERPETUAL",
1529
+ // "c": "67756.7",
1530
+ // "h": "68479.9",
1531
+ // "l": "66594.3",
1532
+ // "o": "68279.7",
1533
+ // "b": "67756.6",
1534
+ // "a": "67756.7",
1535
+ // "v": "1604722",
1536
+ // "qv": "108827258.7761"
1537
+ // }
1538
+ // ]
1539
+ //
1540
+ const ticker = this.safeDict(response, 0, {});
1541
+ return this.parseTicker(ticker, market);
1542
+ }
1543
+ async fetchTickers(symbols = undefined, params = {}) {
1544
+ /**
1545
+ * @method
1546
+ * @name hashkey#fetchTickers
1547
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1548
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-24hr-ticker-price-change
1549
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1550
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1551
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1552
+ */
1553
+ await this.loadMarkets();
1554
+ symbols = this.marketSymbols(symbols);
1555
+ const response = await this.publicGetQuoteV1Ticker24hr(params);
1556
+ return this.parseTickers(response, symbols);
1557
+ }
1558
+ parseTicker(ticker, market = undefined) {
1559
+ //
1560
+ // {
1561
+ // "t": 1721685896846,
1562
+ // "s": "BTCUSDT-PERPETUAL",
1563
+ // "c": "67756.7",
1564
+ // "h": "68479.9",
1565
+ // "l": "66594.3",
1566
+ // "o": "68279.7",
1567
+ // "b": "67756.6",
1568
+ // "a": "67756.7",
1569
+ // "v": "1604722",
1570
+ // "qv": "108827258.7761"
1571
+ // }
1572
+ //
1573
+ const timestamp = this.safeInteger(ticker, 't');
1574
+ const marketId = this.safeString(ticker, 's');
1575
+ market = this.safeMarket(marketId, market);
1576
+ const symbol = market['symbol'];
1577
+ const last = this.safeString(ticker, 'c');
1578
+ return this.safeTicker({
1579
+ 'symbol': symbol,
1580
+ 'timestamp': timestamp,
1581
+ 'datetime': this.iso8601(timestamp),
1582
+ 'high': this.safeString(ticker, 'h'),
1583
+ 'low': this.safeString(ticker, 'l'),
1584
+ 'bid': this.safeString(ticker, 'b'),
1585
+ 'bidVolume': undefined,
1586
+ 'ask': this.safeString(ticker, 'a'),
1587
+ 'askVolume': undefined,
1588
+ 'vwap': undefined,
1589
+ 'open': this.safeString(ticker, 'o'),
1590
+ 'close': last,
1591
+ 'last': last,
1592
+ 'previousClose': undefined,
1593
+ 'change': undefined,
1594
+ 'percentage': undefined,
1595
+ 'average': undefined,
1596
+ 'baseVolume': this.safeString(ticker, 'v'),
1597
+ 'quoteVolume': this.safeString(ticker, 'qv'),
1598
+ 'info': ticker,
1599
+ }, market);
1600
+ }
1601
+ async fetchLastPrices(symbols = undefined, params = {}) {
1602
+ /**
1603
+ * @method
1604
+ * @name hashkey#fetchLastPrices
1605
+ * @description fetches the last price for multiple markets
1606
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-symbol-price-ticker
1607
+ * @param {string[]} [symbols] unified symbols of the markets to fetch the last prices
1608
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1609
+ * @param {string} [params.symbol] the id of the market to fetch last price for
1610
+ * @returns {object} a dictionary of lastprices structures
1611
+ */
1612
+ await this.loadMarkets();
1613
+ symbols = this.marketSymbols(symbols);
1614
+ const request = {};
1615
+ let symbol = undefined;
1616
+ [symbol, params] = this.handleOptionAndParams(params, 'fetchLastPrices', 'symbol');
1617
+ if (symbol !== undefined) {
1618
+ request['symbol'] = symbol;
1619
+ }
1620
+ const response = await this.publicGetQuoteV1TickerPrice(this.extend(request, params));
1621
+ //
1622
+ // [
1623
+ // {
1624
+ // "s": "BTCUSDT-PERPETUAL",
1625
+ // "p": "64871"
1626
+ // },
1627
+ // ...
1628
+ // ]
1629
+ //
1630
+ return this.parseLastPrices(response, symbols);
1631
+ }
1632
+ parseLastPrice(entry, market = undefined) {
1633
+ const marketId = this.safeString(entry, 's');
1634
+ market = this.safeMarket(marketId, market);
1635
+ return {
1636
+ 'symbol': market['symbol'],
1637
+ 'timestamp': undefined,
1638
+ 'datetime': undefined,
1639
+ 'price': this.safeNumber(entry, 'p'),
1640
+ 'side': undefined,
1641
+ 'info': entry,
1642
+ };
1643
+ }
1644
+ async fetchBalance(params = {}) {
1645
+ /**
1646
+ * @method
1647
+ * @name hashkey#fetchBalance
1648
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1649
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-account-information
1650
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1651
+ * @param {string} [params.accountId] account ID, for Master Key only
1652
+ * @param {string} [params.type] 'spot' or 'swap' - the type of the market to fetch balance for (default 'spot')
1653
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1654
+ */
1655
+ await this.loadMarkets();
1656
+ const request = {};
1657
+ const methodName = 'fetchBalance';
1658
+ let marketType = 'spot';
1659
+ [marketType, params] = this.handleMarketTypeAndParams(methodName, undefined, params, marketType);
1660
+ if (marketType === 'swap') {
1661
+ const response = await this.privateGetApiV1FuturesBalance(params);
1662
+ //
1663
+ // [
1664
+ // {
1665
+ // "balance": "30.63364672",
1666
+ // "availableBalance": "28.85635534",
1667
+ // "positionMargin": "4.3421",
1668
+ // "orderMargin": "0",
1669
+ // "asset": "USDT",
1670
+ // "crossUnRealizedPnl": "2.5649"
1671
+ // }
1672
+ // ]
1673
+ //
1674
+ const balance = this.safeDict(response, 0, {});
1675
+ return this.parseSwapBalance(balance);
1676
+ }
1677
+ else if (marketType === 'spot') {
1678
+ let accountId = undefined;
1679
+ [accountId, params] = this.handleOptionAndParams(params, methodName, 'accountId');
1680
+ if (accountId !== undefined) {
1681
+ request['accountId'] = accountId;
1682
+ }
1683
+ const response = await this.privateGetApiV1Account(this.extend(request, params));
1684
+ //
1685
+ // {
1686
+ // "balances": [
1687
+ // {
1688
+ // "asset":"USDT",
1689
+ // "assetId":"USDT",
1690
+ // "assetName":"USDT",
1691
+ // "total":"40",
1692
+ // "free":"40",
1693
+ // "locked":"0"
1694
+ // },
1695
+ // ...
1696
+ // ],
1697
+ // "userId": "1732885739572845312"
1698
+ // }
1699
+ //
1700
+ return this.parseBalance(response);
1701
+ }
1702
+ else {
1703
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets');
1704
+ }
1705
+ }
1706
+ parseBalance(balance) {
1707
+ //
1708
+ // {
1709
+ // "balances": [
1710
+ // {
1711
+ // "asset":"USDT",
1712
+ // "assetId":"USDT",
1713
+ // "assetName":"USDT",
1714
+ // "total":"40",
1715
+ // "free":"40",
1716
+ // "locked":"0"
1717
+ // },
1718
+ // ...
1719
+ // ],
1720
+ // "userId": "1732885739572845312"
1721
+ // }
1722
+ //
1723
+ const result = {
1724
+ 'info': balance,
1725
+ };
1726
+ const balances = this.safeList(balance, 'balances', []);
1727
+ for (let i = 0; i < balances.length; i++) {
1728
+ const balanceEntry = balances[i];
1729
+ const currencyId = this.safeString(balanceEntry, 'asset');
1730
+ const code = this.safeCurrencyCode(currencyId);
1731
+ const account = this.account();
1732
+ account['total'] = this.safeString(balanceEntry, 'total');
1733
+ account['free'] = this.safeString(balanceEntry, 'free');
1734
+ account['used'] = this.safeString(balanceEntry, 'locked');
1735
+ result[code] = account;
1736
+ }
1737
+ return this.safeBalance(result);
1738
+ }
1739
+ parseSwapBalance(balance) {
1740
+ //
1741
+ // {
1742
+ // "balance": "30.63364672",
1743
+ // "availableBalance": "28.85635534",
1744
+ // "positionMargin": "4.3421",
1745
+ // "orderMargin": "0",
1746
+ // "asset": "USDT",
1747
+ // "crossUnRealizedPnl": "2.5649"
1748
+ // }
1749
+ //
1750
+ const currencyId = this.safeString(balance, 'asset');
1751
+ const code = this.safeCurrencyCode(currencyId);
1752
+ const account = this.account();
1753
+ account['total'] = this.safeString(balance, 'balance');
1754
+ const positionMargin = this.safeString(balance, 'positionMargin');
1755
+ const orderMargin = this.safeString(balance, 'orderMargin');
1756
+ account['used'] = Precise.stringAdd(positionMargin, orderMargin);
1757
+ const result = {
1758
+ 'info': balance,
1759
+ };
1760
+ result[code] = account;
1761
+ return this.safeBalance(result);
1762
+ }
1763
+ async fetchDepositAddress(code, params = {}) {
1764
+ /**
1765
+ * @method
1766
+ * @name hashkey#fetchDepositAddress
1767
+ * @description fetch the deposit address for a currency associated with this account
1768
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-deposit-address
1769
+ * @param {string} code unified currency code (default is 'USDT')
1770
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1771
+ * @param {string} [params.network] network for fetch deposit address (default is 'ETH')
1772
+ * @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
1773
+ */
1774
+ await this.loadMarkets();
1775
+ const currency = this.currency(code);
1776
+ const request = {
1777
+ 'coin': currency['id'],
1778
+ };
1779
+ let networkCode = undefined;
1780
+ [networkCode, params] = this.handleNetworkCodeAndParams(params);
1781
+ if (networkCode === undefined) {
1782
+ networkCode = this.defaultNetworkCode(code);
1783
+ }
1784
+ request['chainType'] = this.networkCodeToId(networkCode, code);
1785
+ const response = await this.privateGetApiV1AccountDepositAddress(this.extend(request, params));
1786
+ //
1787
+ // {
1788
+ // "canDeposit": true,
1789
+ // "address": "0x61AAd7F763e2C7fF1CC996918740F67f9dC8BF4e",
1790
+ // "addressExt": "",
1791
+ // "minQuantity": "1",
1792
+ // "needAddressTag": false,
1793
+ // "requiredConfirmTimes": 64,
1794
+ // "canWithdrawConfirmTimes": 64,
1795
+ // "coinType": "ERC20_TOKEN"
1796
+ // }
1797
+ //
1798
+ const depositAddress = this.parseDepositAddress(response, currency);
1799
+ depositAddress['network'] = networkCode;
1800
+ return depositAddress;
1801
+ }
1802
+ parseDepositAddress(depositAddress, currency = undefined) {
1803
+ //
1804
+ // {
1805
+ // "canDeposit": true,
1806
+ // "address": "0x61AAd7F763e2C7fF1CC996918740F67f9dC8BF4e",
1807
+ // "addressExt": "",
1808
+ // "minQuantity": "1",
1809
+ // "needAddressTag": false,
1810
+ // "requiredConfirmTimes": 64,
1811
+ // "canWithdrawConfirmTimes": 64,
1812
+ // "coinType": "ERC20_TOKEN"
1813
+ // }
1814
+ //
1815
+ const address = this.safeString(depositAddress, 'address');
1816
+ this.checkAddress(address);
1817
+ let tag = this.safeString(depositAddress, 'addressExt');
1818
+ if (tag === '') {
1819
+ tag = undefined;
1820
+ }
1821
+ return {
1822
+ 'currency': currency['code'],
1823
+ 'address': address,
1824
+ 'tag': tag,
1825
+ 'network': undefined,
1826
+ 'info': depositAddress,
1827
+ };
1828
+ }
1829
+ async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
1830
+ /**
1831
+ * @method
1832
+ * @name hashkey#fetchDeposits
1833
+ * @description fetch all deposits made to an account
1834
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-deposit-history
1835
+ * @param {string} code unified currency code of the currency transferred
1836
+ * @param {int} [since] the earliest time in ms to fetch transfers for (default 24 hours ago)
1837
+ * @param {int} [limit] the maximum number of transfer structures to retrieve (default 50, max 200)
1838
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1839
+ * @param {int} [params.until] the latest time in ms to fetch transfers for (default time now)
1840
+ * @param {int} [params.fromId] starting ID (To be released)
1841
+ * @returns {object[]} a list of [transfer structures]{@link https://docs.ccxt.com/#/?id=transfer-structure}
1842
+ */
1843
+ const methodName = 'fetchDeposits';
1844
+ await this.loadMarkets();
1845
+ const request = {};
1846
+ let currency = undefined;
1847
+ if (code !== undefined) {
1848
+ currency = this.currency(code);
1849
+ request['coin'] = currency['id'];
1850
+ }
1851
+ if (since !== undefined) {
1852
+ request['startTime'] = since;
1853
+ }
1854
+ if (limit !== undefined) {
1855
+ request['limit'] = limit;
1856
+ }
1857
+ let until = undefined;
1858
+ [until, params] = this.handleOptionAndParams(params, methodName, 'until');
1859
+ if (until !== undefined) {
1860
+ request['endTime'] = until;
1861
+ }
1862
+ const response = await this.privateGetApiV1AccountDepositOrders(this.extend(request, params));
1863
+ //
1864
+ // [
1865
+ // {
1866
+ // "time": "1721641082163",
1867
+ // "coin": "TRXUSDT",
1868
+ // "coinName": "TRXUSDT",
1869
+ // "address": "TBA6CypYJizwA9XdC7Ubgc5F1bxrQ7SqPt",
1870
+ // "quantity": "86.00000000000000000000",
1871
+ // "status": 4,
1872
+ // "statusCode": "4",
1873
+ // "txId": "0970c14da4d7412295fa7b21c03a08da319e746a0d59ef14462a74183d118da4"
1874
+ // }
1875
+ // ]
1876
+ //
1877
+ return this.parseTransactions(response, currency, since, limit, { 'type': 'deposit' });
1878
+ }
1879
+ async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
1880
+ /**
1881
+ * @method
1882
+ * @name hashkey#fetchWithdrawals
1883
+ * @description fetch all withdrawals made from an account
1884
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/withdrawal-records
1885
+ * @param {string} code unified currency code of the currency transferred
1886
+ * @param {int} [since] the earliest time in ms to fetch transfers for (default 24 hours ago)
1887
+ * @param {int} [limit] the maximum number of transfer structures to retrieve (default 50, max 200)
1888
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1889
+ * @param {int} [params.until] the latest time in ms to fetch transfers for (default time now)
1890
+ * @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1891
+ */
1892
+ const methodName = 'fetchWithdrawals';
1893
+ await this.loadMarkets();
1894
+ const request = {};
1895
+ let currency = undefined;
1896
+ if (code !== undefined) {
1897
+ currency = this.currency(code);
1898
+ request['coin'] = currency['id'];
1899
+ }
1900
+ if (since !== undefined) {
1901
+ request['startTime'] = since;
1902
+ }
1903
+ if (limit !== undefined) {
1904
+ request['limit'] = limit;
1905
+ }
1906
+ let until = undefined;
1907
+ [until, params] = this.handleOptionAndParams(params, methodName, 'until');
1908
+ if (until !== undefined) {
1909
+ request['endTime'] = until;
1910
+ }
1911
+ const response = await this.privateGetApiV1AccountWithdrawOrders(this.extend(request, params));
1912
+ //
1913
+ // [
1914
+ // {
1915
+ // "time": "1723545505366",
1916
+ // "id": "W611267400947572736",
1917
+ // "coin": "USDT",
1918
+ // "coinId": "USDT",
1919
+ // "coinName": "USDT",
1920
+ // "address": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
1921
+ // "quantity": "2.00000000",
1922
+ // "arriveQuantity": "2.00000000",
1923
+ // "txId": "f83f94e7d2e81fbec98c66c25d6615872cc2d426145629b6cf22e5e0a0753715",
1924
+ // "addressUrl": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
1925
+ // "feeCoinId": "USDT",
1926
+ // "feeCoinName": "USDT",
1927
+ // "fee": "1.00000000",
1928
+ // "remark": "",
1929
+ // "platform": ""
1930
+ // }
1931
+ // ]
1932
+ //
1933
+ return this.parseTransactions(response, currency, since, limit, { 'type': 'withdrawal' });
1934
+ }
1935
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
1936
+ /**
1937
+ * @method
1938
+ * @name hashkey#withdraw
1939
+ * @description make a withdrawal
1940
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/withdraw
1941
+ * @param {string} code unified currency code
1942
+ * @param {float} amount the amount to withdraw
1943
+ * @param {string} address the address to withdraw to
1944
+ * @param {string} tag
1945
+ * @param {string} [params.network] network for withdraw
1946
+ * @param {string} [params.clientOrderId] client order id
1947
+ * @param {string} [params.platform] the platform to withdraw to (hashkey, HashKey HK)
1948
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1949
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
1950
+ */
1951
+ [tag, params] = this.handleWithdrawTagAndParams(tag, params);
1952
+ await this.loadMarkets();
1953
+ const currency = this.currency(code);
1954
+ const request = {
1955
+ 'coin': currency['id'],
1956
+ 'address': address,
1957
+ 'quantity': amount,
1958
+ };
1959
+ if (tag !== undefined) {
1960
+ request['addressExt'] = tag;
1961
+ }
1962
+ let clientOrderId = undefined;
1963
+ [clientOrderId, params] = this.handleOptionAndParams(params, 'withdraw', 'clientOrderId');
1964
+ if (clientOrderId !== undefined) {
1965
+ request['clientOrderId'] = clientOrderId;
1966
+ }
1967
+ let networkCode = undefined;
1968
+ [networkCode, params] = this.handleNetworkCodeAndParams(params);
1969
+ if (networkCode !== undefined) {
1970
+ request['chainType'] = this.networkCodeToId(networkCode);
1971
+ }
1972
+ let platform = undefined;
1973
+ [platform, params] = this.handleOptionAndParams(params, 'withdraw', 'platform');
1974
+ if (platform !== undefined) {
1975
+ request['platform'] = platform;
1976
+ }
1977
+ const response = await this.privatePostApiV1AccountWithdraw(this.extend(request, params));
1978
+ //
1979
+ // {
1980
+ // "success": true,
1981
+ // "id": "0",
1982
+ // "orderId": "W611267400947572736",
1983
+ // "accountId": "1732885739589466115"
1984
+ // }
1985
+ //
1986
+ return this.parseTransaction(response, currency);
1987
+ }
1988
+ parseTransaction(transaction, currency = undefined) {
1989
+ //
1990
+ // fetchDeposits
1991
+ // {
1992
+ // "time": "1721641082163",
1993
+ // "coin": "TRXUSDT", // todo how to parse it?
1994
+ // "coinName": "TRXUSDT",
1995
+ // "address": "TBA6CypYJizwA9XdC7Ubgc5F1bxrQ7SqPt",
1996
+ // "quantity": "86.00000000000000000000",
1997
+ // "status": 4,
1998
+ // "statusCode": "4",
1999
+ // "txId": "0970c14da4d7412295fa7b21c03a08da319e746a0d59ef14462a74183d118da4"
2000
+ // }
2001
+ //
2002
+ // fetchWithdrawals
2003
+ // {
2004
+ // "time": "1723545505366",
2005
+ // "id": "W611267400947572736",
2006
+ // "coin": "USDT",
2007
+ // "coinId": "USDT",
2008
+ // "coinName": "USDT",
2009
+ // "address": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
2010
+ // "quantity": "2.00000000",
2011
+ // "arriveQuantity": "2.00000000",
2012
+ // "txId": "f83f94e7d2e81fbec98c66c25d6615872cc2d426145629b6cf22e5e0a0753715",
2013
+ // "addressUrl": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
2014
+ // "feeCoinId": "USDT",
2015
+ // "feeCoinName": "USDT",
2016
+ // "fee": "1.00000000",
2017
+ // "remark": "",
2018
+ // "platform": ""
2019
+ // }
2020
+ //
2021
+ // withdraw
2022
+ // {
2023
+ // "success": true,
2024
+ // "id": "0",
2025
+ // "orderId": "W611267400947572736",
2026
+ // "accountId": "1732885739589466115"
2027
+ // }
2028
+ //
2029
+ const id = this.safeString2(transaction, 'id', 'orderId');
2030
+ const address = this.safeString(transaction, 'address');
2031
+ let status = this.safeString(transaction, 'status'); // for fetchDeposits
2032
+ if (status === undefined) {
2033
+ const success = this.safeBool(transaction, 'success', false); // for withdraw
2034
+ if (success) {
2035
+ status = 'ok';
2036
+ }
2037
+ else {
2038
+ const addressUrl = this.safeString(transaction, 'addressUrl'); // for fetchWithdrawals
2039
+ if (addressUrl !== undefined) {
2040
+ status = 'ok';
2041
+ }
2042
+ }
2043
+ }
2044
+ const txid = this.safeString(transaction, 'txId');
2045
+ const coin = this.safeString(transaction, 'coin');
2046
+ const code = this.safeCurrencyCode(coin, currency);
2047
+ const timestamp = this.safeInteger(transaction, 'time');
2048
+ const amount = this.safeNumber(transaction, 'quantity');
2049
+ const feeCost = this.safeNumber(transaction, 'fee');
2050
+ let fee = undefined;
2051
+ if (feeCost !== undefined) {
2052
+ fee = {
2053
+ 'cost': feeCost,
2054
+ 'currency': code,
2055
+ };
2056
+ }
2057
+ return {
2058
+ 'info': transaction,
2059
+ 'id': id,
2060
+ 'txid': txid,
2061
+ 'timestamp': timestamp,
2062
+ 'datetime': this.iso8601(timestamp),
2063
+ 'network': undefined,
2064
+ 'address': address,
2065
+ 'addressTo': undefined,
2066
+ 'addressFrom': undefined,
2067
+ 'tag': undefined,
2068
+ 'tagTo': undefined,
2069
+ 'tagFrom': undefined,
2070
+ 'type': undefined,
2071
+ 'amount': amount,
2072
+ 'currency': code,
2073
+ 'status': this.parseTransactionStatus(status),
2074
+ 'updated': undefined,
2075
+ 'internal': undefined,
2076
+ 'comment': undefined,
2077
+ 'fee': fee,
2078
+ };
2079
+ }
2080
+ parseTransactionStatus(status) {
2081
+ const statuses = {
2082
+ '1': 'pending',
2083
+ '2': 'pending',
2084
+ '3': 'failed',
2085
+ '4': 'ok',
2086
+ '5': 'pending',
2087
+ '6': 'ok',
2088
+ '7': 'failed',
2089
+ '8': 'cancelled',
2090
+ '9': 'failed',
2091
+ '10': 'failed',
2092
+ 'successful': 'ok',
2093
+ 'success': 'ok',
2094
+ };
2095
+ return this.safeString(statuses, status, status);
2096
+ }
2097
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
2098
+ /**
2099
+ * @method
2100
+ * @name hashkey#transfer
2101
+ * @description transfer currency internally between wallets on the same account
2102
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/new-account-transfer
2103
+ * @param {string} code unified currency code
2104
+ * @param {float} amount amount to transfer
2105
+ * @param {string} fromAccount account id to transfer from
2106
+ * @param {string} toAccount account id to transfer to
2107
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2108
+ * @param {string} [params.clientOrderId] a unique id for the transfer
2109
+ * @param {string} [params.remark] a note for the transfer
2110
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
2111
+ */
2112
+ await this.loadMarkets();
2113
+ const currency = this.currency(code);
2114
+ const request = {
2115
+ 'coin': currency['id'],
2116
+ 'quantity': this.currencyToPrecision(code, amount),
2117
+ 'fromAccountId': fromAccount,
2118
+ 'toAccountId': toAccount,
2119
+ };
2120
+ let clientOrderId = undefined;
2121
+ [clientOrderId, params] = this.handleOptionAndParams(params, 'transfer', 'clientOrderId');
2122
+ if (clientOrderId !== undefined) {
2123
+ request['clientOrderId'] = clientOrderId;
2124
+ }
2125
+ let remark = undefined;
2126
+ [remark, params] = this.handleOptionAndParams(params, 'transfer', 'remark');
2127
+ if (remark !== undefined) {
2128
+ request['remark'] = remark;
2129
+ }
2130
+ const response = await this.privatePostApiV1AccountAssetTransfer(this.extend(request, params));
2131
+ //
2132
+ // {
2133
+ // "success": true,
2134
+ // "timestamp": 1722260230773,
2135
+ // "clientOrderId": "",
2136
+ // "orderId": "1740839420695806720"
2137
+ // }
2138
+ //
2139
+ return this.parseTransfer(response, currency);
2140
+ }
2141
+ parseTransfer(transfer, currency = undefined) {
2142
+ const timestamp = this.safeInteger(transfer, 'timestamp');
2143
+ const currencyId = this.safeString(currency, 'id');
2144
+ let status = undefined;
2145
+ const success = this.safeBool(transfer, 'success', false);
2146
+ if (success) {
2147
+ status = 'ok';
2148
+ }
2149
+ return {
2150
+ 'id': this.safeString(transfer, 'orderId'),
2151
+ 'timestamp': timestamp,
2152
+ 'datetime': this.iso8601(timestamp),
2153
+ 'currency': this.safeCurrencyCode(currencyId, currency),
2154
+ 'amount': undefined,
2155
+ 'fromAccount': undefined,
2156
+ 'toAccount': undefined,
2157
+ 'status': status,
2158
+ 'info': transfer,
2159
+ };
2160
+ }
2161
+ async fetchAccounts(params = {}) {
2162
+ /**
2163
+ * @method
2164
+ * @name hashkey#fetchAccounts
2165
+ * @description fetch all the accounts associated with a profile
2166
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/query-sub-account
2167
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2168
+ * @returns {object} a dictionary of [account structures]{@link https://docs.ccxt.com/#/?id=account-structure} indexed by the account type
2169
+ */
2170
+ await this.loadMarkets();
2171
+ const response = await this.privateGetApiV1AccountType(params);
2172
+ //
2173
+ // [
2174
+ // {
2175
+ // "accountId": "1732885739589466112",
2176
+ // "accountLabel": "Main Trading Account",
2177
+ // "accountType": 1,
2178
+ // "accountIndex": 0
2179
+ // },
2180
+ // ...
2181
+ // ]
2182
+ //
2183
+ return this.parseAccounts(response, params);
2184
+ }
2185
+ parseAccount(account) {
2186
+ const accountLabel = this.safeString(account, 'accountLabel');
2187
+ let label = '';
2188
+ if (accountLabel === 'Main Trading Account' || accountLabel === 'Main Future Account') {
2189
+ label = 'main';
2190
+ }
2191
+ else if (accountLabel === 'Sub Main Trading Account' || accountLabel === 'Sub Main Future Account') {
2192
+ label = 'sub';
2193
+ }
2194
+ const accountType = this.parseAccountType(this.safeString(account, 'accountType'));
2195
+ const type = label + ' ' + accountType;
2196
+ return {
2197
+ 'id': this.safeString(account, 'accountId'),
2198
+ 'type': type,
2199
+ 'code': undefined,
2200
+ 'info': account,
2201
+ };
2202
+ }
2203
+ parseAccountType(type) {
2204
+ const types = {
2205
+ '1': 'spot account',
2206
+ '3': 'swap account',
2207
+ '5': 'custody account',
2208
+ '6': 'fiat account',
2209
+ };
2210
+ return this.safeString(types, type, type);
2211
+ }
2212
+ encodeAccountType(type) {
2213
+ const types = {
2214
+ 'spot': '1',
2215
+ 'swap': '3',
2216
+ 'custody': '5',
2217
+ };
2218
+ return this.safeInteger(types, type, type);
2219
+ }
2220
+ encodeFlowType(type) {
2221
+ const types = {
2222
+ 'trade': '1',
2223
+ 'fee': '3',
2224
+ 'transfer': '51',
2225
+ 'deposit': '900',
2226
+ 'withdraw': '904',
2227
+ };
2228
+ return this.safeInteger(types, type, type);
2229
+ }
2230
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
2231
+ /**
2232
+ * @method
2233
+ * @name hashkey#fetchLedger
2234
+ * @description fetch the history of changes, actions done by the user or operations that altered balance of the user
2235
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-account-transaction-list
2236
+ * @param {string} code unified currency code, default is undefined (not used)
2237
+ * @param {int} [since] timestamp in ms of the earliest ledger entry, default is undefined
2238
+ * @param {int} [limit] max number of ledger entrys to return, default is undefined
2239
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2240
+ * @param {int} [params.until] the latest time in ms to fetch entries for
2241
+ * @param {int} [params.flowType] trade, fee, transfer, deposit, withdrawal
2242
+ * @param {int} [params.accountType] spot, swap, custody
2243
+ * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger-structure}
2244
+ */
2245
+ const methodName = 'fetchLedger';
2246
+ if (since === undefined) {
2247
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a since argument');
2248
+ }
2249
+ let until = undefined;
2250
+ [until, params] = this.handleOptionAndParams(params, methodName, 'until');
2251
+ if (until === undefined) {
2252
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires an until argument');
2253
+ }
2254
+ await this.loadMarkets();
2255
+ const currency = this.currency(code);
2256
+ const request = {};
2257
+ request['startTime'] = since;
2258
+ if (limit !== undefined) {
2259
+ request['limit'] = limit;
2260
+ }
2261
+ request['endTime'] = until;
2262
+ let flowType = undefined;
2263
+ [flowType, params] = this.handleOptionAndParams(params, methodName, 'flowType');
2264
+ if (flowType !== undefined) {
2265
+ request['flowType'] = this.encodeFlowType(flowType);
2266
+ }
2267
+ let accountType = undefined;
2268
+ [accountType, params] = this.handleOptionAndParams(params, methodName, 'accountType');
2269
+ if (accountType !== undefined) {
2270
+ request['accountType'] = this.encodeAccountType(accountType);
2271
+ }
2272
+ const response = await this.privateGetApiV1AccountBalanceFlow(this.extend(request, params));
2273
+ //
2274
+ // [
2275
+ // {
2276
+ // "id": "1740844413612065537",
2277
+ // "accountId": "1732885739589466112",
2278
+ // "coin": "USDT",
2279
+ // "coinId": "USDT",
2280
+ // "coinName": "USDT",
2281
+ // "flowTypeValue": 51,
2282
+ // "flowType": "USER_ACCOUNT_TRANSFER",
2283
+ // "flowName": "",
2284
+ // "change": "-1",
2285
+ // "total": "8.015680088",
2286
+ // "created": "1722260825765"
2287
+ // },
2288
+ // ...
2289
+ // ]
2290
+ //
2291
+ return this.parseLedger(response, currency, since, limit);
2292
+ }
2293
+ parseLedgerEntryType(type) {
2294
+ const types = {
2295
+ '1': 'trade',
2296
+ '2': 'fee',
2297
+ '51': 'transfer',
2298
+ '900': 'deposit',
2299
+ '904': 'withdraw',
2300
+ };
2301
+ return this.safeString(types, type, type);
2302
+ }
2303
+ parseLedgerEntry(item, currency = undefined) {
2304
+ //
2305
+ // {
2306
+ // "id": "1740844413612065537",
2307
+ // "accountId": "1732885739589466112",
2308
+ // "coin": "USDT",
2309
+ // "coinId": "USDT",
2310
+ // "coinName": "USDT",
2311
+ // "flowTypeValue": 51,
2312
+ // "flowType": "USER_ACCOUNT_TRANSFER",
2313
+ // "flowName": "",
2314
+ // "change": "-1",
2315
+ // "total": "8.015680088",
2316
+ // "created": "1722260825765"
2317
+ // }
2318
+ //
2319
+ const id = this.safeString(item, 'id');
2320
+ const account = this.safeString(item, 'accountId');
2321
+ const timestamp = this.safeInteger(item, 'created');
2322
+ const type = this.parseLedgerEntryType(this.safeString(item, 'flowTypeValue'));
2323
+ const code = this.safeCurrencyCode(this.safeString(item, 'coin'), currency);
2324
+ const amountString = this.safeString(item, 'change');
2325
+ const amount = this.parseNumber(amountString);
2326
+ let direction = 'in';
2327
+ if (amountString.indexOf('-') >= 0) {
2328
+ direction = 'out';
2329
+ }
2330
+ const afterString = this.safeString(item, 'total');
2331
+ const after = this.parseNumber(afterString);
2332
+ const status = 'ok';
2333
+ return {
2334
+ 'id': id,
2335
+ 'info': item,
2336
+ 'timestamp': timestamp,
2337
+ 'datetime': this.iso8601(timestamp),
2338
+ 'account': account,
2339
+ 'direction': direction,
2340
+ 'referenceId': undefined,
2341
+ 'referenceAccount': undefined,
2342
+ 'type': type,
2343
+ 'currency': code,
2344
+ 'symbol': undefined,
2345
+ 'amount': amount,
2346
+ 'before': undefined,
2347
+ 'after': after,
2348
+ 'status': status,
2349
+ 'fee': undefined,
2350
+ };
2351
+ }
2352
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
2353
+ /**
2354
+ * @method
2355
+ * @name hashkey#createOrder
2356
+ * @description create a trade order
2357
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/test-new-order
2358
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/create-order
2359
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/create-new-futures-order
2360
+ * @param {string} symbol unified symbol of the market to create an order in
2361
+ * @param {string} type 'market' or 'limit' or 'LIMIT_MAKER' for spot, 'market' or 'limit' or 'STOP' for swap
2362
+ * @param {string} side 'buy' or 'sell'
2363
+ * @param {float} amount how much of you want to trade in units of the base currency
2364
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2365
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2366
+ * @param {float} [params.cost] *spot market buy only* the quote quantity that can be used as an alternative for the amount
2367
+ * @param {boolean} [params.test] *spot markets only* whether to use the test endpoint or not, default is false
2368
+ * @param {bool} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
2369
+ * @param {string} [params.timeInForce] "GTC" or "IOC" or "PO" for spot, 'GTC' or 'FOK' or 'IOC' or 'LIMIT_MAKER' or 'PO' for swap
2370
+ * @param {string} [params.clientOrderId] a unique id for the order - is mandatory for swap
2371
+ * @param {float} [params.triggerPrice] *swap markets only* The price at which a trigger order is triggered at
2372
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2373
+ */
2374
+ await this.loadMarkets();
2375
+ const market = this.market(symbol);
2376
+ if (market['spot']) {
2377
+ return await this.createSpotOrder(symbol, type, side, amount, price, params);
2378
+ }
2379
+ else if (market['swap']) {
2380
+ return await this.createSwapOrder(symbol, type, side, amount, price, params);
2381
+ }
2382
+ else {
2383
+ throw new NotSupported(this.id + ' createOrder() is not supported for ' + market['type'] + ' type of markets');
2384
+ }
2385
+ }
2386
+ async createMarketBuyOrderWithCost(symbol, cost, params = {}) {
2387
+ /**
2388
+ * @method
2389
+ * @name createMarketBuyOrderWithCost
2390
+ * @description create a market buy order by providing the symbol and cost
2391
+ * @param {string} symbol unified symbol of the market to create an order in
2392
+ * @param {float} cost how much you want to trade in units of the quote currency
2393
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2394
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2395
+ */
2396
+ await this.loadMarkets();
2397
+ const market = this.market(symbol);
2398
+ if (!market['spot']) {
2399
+ throw new NotSupported(this.id + ' createMarketBuyOrderWithCost() is supported for spot markets only');
2400
+ }
2401
+ params['cost'] = cost;
2402
+ return await this.createOrder(symbol, 'market', 'buy', cost, undefined, params);
2403
+ }
2404
+ async createSpotOrder(symbol, type, side, amount, price = undefined, params = {}) {
2405
+ /**
2406
+ * @method
2407
+ * @name hashkey#createSpotOrder
2408
+ * @description create a trade order on spot market
2409
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/test-new-order
2410
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/create-order
2411
+ * @param {string} symbol unified symbol of the market to create an order in
2412
+ * @param {string} type 'market' or 'limit' or 'LIMIT_MAKER'
2413
+ * @param {string} side 'buy' or 'sell'
2414
+ * @param {float} amount how much of you want to trade in units of the base currency
2415
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2416
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2417
+ * @param {float} [params.cost] *market buy only* the quote quantity that can be used as an alternative for the amount
2418
+ * @param {bool} [params.test] whether to use the test endpoint or not, default is false
2419
+ * @param {bool} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
2420
+ * @param {string} [params.timeInForce] 'GTC', 'IOC', or 'PO'
2421
+ * @param {string} [params.clientOrderId] a unique id for the order
2422
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2423
+ */
2424
+ const triggerPrice = this.safeString2(params, 'stopPrice', 'triggerPrice');
2425
+ if (triggerPrice !== undefined) {
2426
+ throw new NotSupported(this.id + ' trigger orders are not supported for spot markets');
2427
+ }
2428
+ await this.loadMarkets();
2429
+ const market = this.market(symbol);
2430
+ const isMarketBuy = (type === 'market') && (side === 'buy');
2431
+ const cost = this.safeString(params, 'cost');
2432
+ if ((!isMarketBuy) && (cost !== undefined)) {
2433
+ throw new NotSupported(this.id + ' createOrder() supports cost parameter for spot market buy orders only');
2434
+ }
2435
+ const request = this.createSpotOrderRequest(symbol, type, side, amount, price, params);
2436
+ let response = {};
2437
+ const test = this.safeBool(params, 'test');
2438
+ if (test) {
2439
+ params = this.omit(params, 'test');
2440
+ response = await this.privatePostApiV1SpotOrderTest(request);
2441
+ }
2442
+ else if (isMarketBuy && (cost === undefined)) {
2443
+ response = await this.privatePostApiV11SpotOrder(request); // the endpoint for market buy orders by amount
2444
+ //
2445
+ // {
2446
+ // "accountId": "1732885739589466112",
2447
+ // "symbol": "ETHUSDT",
2448
+ // "symbolName": "ETHUSDT",
2449
+ // "clientOrderId": "1722005792096557",
2450
+ // "orderId": "1738705036219839744",
2451
+ // "transactTime": "1722005792106",
2452
+ // "price": "0",
2453
+ // "origQty": "0.006",
2454
+ // "executedQty": "0.0059",
2455
+ // "status": "FILLED",
2456
+ // "timeInForce": "IOC",
2457
+ // "type": "MARKET",
2458
+ // "side": "BUY",
2459
+ // "reqAmount": "0",
2460
+ // "concentration": ""
2461
+ // }
2462
+ //
2463
+ }
2464
+ else {
2465
+ response = await this.privatePostApiV1SpotOrder(request); // the endpoint for market buy orders by cost and other orders
2466
+ //
2467
+ // market buy
2468
+ // {
2469
+ // "accountId": "1732885739589466112",
2470
+ // "symbol": "ETHUSDT",
2471
+ // "symbolName": "ETHUSDT",
2472
+ // "clientOrderId": "1722004623170558",
2473
+ // "orderId": "1738695230608169984",
2474
+ // "transactTime": "1722004623186",
2475
+ // "price": "0",
2476
+ // "origQty": "0",
2477
+ // "executedQty": "0.0061",
2478
+ // "status": "FILLED",
2479
+ // "timeInForce": "IOC",
2480
+ // "type": "MARKET",
2481
+ // "side": "BUY",
2482
+ // "reqAmount": "20",
2483
+ // "concentration": ""
2484
+ // }
2485
+ //
2486
+ // market sell
2487
+ // {
2488
+ // "accountId": "1732885739589466112",
2489
+ // "symbol": "ETHUSDT",
2490
+ // "symbolName": "ETHUSDT",
2491
+ // "clientOrderId": "1722005654516362",
2492
+ // "orderId": "1738703882140316928",
2493
+ // "transactTime": "1722005654529",
2494
+ // "price": "0",
2495
+ // "origQty": "0.006",
2496
+ // "executedQty": "0.006",
2497
+ // "status": "FILLED",
2498
+ // "timeInForce": "IOC",
2499
+ // "type": "MARKET",
2500
+ // "side": "SELL",
2501
+ // "reqAmount": "0",
2502
+ // "concentration": ""
2503
+ // }
2504
+ //
2505
+ // limit
2506
+ // {
2507
+ // "accountId": "1732885739589466112",
2508
+ // "symbol": "ETHUSDT",
2509
+ // "symbolName": "ETHUSDT",
2510
+ // "clientOrderId": "1722006209978370",
2511
+ // "orderId": "1738708541676585728",
2512
+ // "transactTime": "1722006209989",
2513
+ // "price": "5000",
2514
+ // "origQty": "0.005",
2515
+ // "executedQty": "0",
2516
+ // "status": "NEW",
2517
+ // "timeInForce": "GTC",
2518
+ // "type": "LIMIT_MAKER",
2519
+ // "side": "SELL",
2520
+ // "reqAmount": "0",
2521
+ // "concentration": ""
2522
+ // }
2523
+ //
2524
+ }
2525
+ return this.parseOrder(response, market);
2526
+ }
2527
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
2528
+ const market = this.market(symbol);
2529
+ if (market['spot']) {
2530
+ return this.createSpotOrderRequest(symbol, type, side, amount, price, params);
2531
+ }
2532
+ else if (market['swap']) {
2533
+ return this.createSwapOrderRequest(symbol, type, side, amount, price, params);
2534
+ }
2535
+ else {
2536
+ throw new NotSupported(this.id + ' ' + 'createOrderRequest() is not supported for ' + market['type'] + ' type of markets');
2537
+ }
2538
+ }
2539
+ createSpotOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
2540
+ /**
2541
+ * @method
2542
+ * @ignore
2543
+ * @name hashkey#createSpotOrderRequest
2544
+ * @description helper function to build request
2545
+ * @param {string} symbol unified symbol of the market to create an order in
2546
+ * @param {string} type 'market' or 'limit' or 'LIMIT_MAKER'
2547
+ * @param {string} side 'buy' or 'sell'
2548
+ * @param {float} amount how much of you want to trade in units of the base currency
2549
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2550
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2551
+ * @param {float} [params.cost] *market buy only* the quote quantity that can be used as an alternative for the amount
2552
+ * @param {bool} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
2553
+ * @param {string} [params.timeInForce] "GTC", "IOC", or "PO"
2554
+ * @param {string} [params.clientOrderId] a unique id for the order
2555
+ * @returns {object} request to be sent to the exchange
2556
+ */
2557
+ const market = this.market(symbol);
2558
+ type = type.toUpperCase();
2559
+ const request = {
2560
+ 'symbol': market['id'],
2561
+ 'side': side.toUpperCase(),
2562
+ 'type': type,
2563
+ };
2564
+ if (amount !== undefined) {
2565
+ request['quantity'] = this.amountToPrecision(symbol, amount);
2566
+ }
2567
+ let cost = undefined;
2568
+ [cost, params] = this.handleParamString(params, 'cost');
2569
+ if (cost !== undefined) {
2570
+ request['quantity'] = this.costToPrecision(symbol, cost);
2571
+ }
2572
+ if (price !== undefined) {
2573
+ request['price'] = this.priceToPrecision(symbol, price);
2574
+ }
2575
+ const isMarketOrder = type === 'MARKET';
2576
+ let postOnly = false;
2577
+ [postOnly, params] = this.handlePostOnly(isMarketOrder, type === 'LIMIT_MAKER', params);
2578
+ if (postOnly && (type === 'LIMIT')) {
2579
+ request['type'] = 'LIMIT_MAKER';
2580
+ }
2581
+ let clientOrderId = undefined;
2582
+ [clientOrderId, params] = this.handleParamString(params, 'clientOrderId');
2583
+ if (clientOrderId !== undefined) {
2584
+ params['newClientOrderId'] = clientOrderId;
2585
+ }
2586
+ return this.extend(request, params);
2587
+ }
2588
+ createSwapOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
2589
+ /**
2590
+ * @method
2591
+ * @ignore
2592
+ * @name hashkey#createSwapOrderRequest
2593
+ * @description helper function to build request
2594
+ * @param {string} symbol unified symbol of the market to create an order in
2595
+ * @param {string} type 'market' or 'limit' or 'STOP'
2596
+ * @param {string} side 'buy' or 'sell'
2597
+ * @param {float} amount how much of you want to trade in units of the base currency
2598
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2599
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2600
+ * @param {bool} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
2601
+ * @param {bool} [params.reduceOnly] true or false whether the order is reduce only
2602
+ * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
2603
+ * @param {string} [params.timeInForce] 'GTC', 'FOK', 'IOC', 'LIMIT_MAKER' or 'PO'
2604
+ * @param {string} [params.clientOrderId] a unique id for the order
2605
+ * @returns {object} request to be sent to the exchange
2606
+ */
2607
+ const market = this.market(symbol);
2608
+ const request = {
2609
+ 'symbol': market['id'],
2610
+ 'type': 'LIMIT',
2611
+ 'quantity': this.amountToPrecision(symbol, amount),
2612
+ };
2613
+ const isMarketOrder = type === 'market';
2614
+ if (isMarketOrder) {
2615
+ request['priceType'] = 'MARKET';
2616
+ }
2617
+ if (price !== undefined) {
2618
+ request['price'] = this.priceToPrecision(symbol, price);
2619
+ request['priceType'] = 'INPUT';
2620
+ }
2621
+ let reduceOnly = false;
2622
+ [reduceOnly, params] = this.handleParamBool(params, 'reduceOnly', reduceOnly);
2623
+ let suffix = '_OPEN';
2624
+ if (reduceOnly) {
2625
+ suffix = '_CLOSE';
2626
+ }
2627
+ request['side'] = side.toUpperCase() + suffix;
2628
+ let timeInForce = undefined;
2629
+ [timeInForce, params] = this.handleParamString(params, 'timeInForce');
2630
+ let postOnly = false;
2631
+ [postOnly, params] = this.handlePostOnly(isMarketOrder, timeInForce === 'LIMIT_MAKER', params);
2632
+ if (postOnly) {
2633
+ timeInForce = 'LIMIT_MAKER';
2634
+ }
2635
+ if (timeInForce !== undefined) {
2636
+ request['timeInForce'] = timeInForce;
2637
+ }
2638
+ const clientOrderId = this.safeString(params, 'clientOrderId');
2639
+ if (clientOrderId === undefined) {
2640
+ request['clientOrderId'] = this.uuid();
2641
+ }
2642
+ const triggerPrice = this.safeString(params, 'triggerPrice');
2643
+ if (triggerPrice !== undefined) {
2644
+ request['stopPrice'] = this.priceToPrecision(symbol, triggerPrice);
2645
+ request['type'] = 'STOP';
2646
+ params = this.omit(params, 'triggerPrice');
2647
+ }
2648
+ return this.extend(request, params);
2649
+ }
2650
+ async createSwapOrder(symbol, type, side, amount, price = undefined, params = {}) {
2651
+ /**
2652
+ * @method
2653
+ * @name hashkey#createSwapOrder
2654
+ * @description create a trade order on swap market
2655
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/create-new-futures-order
2656
+ * @param {string} symbol unified symbol of the market to create an order in
2657
+ * @param {string} type 'market' or 'limit' or 'STOP'
2658
+ * @param {string} side 'buy' or 'sell'
2659
+ * @param {float} amount how much of you want to trade in units of the base currency
2660
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2661
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2662
+ * @param {bool} [params.postOnly] if true, the order will only be posted to the order book and not executed immediately
2663
+ * @param {bool} [params.reduceOnly] true or false whether the order is reduce only
2664
+ * @param {float} [params.triggerPrice] The price at which a trigger order is triggered at
2665
+ * @param {string} [params.timeInForce] 'GTC', 'FOK', 'IOC', 'LIMIT_MAKER' or 'PO'
2666
+ * @param {string} [params.clientOrderId] a unique id for the order
2667
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2668
+ */
2669
+ await this.loadMarkets();
2670
+ const market = this.market(symbol);
2671
+ const request = this.createSwapOrderRequest(symbol, type, side, amount, price, params);
2672
+ const response = await this.privatePostApiV1FuturesOrder(this.extend(request, params));
2673
+ //
2674
+ // {
2675
+ // "time": "1722429951611",
2676
+ // "updateTime": "1722429951648",
2677
+ // "orderId": "1742263144028363776",
2678
+ // "clientOrderId": "1722429950315",
2679
+ // "symbol": "ETHUSDT-PERPETUAL",
2680
+ // "price": "3460.62",
2681
+ // "leverage": "5",
2682
+ // "origQty": "10",
2683
+ // "executedQty": "10",
2684
+ // "avgPrice": "0",
2685
+ // "marginLocked": "6.9212",
2686
+ // "type": "LIMIT",
2687
+ // "side": "BUY_OPEN",
2688
+ // "timeInForce": "IOC",
2689
+ // "status": "FILLED",
2690
+ // "priceType": "MARKET",
2691
+ // "contractMultiplier": "0.00100000"
2692
+ // }
2693
+ //
2694
+ return this.parseOrder(response, market);
2695
+ }
2696
+ async createOrders(orders, params = {}) {
2697
+ /**
2698
+ * @method
2699
+ * @name hashkey#createOrders
2700
+ * @description create a list of trade orders (all orders should be of the same symbol)
2701
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/create-multiple-orders
2702
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/batch-create-new-futures-order
2703
+ * @param {Array} orders list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
2704
+ * @param {object} [params] extra parameters specific to the api endpoint
2705
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2706
+ */
2707
+ await this.loadMarkets();
2708
+ const ordersRequests = [];
2709
+ for (let i = 0; i < orders.length; i++) {
2710
+ const rawOrder = orders[i];
2711
+ const symbol = this.safeString(rawOrder, 'symbol');
2712
+ const type = this.safeString(rawOrder, 'type');
2713
+ const side = this.safeString(rawOrder, 'side');
2714
+ const amount = this.safeNumber(rawOrder, 'amount');
2715
+ const price = this.safeNumber(rawOrder, 'price');
2716
+ const orderParams = this.safeDict(rawOrder, 'params', {});
2717
+ const orderRequest = this.createOrderRequest(symbol, type, side, amount, price, orderParams);
2718
+ const clientOrderId = this.safeString(orderRequest, 'clientOrderId');
2719
+ if (clientOrderId === undefined) {
2720
+ orderRequest['clientOrderId'] = this.uuid(); // both spot and swap endpoints require clientOrderId
2721
+ }
2722
+ ordersRequests.push(orderRequest);
2723
+ }
2724
+ const firstOrder = ordersRequests[0];
2725
+ const firstSymbol = this.safeString(firstOrder, 'symbol');
2726
+ const market = this.market(firstSymbol);
2727
+ const request = {
2728
+ 'orders': ordersRequests,
2729
+ };
2730
+ let response = undefined;
2731
+ if (market['spot']) {
2732
+ response = await this.privatePostApiV1SpotBatchOrders(this.extend(request, params));
2733
+ //
2734
+ // {
2735
+ // "code": 0,
2736
+ // "result": [
2737
+ // {
2738
+ // "code": "0000",
2739
+ // "order": {
2740
+ // "accountId": "1732885739589466112",
2741
+ // "symbol": "ETHUSDT",
2742
+ // "symbolName": "ETHUSDT",
2743
+ // "clientOrderId": "1722701490163000",
2744
+ // "orderId": "1744540984757258752",
2745
+ // "transactTime": "1722701491385",
2746
+ // "price": "1500",
2747
+ // "origQty": "0.001",
2748
+ // "executedQty": "0",
2749
+ // "status": "NEW",
2750
+ // "timeInForce": "GTC",
2751
+ // "type": "LIMIT",
2752
+ // "side": "BUY",
2753
+ // "reqAmount": "0"
2754
+ // }
2755
+ // }
2756
+ // ],
2757
+ // "concentration": ""
2758
+ // }
2759
+ //
2760
+ }
2761
+ else if (market['swap']) {
2762
+ response = await this.privatePostApiV1FuturesBatchOrders(this.extend(request, params));
2763
+ //
2764
+ // {
2765
+ // "code": "0000",
2766
+ // "result": [
2767
+ // {
2768
+ // "code": "0000",
2769
+ // "order": {
2770
+ // "time": "1722704251911",
2771
+ // "updateTime": "1722704251918",
2772
+ // "orderId": "1744564141727808768",
2773
+ // "clientOrderId": "1722704250648000",
2774
+ // "symbol": "ETHUSDT-PERPETUAL",
2775
+ // "price": "1500",
2776
+ // "leverage": "4",
2777
+ // "origQty": "1",
2778
+ // "executedQty": "0",
2779
+ // "avgPrice": "0",
2780
+ // "marginLocked": "0.375",
2781
+ // "type": "LIMIT",
2782
+ // "side": "BUY_OPEN",
2783
+ // "timeInForce": "GTC",
2784
+ // "status": "NEW",
2785
+ // "priceType": "INPUT",
2786
+ // "isLiquidationOrder": false,
2787
+ // "indexPrice": "0",
2788
+ // "liquidationType": ""
2789
+ // }
2790
+ // },
2791
+ // {
2792
+ // "code": "0207",
2793
+ // "msg": "Create limit order sell price too low"
2794
+ // }
2795
+ // ]
2796
+ // }
2797
+ //
2798
+ }
2799
+ else {
2800
+ throw new NotSupported(this.id + ' ' + 'createOrderRequest() is not supported for ' + market['type'] + ' type of markets');
2801
+ }
2802
+ const result = this.safeList(response, 'result', []);
2803
+ const responseOrders = [];
2804
+ for (let i = 0; i < result.length; i++) {
2805
+ const responseEntry = this.safeDict(result, i, {});
2806
+ const responseOrder = this.safeDict(responseEntry, 'order', {});
2807
+ responseOrders.push(responseOrder);
2808
+ }
2809
+ return this.parseOrders(responseOrders);
2810
+ }
2811
+ async cancelOrder(id, symbol = undefined, params = {}) {
2812
+ /**
2813
+ * @method
2814
+ * @name hashkey#cancelOrder
2815
+ * @description cancels an open order
2816
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/cancel-order
2817
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/cancel-futures-order
2818
+ * @param {string} id order id
2819
+ * @param {string} symbol unified symbol of the market the order was made in
2820
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2821
+ * @param {string} [params.type] 'spot' or 'swap' - the type of the market to fetch entry for (default 'spot')
2822
+ * @param {string} [params.clientOrderId] a unique id for the order that can be used as an alternative for the id
2823
+ * @param {bool} [params.trigger] *swap markets only* true for canceling a trigger order (default false)
2824
+ * @param {bool} [params.stop] *swap markets only* an alternative for trigger param
2825
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2826
+ */
2827
+ const methodName = 'cancelOrder';
2828
+ this.checkTypeParam(methodName, params);
2829
+ await this.loadMarkets();
2830
+ const request = {};
2831
+ const clientOrderId = this.safeString(params, 'clientOrderId');
2832
+ if (clientOrderId === undefined) {
2833
+ request['orderId'] = id;
2834
+ }
2835
+ let market = undefined;
2836
+ if (symbol !== undefined) {
2837
+ market = this.market(symbol);
2838
+ }
2839
+ let marketType = 'spot';
2840
+ [marketType, params] = this.handleMarketTypeAndParams(methodName, market, params, marketType);
2841
+ let response = undefined;
2842
+ if (marketType === 'spot') {
2843
+ response = await this.privateDeleteApiV1SpotOrder(this.extend(request, params));
2844
+ //
2845
+ // {
2846
+ // "accountId": "1732885739589466112",
2847
+ // "symbol": "ETHUSDT",
2848
+ // "clientOrderId": "1722006209978370",
2849
+ // "orderId": "1738708541676585728",
2850
+ // "transactTime": "1722006209989",
2851
+ // "price": "5000",
2852
+ // "origQty": "0.005",
2853
+ // "executedQty": "0",
2854
+ // "status": "NEW",
2855
+ // "timeInForce": "GTC",
2856
+ // "type": "LIMIT_MAKER",
2857
+ // "side": "SELL"
2858
+ // }
2859
+ //
2860
+ }
2861
+ else if (marketType === 'swap') {
2862
+ let isTrigger = false;
2863
+ [isTrigger, params] = this.handleTriggerOptionAndParams(params, methodName, isTrigger);
2864
+ if (isTrigger) {
2865
+ request['type'] = 'STOP';
2866
+ }
2867
+ else {
2868
+ request['type'] = 'LIMIT';
2869
+ }
2870
+ if (market !== undefined) {
2871
+ request['symbol'] = market['id'];
2872
+ }
2873
+ response = await this.privateDeleteApiV1FuturesOrder(this.extend(request, params));
2874
+ //
2875
+ // {
2876
+ // "time": "1722432302919",
2877
+ // "updateTime": "1722432302925",
2878
+ // "orderId": "1742282868229463040",
2879
+ // "clientOrderId": "1722432301670",
2880
+ // "symbol": "ETHUSDT-PERPETUAL",
2881
+ // "price": "4000",
2882
+ // "leverage": "5",
2883
+ // "origQty": "10",
2884
+ // "executedQty": "0",
2885
+ // "avgPrice": "0",
2886
+ // "marginLocked": "0",
2887
+ // "type": "LIMIT_MAKER",
2888
+ // "side": "SELL_CLOSE",
2889
+ // "timeInForce": "GTC",
2890
+ // "status": "NEW",
2891
+ // "priceType": "INPUT",
2892
+ // "isLiquidationOrder": false,
2893
+ // "indexPrice": "0",
2894
+ // "liquidationType": ""
2895
+ // }
2896
+ //
2897
+ }
2898
+ else {
2899
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets');
2900
+ }
2901
+ return this.parseOrder(response);
2902
+ }
2903
+ async cancelAllOrders(symbol = undefined, params = {}) {
2904
+ /**
2905
+ * @method
2906
+ * @name hashkey#cancelAllOrders
2907
+ * @description cancel all open orders
2908
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/cancel-all-open-orders
2909
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/batch-cancel-futures-order
2910
+ * @param {string} symbol unified market symbol, only orders in the market of this symbol are cancelled when symbol is not undefined
2911
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2912
+ * @param {string} [params.side] 'buy' or 'sell'
2913
+ * @returns {object} response from exchange
2914
+ */
2915
+ // Does not cancel trigger orders. For canceling trigger order use cancelOrder() or cancelOrders()
2916
+ const methodName = 'cancelAllOrders';
2917
+ if (symbol === undefined) {
2918
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a symbol argument');
2919
+ }
2920
+ await this.loadMarkets();
2921
+ const market = this.market(symbol);
2922
+ const request = {
2923
+ 'symbol': market['id'],
2924
+ };
2925
+ const side = this.safeString(params, 'side');
2926
+ if (side !== undefined) {
2927
+ request['side'] = side;
2928
+ }
2929
+ let response = undefined;
2930
+ if (market['spot']) {
2931
+ response = await this.privateDeleteApiV1SpotOpenOrders(this.extend(request, params));
2932
+ //
2933
+ // { "success": true }
2934
+ //
2935
+ }
2936
+ else if (market['swap']) {
2937
+ response = await this.privateDeleteApiV1FuturesBatchOrders(this.extend(request, params));
2938
+ //
2939
+ // { "message": "success", "timestamp": "1723127222198", "code": "0000" }
2940
+ //
2941
+ }
2942
+ else {
2943
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + market['type'] + ' type of markets');
2944
+ }
2945
+ const order = this.safeOrder(response);
2946
+ order['info'] = response;
2947
+ return [order];
2948
+ }
2949
+ async cancelOrders(ids, symbol = undefined, params = {}) {
2950
+ /**
2951
+ * @method
2952
+ * @name hashkey#cancelOrders
2953
+ * @description cancel multiple orders
2954
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/cancel-multiple-orders
2955
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/batch-cancel-futures-order-by-order-id
2956
+ * @param {string[]} ids order ids
2957
+ * @param {string} [symbol] unified market symbol (not used by hashkey)
2958
+ * @param {string} [params.type] 'spot' or 'swap' - the type of the market to fetch entry for (default 'spot')
2959
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2960
+ */
2961
+ const methodName = 'cancelOrders';
2962
+ await this.loadMarkets();
2963
+ const request = {};
2964
+ const orderIds = ids.join(',');
2965
+ request['ids'] = orderIds;
2966
+ let market = undefined;
2967
+ if (symbol !== undefined) {
2968
+ market = this.market(symbol);
2969
+ }
2970
+ let marketType = 'spot';
2971
+ [marketType, params] = this.handleMarketTypeAndParams(methodName, market, params, marketType);
2972
+ let response = undefined;
2973
+ if (marketType === 'spot') {
2974
+ response = await this.privateDeleteApiV1SpotCancelOrderByIds(this.extend(request));
2975
+ //
2976
+ // {
2977
+ // "code": "0000",
2978
+ // "result": []
2979
+ // }
2980
+ //
2981
+ }
2982
+ else if (marketType === 'swap') {
2983
+ response = this.privateDeleteApiV1FuturesCancelOrderByIds(this.extend(request));
2984
+ }
2985
+ else {
2986
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets');
2987
+ }
2988
+ const order = this.safeOrder(response);
2989
+ order['info'] = response;
2990
+ return [order];
2991
+ }
2992
+ async fetchOrder(id, symbol = undefined, params = {}) {
2993
+ /**
2994
+ * @method
2995
+ * @name hashkey#fetchOrder
2996
+ * @description fetches information on an order made by the user
2997
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/query-order
2998
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-futures-order
2999
+ * @param {string} id the order id
3000
+ * @param {string} symbol unified symbol of the market the order was made in
3001
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3002
+ * @param {string} [params.type] 'spot' or 'swap' - the type of the market to fetch entry for (default 'spot')
3003
+ * @param {string} [params.clientOrderId] a unique id for the order that can be used as an alternative for the id
3004
+ * @param {string} [params.accountId] *spot markets only* account id to fetch the order from
3005
+ * @param {bool} [params.trigger] *swap markets only* true for fetching a trigger order (default false)
3006
+ * @param {bool} [params.stop] *swap markets only* an alternative for trigger param
3007
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
3008
+ */
3009
+ const methodName = 'fetchOrder';
3010
+ this.checkTypeParam(methodName, params);
3011
+ await this.loadMarkets();
3012
+ const request = {};
3013
+ let clientOrderId = undefined;
3014
+ [clientOrderId, params] = this.handleParamString(params, 'clientOrderId');
3015
+ if (clientOrderId === undefined) {
3016
+ request['orderId'] = id;
3017
+ }
3018
+ let market = undefined;
3019
+ if (symbol !== undefined) {
3020
+ market = this.market(symbol);
3021
+ }
3022
+ let marketType = 'spot';
3023
+ [marketType, params] = this.handleMarketTypeAndParams(methodName, market, params, marketType);
3024
+ let response = undefined;
3025
+ if (marketType === 'spot') {
3026
+ if (clientOrderId !== undefined) {
3027
+ request['origClientOrderId'] = clientOrderId;
3028
+ }
3029
+ let accountId = undefined;
3030
+ [accountId, params] = this.handleOptionAndParams(params, methodName, 'accountId');
3031
+ if (accountId !== undefined) {
3032
+ request['accountId'] = accountId;
3033
+ }
3034
+ response = await this.privateGetApiV1SpotOrder(this.extend(request, params));
3035
+ //
3036
+ // {
3037
+ // "accountId": "1732885739589466112",
3038
+ // "exchangeId": "301",
3039
+ // "symbol": "ETHUSDT",
3040
+ // "symbolName": "ETHUSDT",
3041
+ // "clientOrderId": "1722004623170558",
3042
+ // "orderId": "1738695230608169984",
3043
+ // "price": "0",
3044
+ // "origQty": "0",
3045
+ // "executedQty": "0.0061",
3046
+ // "cummulativeQuoteQty": "19.736489",
3047
+ // "cumulativeQuoteQty": "19.736489",
3048
+ // "avgPrice": "3235.49",
3049
+ // "status": "FILLED",
3050
+ // "timeInForce": "IOC",
3051
+ // "type": "MARKET",
3052
+ // "side": "BUY",
3053
+ // "stopPrice": "0.0",
3054
+ // "icebergQty": "0.0",
3055
+ // "time": "1722004623186",
3056
+ // "updateTime": "1722004623406",
3057
+ // "isWorking": true,
3058
+ // "reqAmount": "20",
3059
+ // "feeCoin": "",
3060
+ // "feeAmount": "0",
3061
+ // "sumFeeAmount": "0"
3062
+ // }
3063
+ //
3064
+ }
3065
+ else if (marketType === 'swap') {
3066
+ let isTrigger = false;
3067
+ [isTrigger, params] = this.handleTriggerOptionAndParams(params, methodName, isTrigger);
3068
+ if (isTrigger) {
3069
+ request['type'] = 'STOP';
3070
+ }
3071
+ response = await this.privateGetApiV1FuturesOrder(this.extend(request, params));
3072
+ //
3073
+ // {
3074
+ // "time": "1722429951611",
3075
+ // "updateTime": "1722429951700",
3076
+ // "orderId": "1742263144028363776",
3077
+ // "clientOrderId": "1722429950315",
3078
+ // "symbol": "ETHUSDT-PERPETUAL",
3079
+ // "price": "3460.62",
3080
+ // "leverage": "5",
3081
+ // "origQty": "10",
3082
+ // "executedQty": "10",
3083
+ // "avgPrice": "3327.52",
3084
+ // "marginLocked": "0",
3085
+ // "type": "LIMIT",
3086
+ // "side": "BUY_OPEN",
3087
+ // "timeInForce": "IOC",
3088
+ // "status": "FILLED",
3089
+ // "priceType": "MARKET",
3090
+ // "isLiquidationOrder": false,
3091
+ // "indexPrice": "0",
3092
+ // "liquidationType": ""
3093
+ // }
3094
+ //
3095
+ }
3096
+ else {
3097
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets');
3098
+ }
3099
+ return this.parseOrder(response);
3100
+ }
3101
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3102
+ /**
3103
+ * @method
3104
+ * @name hashkey#fetchOpenOrders
3105
+ * @description fetch all unfilled currently open orders
3106
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-current-open-orders
3107
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-open-orders
3108
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/sub
3109
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/query-open-futures-orders
3110
+ * @param {string} [symbol] unified market symbol of the market orders were made in - is mandatory for swap markets
3111
+ * @param {int} [since] the earliest time in ms to fetch orders for
3112
+ * @param {int} [limit] the maximum number of order structures to retrieve - default 500, maximum 1000
3113
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3114
+ * @param {string} [params.type] 'spot' or 'swap' - the type of the market to fetch entries for (default 'spot')
3115
+ * @param {string} [params.orderId] *spot markets only* the id of the order to fetch
3116
+ * @param {string} [params.side] *spot markets only* 'buy' or 'sell' - the side of the orders to fetch
3117
+ * @param {string} [params.fromOrderId] *swap markets only* the id of the order to start from
3118
+ * @param {bool} [params.trigger] *swap markets only* true for fetching trigger orders (default false)
3119
+ * @param {bool} [params.stop] *swap markets only* an alternative for trigger param
3120
+ * @param {string} [params.accountId] account id to fetch the orders from
3121
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3122
+ */
3123
+ const methodName = 'fetchOpenOrders';
3124
+ this.checkTypeParam(methodName, params);
3125
+ await this.loadMarkets();
3126
+ let market = undefined;
3127
+ if (symbol !== undefined) {
3128
+ market = this.market(symbol);
3129
+ }
3130
+ let marketType = 'spot';
3131
+ [marketType, params] = this.handleMarketTypeAndParams(methodName, market, params, marketType);
3132
+ params = this.extend({ 'methodName': methodName }, params);
3133
+ if (marketType === 'spot') {
3134
+ return await this.fetchOpenSpotOrders(symbol, since, limit, params);
3135
+ }
3136
+ else if (marketType === 'swap') {
3137
+ return await this.fetchOpenSwapOrders(symbol, since, limit, params);
3138
+ }
3139
+ else {
3140
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets');
3141
+ }
3142
+ }
3143
+ async fetchOpenSpotOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3144
+ /**
3145
+ * @method
3146
+ * @ignore
3147
+ * @name hashkey#fetchOpenSpotOrders
3148
+ * @description fetch all unfilled currently open orders for spot markets
3149
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-current-open-orders
3150
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/sub
3151
+ * @param {string} [symbol] unified market symbol of the market orders were made in
3152
+ * @param {int} [since] the earliest time in ms to fetch orders for
3153
+ * @param {int} [limit] the maximum number of order structures to retrieve - default 500, maximum 1000
3154
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3155
+ * @param {string} [params.orderId] the id of the order to fetch
3156
+ * @param {string} [params.side] 'buy' or 'sell' - the side of the orders to fetch
3157
+ * @param {string} [params.accountId] account id to fetch the orders from
3158
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3159
+ */
3160
+ await this.loadMarkets();
3161
+ let methodName = 'fetchOpenSpotOrders';
3162
+ [methodName, params] = this.handleParamString(params, 'methodName', methodName);
3163
+ let market = undefined;
3164
+ const request = {};
3165
+ let response = undefined;
3166
+ let accountId = undefined;
3167
+ [accountId, params] = this.handleOptionAndParams(params, methodName, 'accountId');
3168
+ if (accountId !== undefined) {
3169
+ request['subAccountId'] = accountId;
3170
+ response = await this.privateGetApiV1SpotSubAccountOpenOrders(this.extend(request, params));
3171
+ }
3172
+ else {
3173
+ if (symbol !== undefined) {
3174
+ market = this.market(symbol);
3175
+ request['symbol'] = market['id'];
3176
+ }
3177
+ if (limit !== undefined) {
3178
+ request['limit'] = limit;
3179
+ }
3180
+ let orderId = undefined;
3181
+ [orderId, params] = this.handleOptionAndParams(params, methodName, 'orderId');
3182
+ if (orderId !== undefined) {
3183
+ request['orderId'] = orderId;
3184
+ }
3185
+ let side = undefined;
3186
+ [side, params] = this.handleOptionAndParams(params, methodName, 'side');
3187
+ if (side !== undefined) {
3188
+ request['side'] = side.toUpperCase();
3189
+ }
3190
+ response = await this.privateGetApiV1SpotOpenOrders(this.extend(request, params));
3191
+ //
3192
+ // [
3193
+ // {
3194
+ // "accountId": "1732885739589466112",
3195
+ // "exchangeId": "301",
3196
+ // "symbol": "ETHUSDT",
3197
+ // "symbolName": "ETHUSDT",
3198
+ // "clientOrderId": "1",
3199
+ // "orderId": "1739491435386897152",
3200
+ // "price": "2000",
3201
+ // "origQty": "0.001",
3202
+ // "executedQty": "0",
3203
+ // "cummulativeQuoteQty": "0",
3204
+ // "cumulativeQuoteQty": "0",
3205
+ // "avgPrice": "0",
3206
+ // "status": "NEW",
3207
+ // "timeInForce": "GTC",
3208
+ // "type": "LIMIT",
3209
+ // "side": "BUY",
3210
+ // "stopPrice": "0.0",
3211
+ // "icebergQty": "0.0",
3212
+ // "time": "1722099538193",
3213
+ // "updateTime": "1722099538197",
3214
+ // "isWorking": true,
3215
+ // "reqAmount": "0"
3216
+ // }
3217
+ // ]
3218
+ //
3219
+ }
3220
+ return this.parseOrders(response, market, since, limit);
3221
+ }
3222
+ async fetchOpenSwapOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3223
+ /**
3224
+ * @method
3225
+ * @ignore
3226
+ * @name hashkey#fetchOpenSwapOrders
3227
+ * @description fetch all unfilled currently open orders for swap markets
3228
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/query-open-futures-orders
3229
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-open-orders
3230
+ * @param {string} symbol *is mandatory* unified market symbol of the market orders were made in
3231
+ * @param {int} [since] the earliest time in ms to fetch orders for
3232
+ * @param {int} [limit] the maximum number of order structures to retrieve - maximum 500
3233
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3234
+ * @param {string} [params.fromOrderId] the id of the order to start from
3235
+ * @param {bool} [params.trigger] true for fetching trigger orders (default false)
3236
+ * @param {bool} [params.stop] an alternative for trigger param
3237
+ * @param {string} [params.accountId] account id to fetch the orders from
3238
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3239
+ */
3240
+ let methodName = 'fetchOpenSwapOrders';
3241
+ [methodName, params] = this.handleParamString(params, 'methodName', methodName);
3242
+ if (symbol === undefined) {
3243
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a symbol argument for swap market orders');
3244
+ }
3245
+ const market = this.market(symbol);
3246
+ const request = {
3247
+ 'symbol': market['id'],
3248
+ };
3249
+ let isTrigger = false;
3250
+ [isTrigger, params] = this.handleTriggerOptionAndParams(params, methodName, isTrigger);
3251
+ if (isTrigger) {
3252
+ request['type'] = 'STOP';
3253
+ }
3254
+ else {
3255
+ request['type'] = 'LIMIT';
3256
+ }
3257
+ if (limit !== undefined) {
3258
+ request['limit'] = limit;
3259
+ }
3260
+ let fromOrderId = undefined;
3261
+ [fromOrderId, params] = this.handleOptionAndParams(params, methodName, 'fromOrderId');
3262
+ if (fromOrderId !== undefined) {
3263
+ request['fromOrderId'] = fromOrderId;
3264
+ }
3265
+ let response = undefined;
3266
+ let accountId = undefined;
3267
+ [accountId, params] = this.handleOptionAndParams(params, methodName, 'accountId');
3268
+ if (accountId !== undefined) {
3269
+ request['subAccountId'] = accountId;
3270
+ response = await this.privateGetApiV1FuturesSubAccountOpenOrders(this.extend(request, params));
3271
+ }
3272
+ else {
3273
+ response = await this.privateGetApiV1FuturesOpenOrders(this.extend(request, params));
3274
+ // 'LIMIT'
3275
+ // [
3276
+ // {
3277
+ // "time": "1722432302919",
3278
+ // "updateTime": "1722432302925",
3279
+ // "orderId": "1742282868229463040",
3280
+ // "clientOrderId": "1722432301670",
3281
+ // "symbol": "ETHUSDT-PERPETUAL",
3282
+ // "price": "4000",
3283
+ // "leverage": "5",
3284
+ // "origQty": "10",
3285
+ // "executedQty": "0",
3286
+ // "avgPrice": "0",
3287
+ // "marginLocked": "0",
3288
+ // "type": "LIMIT_MAKER",
3289
+ // "side": "SELL_CLOSE",
3290
+ // "timeInForce": "GTC",
3291
+ // "status": "NEW",
3292
+ // "priceType": "INPUT",
3293
+ // "isLiquidationOrder": false,
3294
+ // "indexPrice": "0",
3295
+ // "liquidationType": ""
3296
+ // }
3297
+ // ]
3298
+ //
3299
+ // 'STOP'
3300
+ // [
3301
+ // {
3302
+ // "time": "1722433095688",
3303
+ // "updateTime": "1722433095688",
3304
+ // "orderId": "1742289518466225664",
3305
+ // "accountId": "1735619524953226496",
3306
+ // "clientOrderId": "1722433094438",
3307
+ // "symbol": "ETHUSDT-PERPETUAL",
3308
+ // "price": "3700",
3309
+ // "leverage": "0",
3310
+ // "origQty": "10",
3311
+ // "type": "STOP",
3312
+ // "side": "SELL_CLOSE",
3313
+ // "status": "ORDER_NEW",
3314
+ // "stopPrice": "3600"
3315
+ // }
3316
+ // ]
3317
+ }
3318
+ return this.parseOrders(response, market, since, limit);
3319
+ }
3320
+ async fetchCanceledAndClosedOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3321
+ /**
3322
+ * @method
3323
+ * @name hashkey#fetchCanceledAndClosedOrders
3324
+ * @description fetches information on multiple canceled and closed orders made by the user
3325
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-all-orders
3326
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/query-futures-history-orders
3327
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-history-orders
3328
+ * @param {string} symbol *is mandatory for swap markets* unified market symbol of the market orders were made in
3329
+ * @param {int} [since] the earliest time in ms to fetch orders for
3330
+ * @param {int} [limit] the maximum number of order structures to retrieve - default 500, maximum 1000
3331
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3332
+ * @param {int} [params.until] the latest time in ms to fetch entries for - only supports the last 90 days timeframe
3333
+ * @param {string} [params.type] 'spot' or 'swap' - the type of the market to fetch entries for (default 'spot')
3334
+ * @param {string} [params.orderId] *spot markets only* the id of the order to fetch
3335
+ * @param {string} [params.side] *spot markets only* 'buy' or 'sell' - the side of the orders to fetch
3336
+ * @param {string} [params.fromOrderId] *swap markets only* the id of the order to start from
3337
+ * @param {bool} [params.trigger] *swap markets only* the id of the order to start from true for fetching trigger orders (default false)
3338
+ * @param {bool} [params.stop] *swap markets only* the id of the order to start from an alternative for trigger param
3339
+ * @param {string} [params.accountId] account id to fetch the orders from
3340
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
3341
+ */
3342
+ const methodName = 'fetchCanceledAndClosedOrders';
3343
+ this.checkTypeParam(methodName, params);
3344
+ await this.loadMarkets();
3345
+ const request = {};
3346
+ if (limit !== undefined) {
3347
+ request['limit'] = limit;
3348
+ }
3349
+ if (since !== undefined) {
3350
+ request['startTime'] = since;
3351
+ }
3352
+ let until = undefined;
3353
+ [until, params] = this.handleOptionAndParams(params, methodName, 'until');
3354
+ if (until !== undefined) {
3355
+ request['endTime'] = until;
3356
+ }
3357
+ let accountId = undefined;
3358
+ [accountId, params] = this.handleOptionAndParams(params, methodName, 'accountId');
3359
+ let market = undefined;
3360
+ if (symbol !== undefined) {
3361
+ market = this.market(symbol);
3362
+ }
3363
+ let marketType = 'spot';
3364
+ [marketType, params] = this.handleMarketTypeAndParams(methodName, market, params, marketType);
3365
+ let response = undefined;
3366
+ if (marketType === 'spot') {
3367
+ if (market !== undefined) {
3368
+ request['symbol'] = market['id'];
3369
+ }
3370
+ let orderId = undefined;
3371
+ [orderId, params] = this.handleOptionAndParams(params, methodName, 'orderId');
3372
+ if (orderId !== undefined) {
3373
+ request['orderId'] = orderId;
3374
+ }
3375
+ let side = undefined;
3376
+ [side, params] = this.handleOptionAndParams(params, methodName, 'side');
3377
+ if (side !== undefined) {
3378
+ request['side'] = side.toUpperCase();
3379
+ }
3380
+ if (accountId !== undefined) {
3381
+ request['accountId'] = accountId;
3382
+ }
3383
+ response = await this.privateGetApiV1SpotTradeOrders(this.extend(request, params));
3384
+ //
3385
+ // [
3386
+ // {
3387
+ // "accountId": "1732885739589466112",
3388
+ // "exchangeId": "301",
3389
+ // "symbol": "ETHUSDT",
3390
+ // "symbolName": "ETHUSDT",
3391
+ // "clientOrderId": "1722082982086472",
3392
+ // "orderId": "1739352552762301440",
3393
+ // "price": "0",
3394
+ // "origQty": "0.001",
3395
+ // "executedQty": "0.001",
3396
+ // "cummulativeQuoteQty": "3.28996",
3397
+ // "cumulativeQuoteQty": "3.28996",
3398
+ // "avgPrice": "3289.96",
3399
+ // "status": "FILLED",
3400
+ // "timeInForce": "IOC",
3401
+ // "type": "MARKET",
3402
+ // "side": "BUY",
3403
+ // "stopPrice": "0.0",
3404
+ // "icebergQty": "0.0",
3405
+ // "time": "1722082982093",
3406
+ // "updateTime": "1722082982097",
3407
+ // "isWorking": true,
3408
+ // "reqAmount": "0"
3409
+ // },
3410
+ // ...
3411
+ // ]
3412
+ //
3413
+ }
3414
+ else if (marketType === 'swap') {
3415
+ if (symbol === undefined) {
3416
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a symbol argument for swap markets');
3417
+ }
3418
+ request['symbol'] = market['id'];
3419
+ let isTrigger = false;
3420
+ [isTrigger, params] = this.handleTriggerOptionAndParams(params, methodName, isTrigger);
3421
+ if (isTrigger) {
3422
+ request['type'] = 'STOP';
3423
+ }
3424
+ else {
3425
+ request['type'] = 'LIMIT';
3426
+ }
3427
+ let fromOrderId = undefined;
3428
+ [fromOrderId, params] = this.handleOptionAndParams(params, methodName, 'fromOrderId');
3429
+ if (fromOrderId !== undefined) {
3430
+ request['fromOrderId'] = fromOrderId;
3431
+ }
3432
+ if (accountId !== undefined) {
3433
+ request['subAccountId'] = accountId;
3434
+ response = await this.privateGetApiV1FuturesSubAccountHistoryOrders(this.extend(request, params));
3435
+ }
3436
+ else {
3437
+ response = await this.privateGetApiV1FuturesHistoryOrders(this.extend(request, params));
3438
+ //
3439
+ // [
3440
+ // {
3441
+ // "time": "1722429951611",
3442
+ // "updateTime": "1722429951700",
3443
+ // "orderId": "1742263144028363776",
3444
+ // "clientOrderId": "1722429950315",
3445
+ // "symbol": "ETHUSDT-PERPETUAL",
3446
+ // "price": "3460.62",
3447
+ // "leverage": "5",
3448
+ // "origQty": "10",
3449
+ // "executedQty": "10",
3450
+ // "avgPrice": "3327.52",
3451
+ // "marginLocked": "0",
3452
+ // "type": "LIMIT",
3453
+ // "side": "BUY_OPEN",
3454
+ // "timeInForce": "IOC",
3455
+ // "status": "FILLED",
3456
+ // "priceType": "MARKET",
3457
+ // "isLiquidationOrder": false,
3458
+ // "indexPrice": "0",
3459
+ // "liquidationType": ""
3460
+ // }
3461
+ // ]
3462
+ //
3463
+ }
3464
+ }
3465
+ else {
3466
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets');
3467
+ }
3468
+ return this.parseOrders(response, market, since, limit);
3469
+ }
3470
+ checkTypeParam(methodName, params) {
3471
+ // some hashkey endpoints have a type param for swap markets that defines the type of an order
3472
+ // type param is reserved in ccxt for defining the type of the market
3473
+ // current method warns user if he provides the exchange specific value in type parameter
3474
+ const paramsType = this.safeString(params, 'type');
3475
+ if ((paramsType !== undefined) && (paramsType !== 'spot') && (paramsType !== 'swap')) {
3476
+ throw new BadRequest(this.id + ' ' + methodName + ' () type parameter can not be "' + paramsType + '". It should define the type of the market ("spot" or "swap"). To define the type of an order use the trigger parameter (true for trigger orders)');
3477
+ }
3478
+ }
3479
+ handleTriggerOptionAndParams(params, methodName, defaultValue = undefined) {
3480
+ let isStop = defaultValue;
3481
+ [isStop, params] = this.handleOptionAndParams(params, methodName, 'stop', isStop);
3482
+ let isTrigger = isStop;
3483
+ [isTrigger, params] = this.handleOptionAndParams(params, methodName, 'trigger', isTrigger);
3484
+ return [isTrigger, params];
3485
+ }
3486
+ parseOrder(order, market = undefined) {
3487
+ //
3488
+ // createOrder spot
3489
+ // {
3490
+ // "accountId": "1732885739589466112",
3491
+ // "symbol": "ETHUSDT",
3492
+ // "symbolName": "ETHUSDT",
3493
+ // "clientOrderId": "1722004623170558",
3494
+ // "orderId": "1738695230608169984",
3495
+ // "transactTime": "1722004623186",
3496
+ // "price": "0",
3497
+ // "origQty": "0",
3498
+ // "executedQty": "0.0061",
3499
+ // "status": "FILLED",
3500
+ // "timeInForce": "IOC",
3501
+ // "type": "MARKET",
3502
+ // "side": "BUY",
3503
+ // "reqAmount": "20",
3504
+ // "concentration": ""
3505
+ // }
3506
+ //
3507
+ // fetchOrder spot
3508
+ // {
3509
+ // "accountId": "1732885739589466112",
3510
+ // "exchangeId": "301",
3511
+ // "symbol": "ETHUSDT",
3512
+ // "symbolName": "ETHUSDT",
3513
+ // "clientOrderId": "1722004623170558",
3514
+ // "orderId": "1738695230608169984",
3515
+ // "price": "0",
3516
+ // "origQty": "0",
3517
+ // "executedQty": "0.0061",
3518
+ // "cummulativeQuoteQty": "19.736489",
3519
+ // "cumulativeQuoteQty": "19.736489",
3520
+ // "avgPrice": "3235.49",
3521
+ // "status": "FILLED",
3522
+ // "timeInForce": "IOC",
3523
+ // "type": "MARKET",
3524
+ // "side": "BUY",
3525
+ // "stopPrice": "0.0",
3526
+ // "icebergQty": "0.0",
3527
+ // "time": "1722004623186",
3528
+ // "updateTime": "1722004623406",
3529
+ // "isWorking": true,
3530
+ // "reqAmount": "20",
3531
+ // "feeCoin": "",
3532
+ // "feeAmount": "0",
3533
+ // "sumFeeAmount": "0"
3534
+ // }
3535
+ //
3536
+ // cancelOrder
3537
+ // {
3538
+ // "accountId": "1732885739589466112",
3539
+ // "symbol": "ETHUSDT",
3540
+ // "clientOrderId": "1722006209978370",
3541
+ // "orderId": "1738708541676585728",
3542
+ // "transactTime": "1722006209989",
3543
+ // "price": "5000",
3544
+ // "origQty": "0.005",
3545
+ // "executedQty": "0",
3546
+ // "status": "NEW",
3547
+ // "timeInForce": "GTC",
3548
+ // "type": "LIMIT_MAKER",
3549
+ // "side": "SELL"
3550
+ // }
3551
+ //
3552
+ // createOrder swap
3553
+ // {
3554
+ // "time": "1722429951611",
3555
+ // "updateTime": "1722429951648",
3556
+ // "orderId": "1742263144028363776",
3557
+ // "clientOrderId": "1722429950315",
3558
+ // "symbol": "ETHUSDT-PERPETUAL",
3559
+ // "price": "3460.62",
3560
+ // "leverage": "5",
3561
+ // "origQty": "10",
3562
+ // "executedQty": "10",
3563
+ // "avgPrice": "0",
3564
+ // "marginLocked": "6.9212",
3565
+ // "type": "LIMIT",
3566
+ // "side": "BUY_OPEN",
3567
+ // "timeInForce": "IOC",
3568
+ // "status": "FILLED",
3569
+ // "priceType": "MARKET",
3570
+ // "contractMultiplier": "0.00100000"
3571
+ // }
3572
+ //
3573
+ // fetchOrder swap
3574
+ // {
3575
+ // "time": "1722429951611",
3576
+ // "updateTime": "1722429951700",
3577
+ // "orderId": "1742263144028363776",
3578
+ // "clientOrderId": "1722429950315",
3579
+ // "symbol": "ETHUSDT-PERPETUAL",
3580
+ // "price": "3460.62",
3581
+ // "leverage": "5",
3582
+ // "origQty": "10",
3583
+ // "executedQty": "10",
3584
+ // "avgPrice": "3327.52",
3585
+ // "marginLocked": "0",
3586
+ // "type": "LIMIT",
3587
+ // "side": "BUY_OPEN",
3588
+ // "timeInForce": "IOC",
3589
+ // "status": "FILLED",
3590
+ // "priceType": "MARKET",
3591
+ // "isLiquidationOrder": false,
3592
+ // "indexPrice": "0",
3593
+ // "liquidationType": ""
3594
+ // }
3595
+ //
3596
+ const marketId = this.safeString(order, 'symbol');
3597
+ market = this.safeMarket(marketId, market);
3598
+ const timestamp = this.safeInteger2(order, 'transactTime', 'time');
3599
+ const status = this.safeString(order, 'status');
3600
+ let type = this.safeString(order, 'type');
3601
+ const priceType = this.safeString(order, 'priceType');
3602
+ if (priceType === 'MARKET') {
3603
+ type = 'market';
3604
+ }
3605
+ let price = this.omitZero(this.safeString(order, 'price'));
3606
+ if (type === 'STOP') {
3607
+ if (price === undefined) {
3608
+ type = 'market';
3609
+ }
3610
+ else {
3611
+ type = 'limit';
3612
+ }
3613
+ }
3614
+ let timeInForce = this.safeString(order, 'timeInForce');
3615
+ let postOnly = undefined;
3616
+ [type, timeInForce, postOnly] = this.parseOrderTypeTimeInForceAndPostOnly(type, timeInForce);
3617
+ const average = this.omitZero(this.safeString(order, 'avgPrice'));
3618
+ if (price === undefined) {
3619
+ price = average;
3620
+ }
3621
+ let side = this.safeStringLower(order, 'side');
3622
+ let reduceOnly = undefined;
3623
+ [side, reduceOnly] = this.parseOrderSideAndReduceOnly(side);
3624
+ let feeCurrncyId = this.safeString(order, 'feeCoin');
3625
+ if (feeCurrncyId === '') {
3626
+ feeCurrncyId = undefined;
3627
+ }
3628
+ const triggerPrice = this.omitZero(this.safeString(order, 'stopPrice'));
3629
+ return this.safeOrder({
3630
+ 'id': this.safeString(order, 'orderId'),
3631
+ 'clientOrderId': this.safeString(order, 'clientOrderId'),
3632
+ 'datetime': this.iso8601(timestamp),
3633
+ 'timestamp': timestamp,
3634
+ 'lastTradeTimestamp': undefined,
3635
+ 'lastUpdateTimestamp': this.safeInteger(order, 'updateTime'),
3636
+ 'status': this.parseOrderStatus(status),
3637
+ 'symbol': market['symbol'],
3638
+ 'type': type,
3639
+ 'timeInForce': timeInForce,
3640
+ 'side': side,
3641
+ 'price': price,
3642
+ 'average': average,
3643
+ 'amount': this.omitZero(this.safeString(order, 'origQty')),
3644
+ 'filled': this.safeString(order, 'executedQty'),
3645
+ 'remaining': undefined,
3646
+ 'stopPrice': triggerPrice,
3647
+ 'triggerPrice': triggerPrice,
3648
+ 'takeProfitPrice': undefined,
3649
+ 'stopLossPrice': undefined,
3650
+ 'cost': this.omitZero(this.safeString2(order, 'cumulativeQuoteQty', 'cummulativeQuoteQty')),
3651
+ 'trades': undefined,
3652
+ 'fee': {
3653
+ 'currency': this.safeCurrencyCode(feeCurrncyId),
3654
+ 'amount': this.omitZero(this.safeString(order, 'feeAmount')),
3655
+ },
3656
+ 'reduceOnly': reduceOnly,
3657
+ 'postOnly': postOnly,
3658
+ 'info': order,
3659
+ }, market);
3660
+ }
3661
+ parseOrderSideAndReduceOnly(unparsed) {
3662
+ const parts = unparsed.split('_');
3663
+ const side = parts[0];
3664
+ let reduceOnly = undefined;
3665
+ const secondPart = this.safeString(parts, 1);
3666
+ if (secondPart !== undefined) {
3667
+ if (secondPart === 'open') {
3668
+ reduceOnly = false;
3669
+ }
3670
+ else if ((secondPart === 'close')) {
3671
+ reduceOnly = true;
3672
+ }
3673
+ }
3674
+ return [side, reduceOnly];
3675
+ }
3676
+ parseOrderStatus(status) {
3677
+ const statuses = {
3678
+ 'NEW': 'open',
3679
+ 'PARTIALLY_FILLED': 'open',
3680
+ 'PARTIALLY_CANCELED': 'canceled',
3681
+ 'FILLED': 'closed',
3682
+ 'CANCELED': 'canceled',
3683
+ 'ORDER_CANCELED': 'canceled',
3684
+ 'PENDING_CANCEL': 'canceled',
3685
+ 'REJECTED': 'rejected',
3686
+ 'ORDER_NEW': 'open',
3687
+ };
3688
+ return this.safeString(statuses, status, status);
3689
+ }
3690
+ parseOrderTypeTimeInForceAndPostOnly(type, timeInForce) {
3691
+ let postOnly = undefined;
3692
+ if (type === 'LIMIT_MAKER') {
3693
+ postOnly = true;
3694
+ }
3695
+ else if ((timeInForce === 'LIMIT_MAKER') || (timeInForce === 'MAKER')) {
3696
+ postOnly = true;
3697
+ timeInForce = 'PO';
3698
+ }
3699
+ type = this.parseOrderType(type);
3700
+ return [type, timeInForce, postOnly];
3701
+ }
3702
+ parseOrderType(type) {
3703
+ const types = {
3704
+ 'MARKET': 'market',
3705
+ 'LIMIT': 'limit',
3706
+ 'LIMIT_MAKER': 'limit',
3707
+ 'MARKET_OF_BASE': 'market',
3708
+ };
3709
+ return this.safeString(types, type, type);
3710
+ }
3711
+ async fetchFundingRate(symbol, params = {}) {
3712
+ /**
3713
+ * @method
3714
+ * @name hashkey#fetchFundingRate
3715
+ * @description fetch the current funding rate
3716
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-futures-funding-rate
3717
+ * @param {string} symbol unified market symbol
3718
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3719
+ * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
3720
+ */
3721
+ await this.loadMarkets();
3722
+ const market = this.market(symbol);
3723
+ const request = {
3724
+ 'symbol': market['id'],
3725
+ 'timestamp': this.milliseconds(),
3726
+ };
3727
+ const response = await this.publicGetApiV1FuturesFundingRate(this.extend(request, params));
3728
+ //
3729
+ // [
3730
+ // { "symbol": "ETHUSDT-PERPETUAL", "rate": "0.0001", "nextSettleTime": "1722297600000" }
3731
+ // ]
3732
+ //
3733
+ const rate = this.safeDict(response, 0, {});
3734
+ return this.parseFundingRate(rate, market);
3735
+ }
3736
+ async fetchFundingRates(symbols = undefined, params = {}) {
3737
+ /**
3738
+ * @method
3739
+ * @name hashkey#fetchFundingRates
3740
+ * @description fetch the funding rate for multiple markets
3741
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-futures-funding-rate
3742
+ * @param {string[]|undefined} symbols list of unified market symbols
3743
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3744
+ * @returns {object} a dictionary of [funding rates structures]{@link https://docs.ccxt.com/#/?id=funding-rates-structure}, indexe by market symbols
3745
+ */
3746
+ await this.loadMarkets();
3747
+ symbols = this.marketSymbols(symbols);
3748
+ const request = {
3749
+ 'timestamp': this.milliseconds(),
3750
+ };
3751
+ const response = await this.publicGetApiV1FuturesFundingRate(this.extend(request, params));
3752
+ //
3753
+ // [
3754
+ // { "symbol": "BTCUSDT-PERPETUAL", "rate": "0.0001", "nextSettleTime": "1722297600000" },
3755
+ // { "symbol": "ETHUSDT-PERPETUAL", "rate": "0.0001", "nextSettleTime": "1722297600000" }
3756
+ // ]
3757
+ //
3758
+ const fundingRates = this.parseFundingRates(response);
3759
+ return this.filterByArray(fundingRates, 'symbol', symbols);
3760
+ }
3761
+ parseFundingRate(contract, market = undefined) {
3762
+ //
3763
+ // fetchFundingRates
3764
+ // {
3765
+ // "symbol": "ETHUSDT-PERPETUAL",
3766
+ // "rate": "0.0001",
3767
+ // "nextSettleTime": "1722297600000"
3768
+ // }
3769
+ //
3770
+ const marketId = this.safeString(contract, 'symbol');
3771
+ market = this.safeMarket(marketId, market, undefined, 'swap');
3772
+ const fundingRate = this.safeNumber(contract, 'rate');
3773
+ const fundingTimestamp = this.safeInteger(contract, 'nextSettleTime');
3774
+ return {
3775
+ 'info': contract,
3776
+ 'symbol': market['symbol'],
3777
+ 'markPrice': undefined,
3778
+ 'indexPrice': undefined,
3779
+ 'interestRate': undefined,
3780
+ 'estimatedSettlePrice': undefined,
3781
+ 'timestamp': undefined,
3782
+ 'datetime': undefined,
3783
+ 'fundingRate': fundingRate,
3784
+ 'fundingTimestamp': undefined,
3785
+ 'fundingDatetime': undefined,
3786
+ 'nextFundingRate': undefined,
3787
+ 'nextFundingTimestamp': fundingTimestamp,
3788
+ 'nextFundingDatetime': this.iso8601(fundingTimestamp),
3789
+ 'previousFundingRate': undefined,
3790
+ 'previousFundingTimestamp': undefined,
3791
+ 'previousFundingDatetime': undefined,
3792
+ };
3793
+ }
3794
+ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
3795
+ /**
3796
+ * @method
3797
+ * @name hashkey#fetchFundingRateHistory
3798
+ * @description fetches historical funding rate prices
3799
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-futures-history-funding-rate
3800
+ * @param {string} symbol unified symbol of the market to fetch the funding rate history for
3801
+ * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
3802
+ * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
3803
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3804
+ * @param {int} [params.fromId] the id of the entry to start from
3805
+ * @param {int} [params.endId] the id of the entry to end with
3806
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
3807
+ */
3808
+ await this.loadMarkets();
3809
+ if (symbol === undefined) {
3810
+ throw new ArgumentsRequired(this.id + ' fetchFundingRateHistory() requires a symbol argument');
3811
+ }
3812
+ const market = this.market(symbol);
3813
+ const request = {
3814
+ 'symbol': market['id'],
3815
+ };
3816
+ if (limit !== undefined) {
3817
+ request['limit'] = limit;
3818
+ }
3819
+ const response = await this.publicGetApiV1FuturesHistoryFundingRate(this.extend(request, params));
3820
+ //
3821
+ // [
3822
+ // {
3823
+ // "id": "10698",
3824
+ // "symbol": "ETHUSDT-PERPETUAL",
3825
+ // "settleTime": "1722268800000",
3826
+ // "settleRate": "0.0001"
3827
+ // },
3828
+ // ...
3829
+ // ]
3830
+ //
3831
+ const rates = [];
3832
+ for (let i = 0; i < response.length; i++) {
3833
+ const entry = response[i];
3834
+ const timestamp = this.safeInteger(entry, 'settleTime');
3835
+ rates.push({
3836
+ 'info': entry,
3837
+ 'symbol': this.safeSymbol(this.safeString(entry, 'symbol'), market, undefined, 'swap'),
3838
+ 'fundingRate': this.safeNumber(entry, 'settleRate'),
3839
+ 'timestamp': timestamp,
3840
+ 'datetime': this.iso8601(timestamp),
3841
+ });
3842
+ }
3843
+ const sorted = this.sortBy(rates, 'timestamp');
3844
+ return this.filterBySinceLimit(sorted, since, limit);
3845
+ }
3846
+ async fetchPositions(symbols = undefined, params = {}) {
3847
+ /**
3848
+ * @method
3849
+ * @description fetch open positions for a market
3850
+ * @name hashkey#fetchPositions
3851
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-futures-positions
3852
+ * @description fetch all open positions
3853
+ * @param {string[]|undefined} symbols list of unified market symbols
3854
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3855
+ * @param {string} [params.side] 'LONG' or 'SHORT' - the direction of the position (if not provided, positions for both sides will be returned)
3856
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
3857
+ */
3858
+ const methodName = 'fetchPositions';
3859
+ if ((symbols === undefined)) {
3860
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() requires a symbol argument with one single market symbol');
3861
+ }
3862
+ else {
3863
+ const symbolsLength = symbols.length;
3864
+ if (symbolsLength !== 1) {
3865
+ throw new NotSupported(this.id + ' ' + methodName + '() is supported for a symbol argument with one single market symbol only');
3866
+ }
3867
+ }
3868
+ await this.loadMarkets();
3869
+ return await this.fetchPositionsForSymbol(symbols[0], this.extend({ 'methodName': 'fetchPositions' }, params));
3870
+ }
3871
+ async fetchPositionsForSymbol(symbol, params = {}) {
3872
+ /**
3873
+ * @method
3874
+ * @description fetch open positions for a single market
3875
+ * @name hashkey#fetchPositionsForSymbol
3876
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-futures-positions
3877
+ * @description fetch all open positions for specific symbol
3878
+ * @param {string} symbol unified market symbol
3879
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3880
+ * @param {string} [params.side] 'LONG' or 'SHORT' - the direction of the position (if not provided, positions for both sides will be returned)
3881
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
3882
+ */
3883
+ await this.loadMarkets();
3884
+ const market = this.market(symbol);
3885
+ let methodName = 'fetchPosition';
3886
+ [methodName, params] = this.handleParamString(params, 'methodName', methodName);
3887
+ if (!market['swap']) {
3888
+ throw new NotSupported(this.id + ' ' + methodName + '() supports swap markets only');
3889
+ }
3890
+ const request = {
3891
+ 'symbol': market['id'],
3892
+ };
3893
+ let side = undefined;
3894
+ [side, params] = this.handleOptionAndParams(params, methodName, 'side');
3895
+ if (side !== undefined) {
3896
+ request['side'] = side.toUpperCase();
3897
+ }
3898
+ const response = await this.privateGetApiV1FuturesPositions(this.extend(request, params));
3899
+ //
3900
+ // [
3901
+ // {
3902
+ // "symbol": "ETHUSDT-PERPETUAL",
3903
+ // "side": "LONG",
3904
+ // "avgPrice": "3327.52",
3905
+ // "position": "10",
3906
+ // "available": "0",
3907
+ // "leverage": "5",
3908
+ // "lastPrice": "3324.44",
3909
+ // "positionValue": "33.2752",
3910
+ // "liquidationPrice": "-953.83",
3911
+ // "margin": "6.9012",
3912
+ // "marginRate": "",
3913
+ // "unrealizedPnL": "-0.0288",
3914
+ // "profitRate": "-0.0041",
3915
+ // "realizedPnL": "-0.0199",
3916
+ // "minMargin": "0.2173"
3917
+ // }
3918
+ // ]
3919
+ //
3920
+ return this.parsePositions(response, [symbol]);
3921
+ }
3922
+ parsePosition(position, market = undefined) {
3923
+ const marketId = this.safeString(position, 'symbol');
3924
+ market = this.safeMarket(marketId, market);
3925
+ const symbol = market['symbol'];
3926
+ return this.safePosition({
3927
+ 'symbol': symbol,
3928
+ 'id': undefined,
3929
+ 'timestamp': undefined,
3930
+ 'datetime': undefined,
3931
+ 'contracts': this.safeNumber(position, 'position'),
3932
+ 'contractSize': undefined,
3933
+ 'side': this.safeStringLower(position, 'side'),
3934
+ 'notional': this.safeNumber(position, 'positionValue'),
3935
+ 'leverage': this.safeInteger(position, 'leverage'),
3936
+ 'unrealizedPnl': this.safeNumber(position, 'unrealizedPnL'),
3937
+ 'realizedPnl': this.safeNumber(position, 'realizedPnL'),
3938
+ 'collateral': undefined,
3939
+ 'entryPrice': this.safeNumber(position, 'avgPrice'),
3940
+ 'markPrice': undefined,
3941
+ 'liquidationPrice': this.safeNumber(position, 'liquidationPrice'),
3942
+ 'marginMode': 'cross',
3943
+ 'hedged': true,
3944
+ 'maintenanceMargin': this.safeNumber(position, 'minMargin'),
3945
+ 'maintenanceMarginPercentage': undefined,
3946
+ 'initialMargin': this.safeNumber(position, 'margin'),
3947
+ 'initialMarginPercentage': undefined,
3948
+ 'marginRatio': undefined,
3949
+ 'lastUpdateTimestamp': undefined,
3950
+ 'lastPrice': this.safeNumber(position, 'lastPrice'),
3951
+ 'stopLossPrice': undefined,
3952
+ 'takeProfitPrice': undefined,
3953
+ 'percentage': undefined,
3954
+ 'info': position,
3955
+ });
3956
+ }
3957
+ async fetchLeverage(symbol, params = {}) {
3958
+ /**
3959
+ * @method
3960
+ * @name hashkey#fetchLeverage
3961
+ * @description fetch the set leverage for a market
3962
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/query-futures-leverage-trade
3963
+ * @param {string} symbol unified market symbol
3964
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3965
+ * @returns {object} a [leverage structure]{@link https://docs.ccxt.com/#/?id=leverage-structure}
3966
+ */
3967
+ await this.loadMarkets();
3968
+ const market = this.market(symbol);
3969
+ const request = {
3970
+ 'symbol': market['id'],
3971
+ };
3972
+ const response = await this.privateGetApiV1FuturesLeverage(this.extend(request, params));
3973
+ //
3974
+ // [
3975
+ // {
3976
+ // "symbolId": "ETHUSDT-PERPETUAL",
3977
+ // "leverage": "5",
3978
+ // "marginType": "CROSS"
3979
+ // }
3980
+ // ]
3981
+ //
3982
+ const leverage = this.safeDict(response, 0, {});
3983
+ return this.parseLeverage(leverage, market);
3984
+ }
3985
+ parseLeverage(leverage, market = undefined) {
3986
+ const marginMode = this.safeStringLower(leverage, 'marginType');
3987
+ const leverageValue = this.safeNumber(leverage, 'leverage');
3988
+ return {
3989
+ 'info': leverage,
3990
+ 'symbol': market['symbol'],
3991
+ 'marginMode': marginMode,
3992
+ 'longLeverage': leverageValue,
3993
+ 'shortLeverage': leverageValue,
3994
+ };
3995
+ }
3996
+ async setLeverage(leverage, symbol = undefined, params = {}) {
3997
+ /**
3998
+ * @method
3999
+ * @name hashkey#setLeverage
4000
+ * @description set the level of leverage for a market
4001
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/change-futures-leverage-trade
4002
+ * @param {float} leverage the rate of leverage
4003
+ * @param {string} symbol unified market symbol
4004
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
4005
+ * @returns {object} response from the exchange
4006
+ */
4007
+ if (symbol === undefined) {
4008
+ throw new ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
4009
+ }
4010
+ await this.loadMarkets();
4011
+ const request = {
4012
+ 'leverage': leverage,
4013
+ };
4014
+ const market = this.market(symbol);
4015
+ request['symbol'] = market['id'];
4016
+ const response = await this.privatePostApiV1FuturesLeverage(this.extend(request, params));
4017
+ //
4018
+ // {
4019
+ // "code": "0000",
4020
+ // "symbolId": "ETHUSDT-PERPETUAL",
4021
+ // "leverage": "3"
4022
+ // }
4023
+ //
4024
+ return this.parseLeverage(response, market);
4025
+ }
4026
+ async fetchLeverageTiers(symbols = undefined, params = {}) {
4027
+ /**
4028
+ * @method
4029
+ * @name hashkey#fetchLeverageTiers
4030
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/exchangeinfo
4031
+ * @description retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
4032
+ * @param {string[]|undefined} symbols list of unified market symbols
4033
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
4034
+ * @returns {object} a dictionary of [leverage tiers structures]{@link https://docs.ccxt.com/#/?id=leverage-tiers-structure}, indexed by market symbols
4035
+ */
4036
+ await this.loadMarkets();
4037
+ const response = await this.publicGetApiV1ExchangeInfo(params);
4038
+ // response is the same as in fetchMarkets()
4039
+ const data = this.safeList(response, 'contracts', []);
4040
+ symbols = this.marketSymbols(symbols);
4041
+ return this.parseLeverageTiers(data, symbols, 'symbol');
4042
+ }
4043
+ parseMarketLeverageTiers(info, market = undefined) {
4044
+ //
4045
+ // {
4046
+ // "filters": [
4047
+ // {
4048
+ // "minPrice": "0.1",
4049
+ // "maxPrice": "100000.00000000",
4050
+ // "tickSize": "0.1",
4051
+ // "filterType": "PRICE_FILTER"
4052
+ // },
4053
+ // {
4054
+ // "minQty": "0.001",
4055
+ // "maxQty": "10",
4056
+ // "stepSize": "0.001",
4057
+ // "marketOrderMinQty": "0",
4058
+ // "marketOrderMaxQty": "0",
4059
+ // "filterType": "LOT_SIZE"
4060
+ // },
4061
+ // {
4062
+ // "minNotional": "0",
4063
+ // "filterType": "MIN_NOTIONAL"
4064
+ // },
4065
+ // {
4066
+ // "maxSellPrice": "999999",
4067
+ // "buyPriceUpRate": "0.05",
4068
+ // "sellPriceDownRate": "0.05",
4069
+ // "maxEntrustNum": 200,
4070
+ // "maxConditionNum": 200,
4071
+ // "filterType": "LIMIT_TRADING"
4072
+ // },
4073
+ // {
4074
+ // "buyPriceUpRate": "0.05",
4075
+ // "sellPriceDownRate": "0.05",
4076
+ // "filterType": "MARKET_TRADING"
4077
+ // },
4078
+ // {
4079
+ // "noAllowMarketStartTime": "0",
4080
+ // "noAllowMarketEndTime": "0",
4081
+ // "limitOrderStartTime": "0",
4082
+ // "limitOrderEndTime": "0",
4083
+ // "limitMinPrice": "0",
4084
+ // "limitMaxPrice": "0",
4085
+ // "filterType": "OPEN_QUOTE"
4086
+ // }
4087
+ // ],
4088
+ // "exchangeId": "301",
4089
+ // "symbol": "BTCUSDT-PERPETUAL",
4090
+ // "symbolName": "BTCUSDT-PERPETUAL",
4091
+ // "status": "TRADING",
4092
+ // "baseAsset": "BTCUSDT-PERPETUAL",
4093
+ // "baseAssetPrecision": "0.001",
4094
+ // "quoteAsset": "USDT",
4095
+ // "quoteAssetPrecision": "0.1",
4096
+ // "icebergAllowed": false,
4097
+ // "inverse": false,
4098
+ // "index": "USDT",
4099
+ // "marginToken": "USDT",
4100
+ // "marginPrecision": "0.0001",
4101
+ // "contractMultiplier": "0.001",
4102
+ // "underlying": "BTC",
4103
+ // "riskLimits": [
4104
+ // {
4105
+ // "riskLimitId": "200000722",
4106
+ // "quantity": "1000.00",
4107
+ // "initialMargin": "0.10",
4108
+ // "maintMargin": "0.005",
4109
+ // "isWhite": false
4110
+ // },
4111
+ // {
4112
+ // "riskLimitId": "200000723",
4113
+ // "quantity": "2000.00",
4114
+ // "initialMargin": "0.10",
4115
+ // "maintMargin": "0.01",
4116
+ // "isWhite": false
4117
+ // }
4118
+ // ]
4119
+ // }
4120
+ //
4121
+ const riskLimits = this.safeList(info, 'riskLimits', []);
4122
+ const id = this.safeString(info, 'symbol');
4123
+ market = this.safeMarket(id, market);
4124
+ const tiers = [];
4125
+ for (let i = 0; i < riskLimits.length; i++) {
4126
+ const tier = riskLimits[i];
4127
+ const initialMarginRate = this.safeString(tier, 'initialMargin');
4128
+ tiers.push({
4129
+ 'tier': this.sum(i, 1),
4130
+ 'currency': market['settle'],
4131
+ 'minNotional': undefined,
4132
+ 'maxNotional': this.safeNumber(tier, 'quantity'),
4133
+ 'maintenanceMarginRate': this.safeNumber(tier, 'maintMargin'),
4134
+ 'maxLeverage': this.parseNumber(Precise.stringDiv('1', initialMarginRate)),
4135
+ 'info': tier,
4136
+ });
4137
+ }
4138
+ return tiers;
4139
+ }
4140
+ async fetchTradingFee(symbol, params = {}) {
4141
+ /**
4142
+ * @method
4143
+ * @name hashkey#fetchTradingFee
4144
+ * @description fetch the trading fees for a market
4145
+ * @see https://developers.binance.com/docs/wallet/asset/trade-fee // spot
4146
+ * @see https://hashkeyglobal-apidoc.readme.io/reference/get-futures-commission-rate-request-weight // swap
4147
+ * @param {string} symbol unified market symbol
4148
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
4149
+ * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
4150
+ */
4151
+ await this.loadMarkets();
4152
+ const market = this.market(symbol);
4153
+ const methodName = 'fetchTradingFee';
4154
+ let response = undefined;
4155
+ if (market['spot']) {
4156
+ response = await this.fetchTradingFees(params);
4157
+ return this.safeDict(response, symbol);
4158
+ }
4159
+ else if (market['swap']) {
4160
+ response = await this.privateGetApiV1FuturesCommissionRate(this.extend({ 'symbol': market['id'] }, params));
4161
+ return this.parseTradingFee(response, market);
4162
+ //
4163
+ // {
4164
+ // "openMakerFee": "0.00025",
4165
+ // "openTakerFee": "0.0006",
4166
+ // "closeMakerFee": "0.00025",
4167
+ // "closeTakerFee": "0.0006"
4168
+ // }
4169
+ //
4170
+ }
4171
+ else {
4172
+ throw new NotSupported(this.id + ' ' + methodName + '() is not supported for ' + market['type'] + ' type of markets');
4173
+ }
4174
+ }
4175
+ async fetchTradingFees(params = {}) {
4176
+ /**
4177
+ * @method
4178
+ * @name binance#fetchTradingFees
4179
+ * @description *for spot markets only* fetch the trading fees for multiple markets
4180
+ * @see https://developers.binance.com/docs/wallet/asset/trade-fee
4181
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
4182
+ * @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
4183
+ */
4184
+ await this.loadMarkets();
4185
+ const response = await this.privateGetApiV1AccountVipInfo(params);
4186
+ //
4187
+ // {
4188
+ // "code": 0,
4189
+ // "vipLevel": "0",
4190
+ // "tradeVol30Day": "67",
4191
+ // "totalAssetBal": "0",
4192
+ // "data": [
4193
+ // {
4194
+ // "symbol": "UXLINKUSDT",
4195
+ // "productType": "Token-Token",
4196
+ // "buyMakerFeeCurrency": "UXLINK",
4197
+ // "buyTakerFeeCurrency": "UXLINK",
4198
+ // "sellMakerFeeCurrency": "USDT",
4199
+ // "sellTakerFeeCurrency": "USDT",
4200
+ // "actualMakerRate": "0.0012",
4201
+ // "actualTakerRate": "0.0012"
4202
+ // },
4203
+ // ...
4204
+ // ],
4205
+ // "updateTimestamp": "1722320137809"
4206
+ // }
4207
+ //
4208
+ const data = this.safeList(response, 'data', []);
4209
+ const result = {};
4210
+ for (let i = 0; i < data.length; i++) {
4211
+ const fee = this.safeDict(data, i, {});
4212
+ const parsedFee = this.parseTradingFee(fee);
4213
+ result[parsedFee['symbol']] = parsedFee;
4214
+ }
4215
+ return result;
4216
+ }
4217
+ parseTradingFee(fee, market = undefined) {
4218
+ //
4219
+ // spot
4220
+ // {
4221
+ // "symbol": "UXLINKUSDT",
4222
+ // "productType": "Token-Token",
4223
+ // "buyMakerFeeCurrency": "UXLINK",
4224
+ // "buyTakerFeeCurrency": "UXLINK",
4225
+ // "sellMakerFeeCurrency": "USDT",
4226
+ // "sellTakerFeeCurrency": "USDT",
4227
+ // "actualMakerRate": "0.0012",
4228
+ // "actualTakerRate": "0.0012"
4229
+ // }
4230
+ //
4231
+ // swap
4232
+ // {
4233
+ // "openMakerFee": "0.00025",
4234
+ // "openTakerFee": "0.0006",
4235
+ // "closeMakerFee": "0.00025",
4236
+ // "closeTakerFee": "0.0006"
4237
+ // }
4238
+ //
4239
+ const marketId = this.safeString(fee, 'symbol');
4240
+ market = this.safeMarket(marketId, market);
4241
+ return {
4242
+ 'info': fee,
4243
+ 'symbol': market['symbol'],
4244
+ 'maker': this.safeNumber2(fee, 'openMakerFee', 'actualMakerRate'),
4245
+ 'taker': this.safeNumber2(fee, 'openTakerFee', 'actualTakerRate'),
4246
+ 'percentage': true,
4247
+ 'tierBased': true,
4248
+ };
4249
+ }
4250
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
4251
+ let url = this.urls['api'][api] + '/' + path;
4252
+ let query = undefined;
4253
+ if (api === 'private') {
4254
+ this.checkRequiredCredentials();
4255
+ const timestamp = this.milliseconds();
4256
+ const additionalParams = {
4257
+ 'timestamp': timestamp,
4258
+ };
4259
+ const recvWindow = this.safeInteger(this.options, 'recvWindow');
4260
+ if (recvWindow !== undefined) {
4261
+ additionalParams['recvWindow'] = recvWindow;
4262
+ }
4263
+ headers = {
4264
+ 'X-HK-APIKEY': this.apiKey,
4265
+ 'Content-Type': 'application/x-www-form-urlencoded',
4266
+ };
4267
+ let signature = undefined;
4268
+ if ((method === 'POST') && ((path === 'api/v1/spot/batchOrders') || (path === 'api/v1/futures/batchOrders'))) {
4269
+ headers['Content-Type'] = 'application/json';
4270
+ body = this.json(this.safeList(params, 'orders'));
4271
+ signature = this.hmac(this.encode(this.customUrlencode(additionalParams)), this.encode(this.secret), sha256);
4272
+ query = this.customUrlencode(this.extend(additionalParams, { 'signature': signature }));
4273
+ url += '?' + query;
4274
+ }
4275
+ else {
4276
+ const totalParams = this.extend(additionalParams, params);
4277
+ signature = this.hmac(this.encode(this.customUrlencode(totalParams)), this.encode(this.secret), sha256);
4278
+ totalParams['signature'] = signature;
4279
+ query = this.customUrlencode(totalParams);
4280
+ if (method === 'GET') {
4281
+ url += '?' + query;
4282
+ }
4283
+ else {
4284
+ body = query;
4285
+ }
4286
+ }
4287
+ headers['INPUT-SOURCE'] = this.safeString(this.options, 'broker', '10000700011');
4288
+ headers['broker_sign'] = signature;
4289
+ }
4290
+ else {
4291
+ query = this.urlencode(params);
4292
+ if (query.length !== 0) {
4293
+ url += '?' + query;
4294
+ }
4295
+ }
4296
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
4297
+ }
4298
+ customUrlencode(params = {}) {
4299
+ let result = this.urlencode(params);
4300
+ result = result.replace('%2C', ',');
4301
+ return result;
4302
+ }
4303
+ handleErrors(code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
4304
+ if (response === undefined) {
4305
+ return undefined;
4306
+ }
4307
+ let errorInArray = false;
4308
+ let responseCodeString = this.safeString(response, 'code', undefined);
4309
+ const responseCodeInteger = this.safeInteger(response, 'code', undefined); // some codes in response are returned as '0000' others as 0
4310
+ if (responseCodeInteger === 0) {
4311
+ const result = this.safeList(response, 'result', []); // for batch methods
4312
+ for (let i = 0; i < result.length; i++) {
4313
+ const entry = this.safeDict(result, i);
4314
+ const entryCodeInteger = this.safeInteger(entry, 'code');
4315
+ if (entryCodeInteger !== 0) {
4316
+ errorInArray = true;
4317
+ responseCodeString = this.safeString(entry, 'code');
4318
+ }
4319
+ }
4320
+ }
4321
+ if ((code !== 200) || errorInArray) {
4322
+ const feedback = this.id + ' ' + body;
4323
+ this.throwBroadlyMatchedException(this.exceptions['broad'], responseCodeString, feedback);
4324
+ this.throwExactlyMatchedException(this.exceptions['exact'], responseCodeString, feedback);
4325
+ throw new ExchangeError(feedback);
4326
+ }
4327
+ return undefined;
4328
+ }
4329
+ }