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