ccxt 4.3.85 → 4.3.87

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