ccxt 4.5.30 → 4.5.32

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 (73) hide show
  1. package/README.md +4 -4
  2. package/dist/ccxt.browser.min.js +18 -18
  3. package/dist/cjs/ccxt.js +6 -4
  4. package/dist/cjs/src/aster.js +3802 -0
  5. package/dist/cjs/src/backpack.js +1 -1
  6. package/dist/cjs/src/base/Exchange.js +35 -2
  7. package/dist/cjs/src/base/ws/WsClient.js +1 -0
  8. package/dist/cjs/src/bigone.js +1 -1
  9. package/dist/cjs/src/binance.js +1 -0
  10. package/dist/cjs/src/bingx.js +73 -0
  11. package/dist/cjs/src/cryptomus.js +1 -1
  12. package/dist/cjs/src/gate.js +52 -6
  13. package/dist/cjs/src/hyperliquid.js +9 -1
  14. package/dist/cjs/src/kucoin.js +63 -64
  15. package/dist/cjs/src/okx.js +14 -5
  16. package/dist/cjs/src/pro/apex.js +2 -2
  17. package/dist/cjs/src/pro/ascendex.js +1 -1
  18. package/dist/cjs/src/pro/aster.js +1046 -0
  19. package/dist/cjs/src/pro/bingx.js +1 -1
  20. package/dist/cjs/src/pro/bybit.js +1 -1
  21. package/dist/cjs/src/pro/cryptocom.js +1 -1
  22. package/dist/cjs/src/pro/dydx.js +1 -1
  23. package/dist/cjs/src/pro/htx.js +1 -1
  24. package/dist/cjs/src/pro/hyperliquid.js +1 -1
  25. package/dist/cjs/src/pro/p2b.js +1 -1
  26. package/dist/cjs/src/pro/toobit.js +1 -1
  27. package/js/ccxt.d.ts +8 -5
  28. package/js/ccxt.js +6 -4
  29. package/js/src/abstract/aster.d.ts +88 -0
  30. package/js/src/abstract/binance.d.ts +1 -0
  31. package/js/src/abstract/binancecoinm.d.ts +1 -0
  32. package/js/src/abstract/binanceus.d.ts +1 -0
  33. package/js/src/abstract/binanceusdm.d.ts +1 -0
  34. package/js/src/abstract/kucoin.d.ts +2 -0
  35. package/js/src/abstract/kucoinfutures.d.ts +2 -0
  36. package/js/src/aster.d.ts +563 -0
  37. package/js/src/aster.js +3801 -0
  38. package/js/src/backpack.js +1 -1
  39. package/js/src/base/Exchange.d.ts +4 -0
  40. package/js/src/base/Exchange.js +35 -1
  41. package/js/src/base/ws/WsClient.js +1 -0
  42. package/js/src/bigone.js +1 -1
  43. package/js/src/binance.d.ts +1 -1
  44. package/js/src/binance.js +1 -0
  45. package/js/src/bingx.d.ts +12 -1
  46. package/js/src/bingx.js +73 -0
  47. package/js/src/cryptomus.js +1 -1
  48. package/js/src/exmo.d.ts +1 -1
  49. package/js/src/gate.js +52 -6
  50. package/js/src/hyperliquid.d.ts +1 -0
  51. package/js/src/hyperliquid.js +9 -1
  52. package/js/src/kucoin.d.ts +5 -3
  53. package/js/src/kucoin.js +63 -64
  54. package/js/src/okx.js +14 -5
  55. package/js/src/pro/apex.js +2 -2
  56. package/js/src/pro/ascendex.js +1 -1
  57. package/js/src/pro/aster.d.ts +273 -0
  58. package/js/src/pro/aster.js +1045 -0
  59. package/js/src/pro/bingx.js +1 -1
  60. package/js/src/pro/bybit.js +1 -1
  61. package/js/src/pro/cryptocom.js +1 -1
  62. package/js/src/pro/dydx.js +1 -1
  63. package/js/src/pro/htx.js +1 -1
  64. package/js/src/pro/hyperliquid.js +1 -1
  65. package/js/src/pro/p2b.js +1 -1
  66. package/js/src/pro/toobit.js +1 -1
  67. package/package.json +1 -1
  68. package/dist/cjs/src/oceanex.js +0 -1125
  69. package/js/src/abstract/oceanex.d.ts +0 -30
  70. package/js/src/oceanex.d.ts +0 -231
  71. package/js/src/oceanex.js +0 -1124
  72. /package/dist/cjs/src/abstract/{oceanex.js → aster.js} +0 -0
  73. /package/js/src/abstract/{oceanex.js → aster.js} +0 -0
@@ -0,0 +1,3802 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var aster$1 = require('./abstract/aster.js');
6
+ var errors = require('./base/errors.js');
7
+ var number = require('./base/functions/number.js');
8
+ var Precise = require('./base/Precise.js');
9
+ var sha256 = require('./static_dependencies/noble-hashes/sha256.js');
10
+ var crypto = require('./base/functions/crypto.js');
11
+ var sha3 = require('./static_dependencies/noble-hashes/sha3.js');
12
+ var secp256k1 = require('./static_dependencies/noble-curves/secp256k1.js');
13
+
14
+ // ----------------------------------------------------------------------------
15
+ // ---------------------------------------------------------------------------xs
16
+ /**
17
+ * @class aster
18
+ * @augments Exchange
19
+ */
20
+ class aster extends aster$1["default"] {
21
+ describe() {
22
+ return this.deepExtend(super.describe(), {
23
+ 'id': 'aster',
24
+ 'name': 'Aster',
25
+ 'dex': true,
26
+ 'countries': ['US'],
27
+ // 3 req/s for free
28
+ // 150 req/s for subscribers: https://aster.markets/data
29
+ // for brokers: https://aster.markets/docs/api-references/broker-api/#authentication-and-rate-limit
30
+ 'rateLimit': 333,
31
+ 'hostname': 'aster.markets',
32
+ 'pro': true,
33
+ 'urls': {
34
+ 'logo': 'https://github.com/user-attachments/assets/4982201b-73cd-4d7a-8907-e69e239e9609',
35
+ 'www': 'https://www.asterdex.com/en',
36
+ 'api': {
37
+ 'fapiPublic': 'https://fapi.asterdex.com/fapi',
38
+ 'fapiPrivate': 'https://fapi.asterdex.com/fapi',
39
+ 'sapiPublic': 'https://sapi.asterdex.com/api',
40
+ 'sapiPrivate': 'https://sapi.asterdex.com/api',
41
+ },
42
+ 'doc': 'https://github.com/asterdex/api-docs',
43
+ 'fees': 'https://docs.asterdex.com/product/asterex-simple/fees-and-slippage',
44
+ 'referral': {
45
+ 'url': 'https://www.asterdex.com/en/referral/aA1c2B',
46
+ 'discount': 0.1,
47
+ },
48
+ },
49
+ 'has': {
50
+ 'CORS': undefined,
51
+ 'spot': false,
52
+ 'margin': false,
53
+ 'swap': false,
54
+ 'future': false,
55
+ 'option': false,
56
+ 'addMargin': true,
57
+ 'borrowCrossMargin': false,
58
+ 'borrowIsolatedMargin': false,
59
+ 'cancelAllOrders': true,
60
+ 'cancelOrder': true,
61
+ 'cancelOrders': true,
62
+ 'closeAllPositions': false,
63
+ 'closePosition': false,
64
+ 'createConvertTrade': false,
65
+ 'createDepositAddress': false,
66
+ 'createLimitBuyOrder': false,
67
+ 'createLimitSellOrder': false,
68
+ 'createMarketBuyOrder': false,
69
+ 'createMarketBuyOrderWithCost': false,
70
+ 'createMarketOrderWithCost': false,
71
+ 'createMarketSellOrder': false,
72
+ 'createMarketSellOrderWithCost': false,
73
+ 'createOrder': true,
74
+ 'createOrders': false,
75
+ 'createOrderWithTakeProfitAndStopLoss': false,
76
+ 'createPostOnlyOrder': false,
77
+ 'createReduceOnlyOrder': false,
78
+ 'createStopLimitOrder': false,
79
+ 'createStopLossOrder': false,
80
+ 'createStopMarketOrder': false,
81
+ 'createStopOrder': false,
82
+ 'createTakeProfitOrder': false,
83
+ 'createTrailingPercentOrder': false,
84
+ 'createTriggerOrder': false,
85
+ 'editOrder': false,
86
+ 'editOrders': false,
87
+ 'fetchAccounts': undefined,
88
+ 'fetchBalance': true,
89
+ 'fetchBidsAsks': false,
90
+ 'fetchBorrowInterest': false,
91
+ 'fetchBorrowRateHistories': false,
92
+ 'fetchBorrowRateHistory': false,
93
+ 'fetchCanceledAndClosedOrders': 'emulated',
94
+ 'fetchCanceledOrders': 'emulated',
95
+ 'fetchClosedOrder': false,
96
+ 'fetchClosedOrders': 'emulated',
97
+ 'fetchConvertCurrencies': false,
98
+ 'fetchConvertQuote': false,
99
+ 'fetchConvertTrade': false,
100
+ 'fetchConvertTradeHistory': false,
101
+ 'fetchCrossBorrowRate': false,
102
+ 'fetchCrossBorrowRates': false,
103
+ 'fetchCurrencies': true,
104
+ 'fetchDeposit': false,
105
+ 'fetchDepositAddress': false,
106
+ 'fetchDepositAddresses': false,
107
+ 'fetchDepositAddressesByNetwork': false,
108
+ 'fetchDeposits': false,
109
+ 'fetchDepositsWithdrawals': false,
110
+ 'fetchDepositWithdrawFee': 'emulated',
111
+ 'fetchDepositWithdrawFees': false,
112
+ 'fetchFundingHistory': true,
113
+ 'fetchFundingInterval': 'emulated',
114
+ 'fetchFundingIntervals': true,
115
+ 'fetchFundingRate': true,
116
+ 'fetchFundingRateHistory': true,
117
+ 'fetchFundingRates': true,
118
+ 'fetchGreeks': false,
119
+ 'fetchIndexOHLCV': false,
120
+ 'fetchIsolatedBorrowRate': 'emulated',
121
+ 'fetchIsolatedBorrowRates': false,
122
+ 'fetchL3OrderBook': false,
123
+ 'fetchLastPrices': false,
124
+ 'fetchLedger': true,
125
+ 'fetchLedgerEntry': false,
126
+ 'fetchLeverage': 'emulated',
127
+ 'fetchLeverages': true,
128
+ 'fetchLeverageTiers': false,
129
+ 'fetchLiquidations': false,
130
+ 'fetchLongShortRatio': false,
131
+ 'fetchLongShortRatioHistory': false,
132
+ 'fetchMarginAdjustmentHistory': true,
133
+ 'fetchMarginMode': 'emulated',
134
+ 'fetchMarginModes': true,
135
+ 'fetchMarketLeverageTiers': 'emulated',
136
+ 'fetchMarkets': true,
137
+ 'fetchMarkOHLCV': false,
138
+ 'fetchMarkPrice': false,
139
+ 'fetchMarkPrices': false,
140
+ 'fetchMyLiquidations': false,
141
+ 'fetchMySettlementHistory': false,
142
+ 'fetchMyTrades': true,
143
+ 'fetchOHLCV': true,
144
+ 'fetchOpenInterest': false,
145
+ 'fetchOpenInterestHistory': false,
146
+ 'fetchOpenOrder': true,
147
+ 'fetchOpenOrders': true,
148
+ 'fetchOption': false,
149
+ 'fetchOptionChain': false,
150
+ 'fetchOrder': true,
151
+ 'fetchOrderBook': true,
152
+ 'fetchOrderBooks': false,
153
+ 'fetchOrders': true,
154
+ 'fetchOrderTrades': false,
155
+ 'fetchPosition': false,
156
+ 'fetchPositionHistory': false,
157
+ 'fetchPositionMode': true,
158
+ 'fetchPositions': true,
159
+ 'fetchPositionsHistory': false,
160
+ 'fetchPositionsRisk': true,
161
+ 'fetchPremiumIndexOHLCV': false,
162
+ 'fetchSettlementHistory': false,
163
+ 'fetchStatus': false,
164
+ 'fetchTicker': true,
165
+ 'fetchTickers': true,
166
+ 'fetchTime': true,
167
+ 'fetchTrades': true,
168
+ 'fetchTradingFee': true,
169
+ 'fetchTradingFees': false,
170
+ 'fetchTradingLimits': 'emulated',
171
+ 'fetchTransactionFee': 'emulated',
172
+ 'fetchTransactionFees': false,
173
+ 'fetchTransactions': false,
174
+ 'fetchTransfer': false,
175
+ 'fetchTransfers': false,
176
+ 'fetchUnderlyingAssets': false,
177
+ 'fetchVolatilityHistory': false,
178
+ 'fetchWithdrawAddresses': false,
179
+ 'fetchWithdrawal': false,
180
+ 'fetchWithdrawals': false,
181
+ 'fetchWithdrawalWhitelist': false,
182
+ 'reduceMargin': true,
183
+ 'repayCrossMargin': false,
184
+ 'repayIsolatedMargin': false,
185
+ 'sandbox': false,
186
+ 'setLeverage': true,
187
+ 'setMargin': false,
188
+ 'setMarginMode': true,
189
+ 'setPositionMode': true,
190
+ 'signIn': false,
191
+ 'transfer': true,
192
+ 'withdraw': true,
193
+ },
194
+ 'api': {
195
+ 'fapiPublic': {
196
+ 'get': [
197
+ 'v1/ping',
198
+ 'v1/time',
199
+ 'v1/exchangeInfo',
200
+ 'v1/depth',
201
+ 'v1/trades',
202
+ 'v1/historicalTrades',
203
+ 'v1/aggTrades',
204
+ 'v1/klines',
205
+ 'v1/indexPriceKlines',
206
+ 'v1/markPriceKlines',
207
+ 'v1/premiumIndex',
208
+ 'v1/fundingRate',
209
+ 'v1/fundingInfo',
210
+ 'v1/ticker/24hr',
211
+ 'v1/ticker/price',
212
+ 'v1/ticker/bookTicker',
213
+ 'v1/adlQuantile',
214
+ 'v1/forceOrders',
215
+ ],
216
+ 'post': [
217
+ 'v1/listenKey',
218
+ ],
219
+ 'put': [
220
+ 'v1/listenKey',
221
+ ],
222
+ 'delete': [
223
+ 'v1/listenKey',
224
+ ],
225
+ },
226
+ 'fapiPrivate': {
227
+ 'get': [
228
+ 'v1/positionSide/dual',
229
+ 'v1/multiAssetsMargin',
230
+ 'v1/order',
231
+ 'v1/openOrder',
232
+ 'v1/openOrders',
233
+ 'v1/allOrders',
234
+ 'v2/balance',
235
+ 'v3/balance',
236
+ 'v3/account',
237
+ 'v4/account',
238
+ 'v1/positionMargin/history',
239
+ 'v2/positionRisk',
240
+ 'v3/positionRisk',
241
+ 'v1/userTrades',
242
+ 'v1/income',
243
+ 'v1/leverageBracket',
244
+ 'v1/commissionRate',
245
+ ],
246
+ 'post': [
247
+ 'v1/positionSide/dual',
248
+ 'v1/multiAssetsMargin',
249
+ 'v1/order',
250
+ 'v1/order/test',
251
+ 'v1/batchOrders',
252
+ 'v1/asset/wallet/transfer',
253
+ 'v1/countdownCancelAll',
254
+ 'v1/leverage',
255
+ 'v1/marginType',
256
+ 'v1/positionMargin',
257
+ ],
258
+ 'delete': [
259
+ 'v1/order',
260
+ 'v1/allOpenOrders',
261
+ 'v1/batchOrders',
262
+ ],
263
+ },
264
+ 'sapiPublic': {
265
+ 'get': [
266
+ 'v1/ping',
267
+ 'v1/time',
268
+ 'v1/exchangeInfo',
269
+ 'v1/depth',
270
+ 'v1/trades',
271
+ 'v1/historicalTrades',
272
+ 'v1/aggTrades',
273
+ 'v1/klines',
274
+ 'v1/ticker/24hr',
275
+ 'v1/ticker/price',
276
+ 'v1/ticker/bookTicker',
277
+ 'v1/aster/withdraw/estimateFee',
278
+ ],
279
+ 'post': [
280
+ 'v1/getNonce',
281
+ 'v1/createApiKey',
282
+ 'v1/listenKey',
283
+ ],
284
+ 'put': [
285
+ 'v1/listenKey',
286
+ ],
287
+ 'delete': [
288
+ 'v1/listenKey',
289
+ ],
290
+ },
291
+ 'sapiPrivate': {
292
+ 'get': [
293
+ 'v1/commissionRate',
294
+ 'v1/order',
295
+ 'v1/openOrders',
296
+ 'v1/allOrders',
297
+ 'v1/transactionHistory',
298
+ 'v1/account',
299
+ 'v1/userTrades',
300
+ ],
301
+ 'post': [
302
+ 'v1/order',
303
+ 'v1/asset/wallet/transfer',
304
+ 'v1/asset/sendToAddress',
305
+ 'v1/aster/user-withdraw',
306
+ ],
307
+ 'delete': [
308
+ 'v1/order',
309
+ 'v1/allOpenOrders',
310
+ ],
311
+ },
312
+ },
313
+ 'timeframes': {
314
+ '1m': '1m',
315
+ '3m': '3m',
316
+ '5m': '5m',
317
+ '15m': '15m',
318
+ '30m': '30m',
319
+ '1h': '1h',
320
+ '2h': '2h',
321
+ '4h': '4h',
322
+ '6h': '6h',
323
+ '8h': '8h',
324
+ '12h': '12h',
325
+ '1d': '1d',
326
+ '3d': '3d',
327
+ '1w': '1w',
328
+ '1M': '1M',
329
+ },
330
+ 'precisionMode': number.TICK_SIZE,
331
+ 'requiredCredentials': {
332
+ 'apiKey': true,
333
+ 'secret': true,
334
+ },
335
+ 'fees': {
336
+ 'trading': {
337
+ 'tierBased': true,
338
+ 'percentage': true,
339
+ 'maker': this.parseNumber('0.0001'),
340
+ 'taker': this.parseNumber('0.00035'),
341
+ },
342
+ },
343
+ 'options': {
344
+ 'recvWindow': 10 * 1000,
345
+ 'defaultTimeInForce': 'GTC',
346
+ 'zeroAddress': '0x0000000000000000000000000000000000000000',
347
+ 'quoteOrderQty': true,
348
+ 'accountsByType': {
349
+ 'spot': 'SPOT',
350
+ 'future': 'FUTURE',
351
+ 'linear': 'FUTURE',
352
+ 'swap': 'FUTURE',
353
+ },
354
+ 'networks': {
355
+ 'ERC20': 'ETH',
356
+ 'BEP20': 'BSC',
357
+ 'ARB': 'Arbitrum',
358
+ },
359
+ 'networksToChainId': {
360
+ 'ETH': 1,
361
+ 'BSC': 56,
362
+ 'Arbitrum': 42161,
363
+ },
364
+ },
365
+ 'exceptions': {
366
+ 'exact': {
367
+ // 10xx - General Server or Network issues
368
+ '-1000': errors.OperationFailed,
369
+ '-1001': errors.NetworkError,
370
+ '-1002': errors.AuthenticationError,
371
+ '-1003': errors.RateLimitExceeded,
372
+ '-1004': errors.DuplicateOrderId,
373
+ '-1005': errors.BadRequest,
374
+ '-1006': errors.BadResponse,
375
+ '-1007': errors.RequestTimeout,
376
+ '-1010': errors.OperationFailed,
377
+ '-1011': errors.PermissionDenied,
378
+ '-1013': errors.BadRequest,
379
+ '-1014': errors.OrderNotFillable,
380
+ '-1015': errors.RateLimitExceeded,
381
+ '-1016': errors.ExchangeClosedByUser,
382
+ '-1020': errors.NotSupported,
383
+ '-1021': errors.InvalidNonce,
384
+ '-1022': errors.AuthenticationError,
385
+ '-1023': errors.BadRequest,
386
+ // 11xx - Request issues
387
+ '-1100': errors.BadRequest,
388
+ '-1101': errors.BadRequest,
389
+ '-1102': errors.ArgumentsRequired,
390
+ '-1103': errors.BadRequest,
391
+ '-1104': errors.BadRequest,
392
+ '-1105': errors.ArgumentsRequired,
393
+ '-1106': errors.BadRequest,
394
+ '-1108': errors.BadRequest,
395
+ '-1109': errors.BadRequest,
396
+ '-1110': errors.BadSymbol,
397
+ '-1111': errors.BadRequest,
398
+ '-1112': errors.BadRequest,
399
+ '-1113': errors.BadRequest,
400
+ '-1114': errors.BadRequest,
401
+ '-1115': errors.InvalidOrder,
402
+ '-1116': errors.InvalidOrder,
403
+ '-1117': errors.InvalidOrder,
404
+ '-1118': errors.InvalidOrder,
405
+ '-1119': errors.InvalidOrder,
406
+ '-1120': errors.BadRequest,
407
+ '-1121': errors.BadSymbol,
408
+ '-1125': errors.AuthenticationError,
409
+ '-1127': errors.BadRequest,
410
+ '-1128': errors.BadRequest,
411
+ '-1130': errors.BadRequest,
412
+ '-1136': errors.InvalidOrder,
413
+ // 20xx - Processing Issues
414
+ '-2010': errors.InvalidOrder,
415
+ '-2011': errors.OrderNotFound,
416
+ '-2013': errors.OrderNotFound,
417
+ '-2014': errors.AuthenticationError,
418
+ '-2015': errors.AuthenticationError,
419
+ '-2016': errors.MarketClosed,
420
+ '-2018': errors.InsufficientFunds,
421
+ '-2019': errors.InsufficientFunds,
422
+ '-2020': errors.OrderNotFillable,
423
+ '-2021': errors.OrderImmediatelyFillable,
424
+ '-2022': errors.OperationRejected,
425
+ '-2023': errors.AccountSuspended,
426
+ '-2024': errors.InsufficientFunds,
427
+ '-2025': errors.RateLimitExceeded,
428
+ '-2026': errors.NotSupported,
429
+ '-2027': errors.BadRequest,
430
+ '-2028': errors.BadRequest,
431
+ // 40xx - Filters and other Issues
432
+ '-4000': errors.InvalidOrder,
433
+ '-4001': errors.InvalidOrder,
434
+ '-4002': errors.InvalidOrder,
435
+ '-4003': errors.InvalidOrder,
436
+ '-4004': errors.InvalidOrder,
437
+ '-4005': errors.InvalidOrder,
438
+ '-4006': errors.InvalidOrder,
439
+ '-4007': errors.InvalidOrder,
440
+ '-4008': errors.InvalidOrder,
441
+ '-4009': errors.InvalidOrder,
442
+ '-4010': errors.InvalidOrder,
443
+ '-4011': errors.InvalidOrder,
444
+ '-4012': errors.RateLimitExceeded,
445
+ '-4013': errors.InvalidOrder,
446
+ '-4014': errors.InvalidOrder,
447
+ '-4015': errors.InvalidOrder,
448
+ '-4016': errors.InvalidOrder,
449
+ '-4017': errors.InvalidOrder,
450
+ '-4018': errors.InvalidOrder,
451
+ '-4019': errors.BadRequest,
452
+ '-4020': errors.BadRequest,
453
+ '-4021': errors.BadRequest,
454
+ '-4022': errors.MarketClosed,
455
+ '-4023': errors.InvalidOrder,
456
+ '-4024': errors.InvalidOrder,
457
+ '-4025': errors.BadRequest,
458
+ '-4026': errors.BadRequest,
459
+ '-4027': errors.BadRequest,
460
+ '-4028': errors.BadRequest,
461
+ '-4029': errors.BadRequest,
462
+ '-4030': errors.BadRequest,
463
+ '-4031': errors.BadRequest,
464
+ '-4032': errors.RateLimitExceeded,
465
+ '-4033': errors.AccountNotEnabled,
466
+ '-4044': errors.BadRequest,
467
+ '-4045': errors.RateLimitExceeded,
468
+ '-4046': errors.NoChange,
469
+ '-4047': errors.OperationRejected,
470
+ '-4048': errors.OperationRejected,
471
+ '-4049': errors.OperationRejected,
472
+ '-4050': errors.InsufficientFunds,
473
+ '-4051': errors.InsufficientFunds,
474
+ '-4052': errors.NoChange,
475
+ '-4053': errors.OperationRejected,
476
+ '-4054': errors.OperationRejected,
477
+ '-4055': errors.ArgumentsRequired,
478
+ '-4056': errors.AuthenticationError,
479
+ '-4057': errors.AuthenticationError,
480
+ '-4058': errors.InvalidOrder,
481
+ '-4059': errors.NoChange,
482
+ '-4060': errors.InvalidOrder,
483
+ '-4061': errors.InvalidOrder,
484
+ '-4062': errors.OperationRejected,
485
+ '-4063': errors.BadRequest,
486
+ '-4064': errors.BadRequest,
487
+ '-4065': errors.BadRequest,
488
+ '-4066': errors.BadRequest,
489
+ '-4067': errors.OperationRejected,
490
+ '-4068': errors.OperationRejected,
491
+ '-4069': errors.BadRequest,
492
+ '-4070': errors.InvalidOrder,
493
+ '-4071': errors.InvalidOrder,
494
+ '-4072': errors.NoChange,
495
+ '-4073': errors.BadRequest,
496
+ '-4074': errors.InvalidOrder,
497
+ '-4075': errors.OperationRejected,
498
+ '-4076': errors.OperationRejected,
499
+ '-4077': errors.RateLimitExceeded,
500
+ '-4078': errors.BadRequest,
501
+ '-4079': errors.BadRequest,
502
+ '-4080': errors.BadRequest,
503
+ '-4081': errors.BadRequest,
504
+ '-4082': errors.RateLimitExceeded,
505
+ '-4083': errors.OperationFailed,
506
+ '-4084': errors.NotSupported,
507
+ '-4085': errors.BadRequest,
508
+ '-4086': errors.BadRequest,
509
+ '-4087': errors.PermissionDenied,
510
+ '-4088': errors.PermissionDenied,
511
+ '-4104': errors.BadSymbol,
512
+ '-4114': errors.InvalidOrder,
513
+ '-4115': errors.DuplicateOrderId,
514
+ '-4118': errors.InsufficientFunds,
515
+ '-4131': errors.InvalidOrder,
516
+ '-4135': errors.InvalidOrder,
517
+ '-4137': errors.InvalidOrder,
518
+ '-4138': errors.OperationRejected,
519
+ '-4139': errors.InvalidOrder,
520
+ '-4140': errors.OperationRejected,
521
+ '-4141': errors.MarketClosed,
522
+ '-4142': errors.InvalidOrder,
523
+ '-4144': errors.BadSymbol,
524
+ '-4161': errors.OperationRejected,
525
+ '-4164': errors.InvalidOrder,
526
+ '-4165': errors.BadRequest,
527
+ '-4183': errors.InvalidOrder,
528
+ '-4184': errors.InvalidOrder,
529
+ '-5060': errors.OperationRejected,
530
+ '-5076': errors.OperationRejected, // {"code":-5076,"msg":"Total order value should be more than 5 USDT"}
531
+ },
532
+ 'broad': {},
533
+ },
534
+ });
535
+ }
536
+ isInverse(type, subType = undefined) {
537
+ if (subType === undefined) {
538
+ return (type === 'delivery');
539
+ }
540
+ else {
541
+ return subType === 'inverse';
542
+ }
543
+ }
544
+ isLinear(type, subType = undefined) {
545
+ if (subType === undefined) {
546
+ return (type === 'future') || (type === 'swap');
547
+ }
548
+ else {
549
+ return subType === 'linear';
550
+ }
551
+ }
552
+ /**
553
+ * @method
554
+ * @name aster#fetchCurrencies
555
+ * @description fetches all available currencies on an exchange
556
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#trading-specification-information
557
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#exchange-information
558
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
559
+ * @returns {object} an associative dictionary of currencies
560
+ */
561
+ async fetchCurrencies(params = {}) {
562
+ const promises = [
563
+ this.sapiPublicGetV1ExchangeInfo(params),
564
+ this.fapiPublicGetV1ExchangeInfo(params),
565
+ ];
566
+ const results = await Promise.all(promises);
567
+ const sapiResult = this.safeDict(results, 0, {});
568
+ const sapiRows = this.safeList(sapiResult, 'assets', []);
569
+ const fapiResult = this.safeDict(results, 1, {});
570
+ const fapiRows = this.safeList(fapiResult, 'assets', []);
571
+ const rows = this.arrayConcat(sapiRows, fapiRows);
572
+ //
573
+ // [
574
+ // {
575
+ // "asset": "USDT",
576
+ // "marginAvailable": true,
577
+ // "autoAssetExchange": "-10000"
578
+ // }
579
+ // ]
580
+ //
581
+ const result = {};
582
+ for (let i = 0; i < rows.length; i++) {
583
+ const currency = rows[i];
584
+ const currencyId = this.safeString(currency, 'asset');
585
+ const code = this.safeCurrencyCode(currencyId);
586
+ result[code] = this.safeCurrencyStructure({
587
+ 'info': currency,
588
+ 'code': code,
589
+ 'id': currencyId,
590
+ 'name': code,
591
+ 'active': undefined,
592
+ 'deposit': undefined,
593
+ 'withdraw': undefined,
594
+ 'fee': undefined,
595
+ 'precision': undefined,
596
+ 'limits': {
597
+ 'amount': {
598
+ 'min': undefined,
599
+ 'max': undefined,
600
+ },
601
+ 'withdraw': {
602
+ 'min': undefined,
603
+ 'max': undefined,
604
+ },
605
+ 'deposit': {
606
+ 'min': undefined,
607
+ 'max': undefined,
608
+ },
609
+ },
610
+ 'networks': undefined,
611
+ 'type': 'crypto', // atm exchange api provides only cryptos
612
+ });
613
+ }
614
+ return result;
615
+ }
616
+ /**
617
+ * @method
618
+ * @name aster#fetchMarkets
619
+ * @description retrieves data on all markets for bigone
620
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#trading-specification-information
621
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#exchange-information
622
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
623
+ * @returns {object[]} an array of objects representing market data
624
+ */
625
+ async fetchMarkets(params = {}) {
626
+ const promises = [
627
+ this.sapiPublicGetV1ExchangeInfo(params),
628
+ this.fapiPublicGetV1ExchangeInfo(params),
629
+ ];
630
+ const results = await Promise.all(promises);
631
+ const sapiResult = this.safeDict(results, 0, {});
632
+ const sapiRows = this.safeList(sapiResult, 'symbols', []);
633
+ const fapiResult = this.safeDict(results, 1, {});
634
+ const fapiRows = this.safeList(fapiResult, 'symbols', []);
635
+ const rows = this.arrayConcat(sapiRows, fapiRows);
636
+ //
637
+ // [
638
+ // {
639
+ // "symbol": "BTCUSDT",
640
+ // "pair": "BTCUSDT",
641
+ // "contractType": "PERPETUAL",
642
+ // "deliveryDate": 4133404800000,
643
+ // "onboardDate": 1627628400000,
644
+ // "status": "TRADING",
645
+ // "maintMarginPercent": "2.5000",
646
+ // "requiredMarginPercent": "5.0000",
647
+ // "baseAsset": "BTC",
648
+ // "quoteAsset": "USDT",
649
+ // "marginAsset": "USDT",
650
+ // "pricePrecision": 1,
651
+ // "quantityPrecision": 3,
652
+ // "baseAssetPrecision": 8,
653
+ // "quotePrecision": 8,
654
+ // "underlyingType": "COIN",
655
+ // "underlyingSubType": [],
656
+ // "settlePlan": 0,
657
+ // "triggerProtect": "0.0200",
658
+ // "liquidationFee": "0.025000",
659
+ // "marketTakeBound": "0.02",
660
+ // "filters": [
661
+ // {
662
+ // "minPrice": "1",
663
+ // "maxPrice": "1000000",
664
+ // "filterType": "PRICE_FILTER",
665
+ // "tickSize": "0.1"
666
+ // },
667
+ // {
668
+ // "stepSize": "0.001",
669
+ // "filterType": "LOT_SIZE",
670
+ // "maxQty": "100",
671
+ // "minQty": "0.001"
672
+ // },
673
+ // {
674
+ // "stepSize": "0.001",
675
+ // "filterType": "MARKET_LOT_SIZE",
676
+ // "maxQty": "10",
677
+ // "minQty": "0.001"
678
+ // },
679
+ // {
680
+ // "limit": 200,
681
+ // "filterType": "MAX_NUM_ORDERS"
682
+ // },
683
+ // {
684
+ // "limit": 10,
685
+ // "filterType": "MAX_NUM_ALGO_ORDERS"
686
+ // },
687
+ // {
688
+ // "notional": "5",
689
+ // "filterType": "MIN_NOTIONAL"
690
+ // },
691
+ // {
692
+ // "multiplierDown": "0.9800",
693
+ // "multiplierUp": "1.0200",
694
+ // "multiplierDecimal": "4",
695
+ // "filterType": "PERCENT_PRICE"
696
+ // }
697
+ // ],
698
+ // "orderTypes": [
699
+ // "LIMIT",
700
+ // "MARKET",
701
+ // "STOP",
702
+ // "STOP_MARKET",
703
+ // "TAKE_PROFIT",
704
+ // "TAKE_PROFIT_MARKET",
705
+ // "TRAILING_STOP_MARKET"
706
+ // ],
707
+ // "timeInForce": [
708
+ // "GTC",
709
+ // "IOC",
710
+ // "FOK",
711
+ // "GTX",
712
+ // "RPI"
713
+ // ]
714
+ // }
715
+ // ]
716
+ //
717
+ const fees = this.fees;
718
+ const result = [];
719
+ for (let i = 0; i < rows.length; i++) {
720
+ let swap = false;
721
+ const market = rows[i];
722
+ const id = this.safeString(market, 'symbol');
723
+ const baseId = this.safeString(market, 'baseAsset');
724
+ const quoteId = this.safeString(market, 'quoteAsset');
725
+ const base = this.safeCurrencyCode(baseId);
726
+ const quote = this.safeCurrencyCode(quoteId);
727
+ const contractType = this.safeString(market, 'contractType');
728
+ const contract = contractType !== undefined;
729
+ let spot = true;
730
+ if (contractType === 'PERPETUAL') {
731
+ swap = true;
732
+ spot = false;
733
+ }
734
+ let contractSize = undefined;
735
+ let linear = undefined;
736
+ let inverse = undefined;
737
+ let symbol = base + '/' + quote;
738
+ let settle = undefined;
739
+ let settleId = undefined;
740
+ if (contract) {
741
+ settleId = this.safeString(market, 'marginAsset');
742
+ settle = this.safeCurrencyCode(settleId);
743
+ if (swap) {
744
+ symbol = symbol + ':' + settle;
745
+ }
746
+ linear = settle === quote;
747
+ inverse = settle === base;
748
+ contractSize = this.safeNumber2(market, 'contractSize', 'unit', this.parseNumber('1'));
749
+ }
750
+ let unifiedType = undefined;
751
+ if (spot) {
752
+ unifiedType = 'spot';
753
+ }
754
+ else if (swap) {
755
+ unifiedType = 'swap';
756
+ }
757
+ const status = this.safeString(market, 'status');
758
+ const active = status === 'TRADING';
759
+ const filters = this.safeList(market, 'filters', []);
760
+ const filtersByType = this.indexBy(filters, 'filterType');
761
+ const entry = this.safeMarketStructure({
762
+ 'id': id,
763
+ 'symbol': symbol,
764
+ 'base': base,
765
+ 'quote': quote,
766
+ 'settle': settle,
767
+ 'baseId': baseId,
768
+ 'quoteId': quoteId,
769
+ 'settleId': settleId,
770
+ 'type': unifiedType,
771
+ 'spot': spot,
772
+ 'margin': false,
773
+ 'swap': swap,
774
+ 'future': false,
775
+ 'option': false,
776
+ 'active': active,
777
+ 'contract': contract,
778
+ 'linear': linear,
779
+ 'inverse': inverse,
780
+ 'taker': fees['trading']['taker'],
781
+ 'maker': fees['trading']['maker'],
782
+ 'contractSize': contractSize,
783
+ 'expiry': undefined,
784
+ 'expiryDatetime': undefined,
785
+ 'strike': undefined,
786
+ 'optionType': undefined,
787
+ 'precision': {
788
+ 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'quantityPrecision'))),
789
+ 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))),
790
+ 'base': this.parseNumber(this.parsePrecision(this.safeString(market, 'baseAssetPrecision'))),
791
+ 'quote': this.parseNumber(this.parsePrecision(this.safeString(market, 'quotePrecision'))),
792
+ },
793
+ 'limits': {
794
+ 'leverage': {
795
+ 'min': undefined,
796
+ 'max': undefined,
797
+ },
798
+ 'amount': {
799
+ 'min': undefined,
800
+ 'max': undefined,
801
+ },
802
+ 'price': {
803
+ 'min': undefined,
804
+ 'max': undefined,
805
+ },
806
+ 'cost': {
807
+ 'min': undefined,
808
+ 'max': undefined,
809
+ },
810
+ },
811
+ 'created': this.safeInteger(market, 'onboardDate'),
812
+ 'info': market,
813
+ });
814
+ if ('PRICE_FILTER' in filtersByType) {
815
+ const filter = this.safeDict(filtersByType, 'PRICE_FILTER', {});
816
+ entry['limits']['price'] = {
817
+ 'min': this.safeNumber(filter, 'minPrice'),
818
+ 'max': this.safeNumber(filter, 'maxPrice'),
819
+ };
820
+ entry['precision']['price'] = this.safeNumber(filter, 'tickSize');
821
+ }
822
+ if ('LOT_SIZE' in filtersByType) {
823
+ const filter = this.safeDict(filtersByType, 'LOT_SIZE', {});
824
+ entry['precision']['amount'] = this.safeNumber(filter, 'stepSize');
825
+ entry['limits']['amount'] = {
826
+ 'min': this.safeNumber(filter, 'minQty'),
827
+ 'max': this.safeNumber(filter, 'maxQty'),
828
+ };
829
+ }
830
+ if ('MARKET_LOT_SIZE' in filtersByType) {
831
+ const filter = this.safeDict(filtersByType, 'MARKET_LOT_SIZE', {});
832
+ entry['limits']['market'] = {
833
+ 'min': this.safeNumber(filter, 'minQty'),
834
+ 'max': this.safeNumber(filter, 'maxQty'),
835
+ };
836
+ }
837
+ if (('MIN_NOTIONAL' in filtersByType) || ('NOTIONAL' in filtersByType)) {
838
+ const filter = this.safeDict2(filtersByType, 'MIN_NOTIONAL', 'NOTIONAL', {});
839
+ entry['limits']['cost']['min'] = this.safeNumber(filter, 'notional');
840
+ }
841
+ result.push(entry);
842
+ }
843
+ return result;
844
+ }
845
+ /**
846
+ * @method
847
+ * @name aster#fetchTime
848
+ * @description fetches the current integer timestamp in milliseconds from the exchange server
849
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#check-server-time
850
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
851
+ * @returns {int} the current integer timestamp in milliseconds from the exchange server
852
+ */
853
+ async fetchTime(params = {}) {
854
+ const response = await this.fapiPublicGetV1Time(params);
855
+ //
856
+ // {
857
+ // "serverTime": 1499827319559
858
+ // }
859
+ //
860
+ return this.safeInteger(response, 'serverTime');
861
+ }
862
+ parseOHLCV(ohlcv, market = undefined) {
863
+ //
864
+ // [
865
+ // 1631158560000,
866
+ // "208.1850",
867
+ // "208.1850",
868
+ // "208.1850",
869
+ // "208.1850",
870
+ // "11.84",
871
+ // 1631158619999,
872
+ // "2464.910400",
873
+ // 1,
874
+ // "11.84",
875
+ // "2464.910400",
876
+ // "0"
877
+ // ]
878
+ //
879
+ return [
880
+ this.safeInteger(ohlcv, 0),
881
+ this.safeNumber(ohlcv, 1),
882
+ this.safeNumber(ohlcv, 2),
883
+ this.safeNumber(ohlcv, 3),
884
+ this.safeNumber(ohlcv, 4),
885
+ this.safeNumber(ohlcv, 5),
886
+ ];
887
+ }
888
+ /**
889
+ * @method
890
+ * @name aster#fetchOHLCV
891
+ * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
892
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-data
893
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-data
894
+ * @param {string} symbol unified symbol of the market to fetch OHLCV data for
895
+ * @param {string} timeframe the length of time each candle represents
896
+ * @param {int} [since] timestamp in ms of the earliest candle to fetch
897
+ * @param {int} [limit] the maximum amount of candles to fetch
898
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
899
+ * @param {string} [params.price] "mark" or "index" for mark price and index price candles
900
+ * @param {int} [params.until] the latest time in ms to fetch orders for
901
+ * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
902
+ */
903
+ async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
904
+ if (symbol === undefined) {
905
+ throw new errors.ArgumentsRequired(this.id + ' fetchOHLCV() requires a symbol argument');
906
+ }
907
+ await this.loadMarkets();
908
+ const market = this.market(symbol);
909
+ let request = {};
910
+ if (since !== undefined) {
911
+ request['startTime'] = since;
912
+ }
913
+ if (limit !== undefined) {
914
+ if (limit > 1500) {
915
+ limit = 1500; // Default 500; max 1500.
916
+ }
917
+ request['limit'] = limit;
918
+ }
919
+ [request, params] = this.handleUntilOption('endTime', request, params);
920
+ request['interval'] = this.safeString(this.timeframes, timeframe, timeframe);
921
+ const price = this.safeString(params, 'price');
922
+ const isMark = (price === 'mark');
923
+ const isIndex = (price === 'index');
924
+ params = this.omit(params, 'price');
925
+ let response = undefined;
926
+ if (isMark) {
927
+ request['symbol'] = market['id'];
928
+ response = await this.fapiPublicGetV1MarkPriceKlines(this.extend(request, params));
929
+ }
930
+ else if (isIndex) {
931
+ request['pair'] = market['id'];
932
+ response = await this.fapiPublicGetV1IndexPriceKlines(this.extend(request, params));
933
+ }
934
+ else {
935
+ request['symbol'] = market['id'];
936
+ if (market['linear']) {
937
+ response = await this.fapiPublicGetV1Klines(this.extend(request, params));
938
+ }
939
+ else {
940
+ response = await this.sapiPublicGetV1Klines(this.extend(request, params));
941
+ }
942
+ }
943
+ //
944
+ // [
945
+ // [
946
+ // 1631158560000,
947
+ // "208.1850",
948
+ // "208.1850",
949
+ // "208.1850",
950
+ // "208.1850",
951
+ // "11.84",
952
+ // 1631158619999,
953
+ // "2464.910400",
954
+ // 1,
955
+ // "11.84",
956
+ // "2464.910400",
957
+ // "0"
958
+ // ]
959
+ // ]
960
+ //
961
+ return this.parseOHLCVs(response, market, timeframe, since, limit);
962
+ }
963
+ parseTrade(trade, market = undefined) {
964
+ //
965
+ // fetchTrades
966
+ //
967
+ // {
968
+ // "id": 3913206,
969
+ // "price": "644.100",
970
+ // "qty": "0.08",
971
+ // "quoteQty": "51.528",
972
+ // "time": 1749784506633,
973
+ // "isBuyerMaker": true
974
+ // }
975
+ //
976
+ // {
977
+ // "id": 657,
978
+ // "price": "1.01000000",
979
+ // "qty": "5.00000000",
980
+ // "baseQty": "4.95049505",
981
+ // "time": 1755156533943,
982
+ // "isBuyerMaker": false
983
+ // }
984
+ //
985
+ // fetchMyTrades
986
+ //
987
+ // {
988
+ // "buyer": false,
989
+ // "commission": "-0.07819010",
990
+ // "commissionAsset": "USDT",
991
+ // "id": 698759,
992
+ // "maker": false,
993
+ // "orderId": 25851813,
994
+ // "price": "7819.01",
995
+ // "qty": "0.002",
996
+ // "quoteQty": "15.63802",
997
+ // "realizedPnl": "-0.91539999",
998
+ // "side": "SELL",
999
+ // "positionSide": "SHORT",
1000
+ // "symbol": "BTCUSDT",
1001
+ // "time": 1569514978020
1002
+ // }
1003
+ //
1004
+ const id = this.safeString(trade, 'id');
1005
+ const symbol = market['symbol'];
1006
+ const currencyId = this.safeString(trade, 'commissionAsset');
1007
+ const currencyCode = this.safeCurrencyCode(currencyId);
1008
+ const amountString = this.safeString(trade, 'qty');
1009
+ const priceString = this.safeString(trade, 'price');
1010
+ const costString = this.safeString2(trade, 'quoteQty', 'baseQty');
1011
+ const timestamp = this.safeInteger(trade, 'time');
1012
+ let side = this.safeStringLower(trade, 'side');
1013
+ const isMaker = this.safeBool(trade, 'maker');
1014
+ let takerOrMaker = undefined;
1015
+ if (isMaker !== undefined) {
1016
+ takerOrMaker = isMaker ? 'maker' : 'taker';
1017
+ }
1018
+ const isBuyerMaker = this.safeBool(trade, 'isBuyerMaker');
1019
+ if (isBuyerMaker !== undefined) {
1020
+ side = isBuyerMaker ? 'sell' : 'buy';
1021
+ }
1022
+ return this.safeTrade({
1023
+ 'id': id,
1024
+ 'info': trade,
1025
+ 'timestamp': timestamp,
1026
+ 'datetime': this.iso8601(timestamp),
1027
+ 'symbol': symbol,
1028
+ 'order': this.safeString(trade, 'orderId'),
1029
+ 'type': undefined,
1030
+ 'side': side,
1031
+ 'takerOrMaker': takerOrMaker,
1032
+ 'price': priceString,
1033
+ 'amount': amountString,
1034
+ 'cost': costString,
1035
+ 'fee': {
1036
+ 'cost': this.parseNumber(Precise["default"].stringAbs(this.safeString(trade, 'commission'))),
1037
+ 'currency': currencyCode,
1038
+ },
1039
+ }, market);
1040
+ }
1041
+ /**
1042
+ * @method
1043
+ * @name aster#fetchTrades
1044
+ * @description get the list of most recent trades for a particular symbol
1045
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#recent-trades-list
1046
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#recent-trades-list
1047
+ * @param {string} symbol unified symbol of the market to fetch trades for
1048
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
1049
+ * @param {int} [limit] the maximum amount of trades to fetch
1050
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1051
+ * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
1052
+ */
1053
+ async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
1054
+ if (symbol === undefined) {
1055
+ throw new errors.ArgumentsRequired(this.id + ' fetchTrades() requires a symbol argument');
1056
+ }
1057
+ await this.loadMarkets();
1058
+ const market = this.market(symbol);
1059
+ const request = {
1060
+ 'symbol': market['id'],
1061
+ };
1062
+ if (limit !== undefined) {
1063
+ if (limit > 1000) {
1064
+ limit = 1000; // Default 500; max 1000.
1065
+ }
1066
+ request['limit'] = limit;
1067
+ }
1068
+ let response = undefined;
1069
+ if (market['swap']) {
1070
+ response = await this.fapiPublicGetV1Trades(this.extend(request, params));
1071
+ //
1072
+ // [
1073
+ // {
1074
+ // "id": 3913206,
1075
+ // "price": "644.100",
1076
+ // "qty": "0.08",
1077
+ // "quoteQty": "51.528",
1078
+ // "time": 1749784506633,
1079
+ // "isBuyerMaker": true
1080
+ // }
1081
+ // ]
1082
+ //
1083
+ }
1084
+ else {
1085
+ response = await this.sapiPublicGetV1Trades(this.extend(request, params));
1086
+ // [
1087
+ // {
1088
+ // "id": 657,
1089
+ // "price": "1.01000000",
1090
+ // "qty": "5.00000000",
1091
+ // "baseQty": "4.95049505",
1092
+ // "time": 1755156533943,
1093
+ // "isBuyerMaker": false
1094
+ // }
1095
+ // ]
1096
+ }
1097
+ return this.parseTrades(response, market, since, limit);
1098
+ }
1099
+ /**
1100
+ * @method
1101
+ * @name aster#fetchMyTrades
1102
+ * @description fetch all trades made by the user
1103
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#account-trade-history-user_data
1104
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#account-trade-list-user_data
1105
+ * @param {string} [symbol] unified market symbol
1106
+ * @param {int} [since] the earliest time in ms to fetch trades for
1107
+ * @param {int} [limit] the maximum number of trades structures to retrieve
1108
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1109
+ * @param {int} [params.until] timestamp in ms for the ending date filter, default is undefined
1110
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
1111
+ */
1112
+ async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1113
+ if (symbol === undefined) {
1114
+ throw new errors.ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol argument');
1115
+ }
1116
+ await this.loadMarkets();
1117
+ const market = this.market(symbol);
1118
+ let request = {
1119
+ 'symbol': market['id'],
1120
+ };
1121
+ if (since !== undefined) {
1122
+ request['startTime'] = since;
1123
+ }
1124
+ if (limit !== undefined) {
1125
+ if (limit > 1000) {
1126
+ limit = 1000; // Default 500; max 1000.
1127
+ }
1128
+ request['limit'] = limit;
1129
+ }
1130
+ [request, params] = this.handleUntilOption('endTime', request, params);
1131
+ let response = undefined;
1132
+ if (market['swap']) {
1133
+ response = await this.fapiPrivateGetV1UserTrades(this.extend(request, params));
1134
+ }
1135
+ else {
1136
+ response = await this.sapiPrivateGetV1UserTrades(this.extend(request, params));
1137
+ }
1138
+ //
1139
+ // [
1140
+ // {
1141
+ // "buyer": false,
1142
+ // "commission": "-0.07819010",
1143
+ // "commissionAsset": "USDT",
1144
+ // "id": 698759,
1145
+ // "maker": false,
1146
+ // "orderId": 25851813,
1147
+ // "price": "7819.01",
1148
+ // "qty": "0.002",
1149
+ // "quoteQty": "15.63802",
1150
+ // "realizedPnl": "-0.91539999",
1151
+ // "side": "SELL",
1152
+ // "positionSide": "SHORT",
1153
+ // "symbol": "BTCUSDT",
1154
+ // "time": 1569514978020
1155
+ // }
1156
+ // ]
1157
+ //
1158
+ return this.parseTrades(response, market, since, limit, params);
1159
+ }
1160
+ /**
1161
+ * @method
1162
+ * @name aster#fetchOrderBook
1163
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
1164
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#depth-information
1165
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#order-book
1166
+ * @param {string} symbol unified symbol of the market to fetch the order book for
1167
+ * @param {int} [limit] the maximum amount of order book entries to return
1168
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1169
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
1170
+ */
1171
+ async fetchOrderBook(symbol, limit = undefined, params = {}) {
1172
+ if (symbol === undefined) {
1173
+ throw new errors.ArgumentsRequired(this.id + ' fetchOrderBook() requires a symbol argument');
1174
+ }
1175
+ await this.loadMarkets();
1176
+ const market = this.market(symbol);
1177
+ const request = {
1178
+ 'symbol': market['id'],
1179
+ };
1180
+ if (limit !== undefined) {
1181
+ // limit: [5, 10, 20, 50, 100, 500, 1000]. Default: 500
1182
+ if (limit > 1000) {
1183
+ limit = 1000; // Default 500; max 1000.
1184
+ }
1185
+ request['limit'] = limit;
1186
+ }
1187
+ let response = undefined;
1188
+ if (market['swap']) {
1189
+ response = await this.fapiPublicGetV1Depth(this.extend(request, params));
1190
+ }
1191
+ else {
1192
+ response = await this.sapiPublicGetV1Depth(this.extend(request, params));
1193
+ }
1194
+ //
1195
+ // {
1196
+ // "lastUpdateId": 1027024,
1197
+ // "E": 1589436922972, // Message output time
1198
+ // "T": 1589436922959, // Transaction time
1199
+ // "bids": [
1200
+ // [
1201
+ // "4.00000000", // PRICE
1202
+ // "431.00000000" // QTY
1203
+ // ]
1204
+ // ],
1205
+ // "asks": [
1206
+ // [
1207
+ // "4.00000200",
1208
+ // "12.00000000"
1209
+ // ]
1210
+ // ]
1211
+ // }
1212
+ //
1213
+ const timestamp = this.safeInteger(response, 'T');
1214
+ return this.parseOrderBook(response, symbol, timestamp, 'bids', 'asks');
1215
+ }
1216
+ /**
1217
+ * @method
1218
+ * @name aster#fetchFundingRateHistory
1219
+ * @description fetches historical funding rate prices
1220
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-funding-rate-history
1221
+ * @param {string} symbol unified symbol of the market to fetch the funding rate history for
1222
+ * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
1223
+ * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
1224
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1225
+ * @param {int} [params.until] timestamp in ms of the latest funding rate
1226
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
1227
+ */
1228
+ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1229
+ await this.loadMarkets();
1230
+ let request = {};
1231
+ if (symbol !== undefined) {
1232
+ const market = this.market(symbol);
1233
+ request['symbol'] = market['id'];
1234
+ }
1235
+ if (since !== undefined) {
1236
+ request['startTime'] = since;
1237
+ }
1238
+ if (limit !== undefined) {
1239
+ if (limit > 1000) {
1240
+ limit = 1000; // Default 100; max 1000
1241
+ }
1242
+ request['limit'] = limit;
1243
+ }
1244
+ [request, params] = this.handleUntilOption('endTime', request, params);
1245
+ const response = await this.fapiPublicGetV1FundingRate(this.extend(request, params));
1246
+ //
1247
+ // [
1248
+ // {
1249
+ // "symbol": "BTCUSDT",
1250
+ // "fundingTime": 1747209600000,
1251
+ // "fundingRate": "0.00010000"
1252
+ // }
1253
+ // ]
1254
+ //
1255
+ const rates = [];
1256
+ for (let i = 0; i < response.length; i++) {
1257
+ const entry = response[i];
1258
+ const timestamp = this.safeInteger(entry, 'fundingTime');
1259
+ rates.push({
1260
+ 'info': entry,
1261
+ 'symbol': this.safeSymbol(this.safeString(entry, 'symbol'), undefined, undefined, 'swap'),
1262
+ 'fundingRate': this.safeNumber(entry, 'fundingRate'),
1263
+ 'timestamp': timestamp,
1264
+ 'datetime': this.iso8601(timestamp),
1265
+ });
1266
+ }
1267
+ const sorted = this.sortBy(rates, 'timestamp');
1268
+ return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
1269
+ }
1270
+ parseTicker(ticker, market = undefined) {
1271
+ //
1272
+ // spot
1273
+ // {
1274
+ // "symbol": "BTCUSDT",
1275
+ // "priceChange": "-2274.38",
1276
+ // "priceChangePercent": "-2.049",
1277
+ // "weightedAvgPrice": "109524.37084136",
1278
+ // "lastPrice": "108738.78",
1279
+ // "lastQty": "0.00034",
1280
+ // "openPrice": "111013.16",
1281
+ // "highPrice": "111975.81",
1282
+ // "lowPrice": "107459.25",
1283
+ // "volume": "28.67876",
1284
+ // "quoteVolume": "3141023.14551030",
1285
+ // "openTime": "1760578800000",
1286
+ // "closeTime": "1760665024749",
1287
+ // "firstId": "37447",
1288
+ // "lastId": "39698",
1289
+ // "count": "2252",
1290
+ // "baseAsset": "BTC",
1291
+ // "quoteAsset": "USDT",
1292
+ // "bidPrice": "108705.11",
1293
+ // "bidQty": "0.03351",
1294
+ // "askPrice": "108725.99",
1295
+ // "askQty": "0.08724"
1296
+ // }
1297
+ // swap
1298
+ // {
1299
+ // "symbol": "BTCUSDT",
1300
+ // "priceChange": "1845.7",
1301
+ // "priceChangePercent": "1.755",
1302
+ // "weightedAvgPrice": "105515.5",
1303
+ // "lastPrice": "107037.7",
1304
+ // "lastQty": "0.004",
1305
+ // "openPrice": "105192.0",
1306
+ // "highPrice": "107223.5",
1307
+ // "lowPrice": "104431.6",
1308
+ // "volume": "8753.286",
1309
+ // "quoteVolume": "923607368.61",
1310
+ // "openTime": 1749976620000,
1311
+ // "closeTime": 1750063053754,
1312
+ // "firstId": 24195078,
1313
+ // "lastId": 24375783,
1314
+ // "count": 180706
1315
+ // }
1316
+ //
1317
+ const timestamp = this.safeInteger(ticker, 'closeTime');
1318
+ let marketType = undefined;
1319
+ if ('bidQty' in ticker) {
1320
+ marketType = 'spot';
1321
+ }
1322
+ else {
1323
+ marketType = 'contract';
1324
+ }
1325
+ const marketId = this.safeString(ticker, 'symbol');
1326
+ market = this.safeMarket(marketId, market, undefined, marketType);
1327
+ const symbol = market['symbol'];
1328
+ const last = this.safeString(ticker, 'lastPrice');
1329
+ const open = this.safeString(ticker, 'openPrice');
1330
+ let percentage = this.safeString(ticker, 'priceChangePercent');
1331
+ percentage = Precise["default"].stringMul(percentage, '100');
1332
+ const quoteVolume = this.safeString(ticker, 'quoteVolume');
1333
+ const baseVolume = this.safeString(ticker, 'volume');
1334
+ const high = this.safeString(ticker, 'highPrice');
1335
+ const low = this.safeString(ticker, 'lowPrice');
1336
+ return this.safeTicker({
1337
+ 'symbol': symbol,
1338
+ 'timestamp': timestamp,
1339
+ 'datetime': this.iso8601(timestamp),
1340
+ 'high': high,
1341
+ 'low': low,
1342
+ 'bid': this.safeString(ticker, 'bidPrice'),
1343
+ 'bidVolume': this.safeString(ticker, 'bidQty'),
1344
+ 'ask': this.safeString(ticker, 'askPrice'),
1345
+ 'askVolume': this.safeString(ticker, 'askQty'),
1346
+ 'vwap': undefined,
1347
+ 'open': open,
1348
+ 'close': last,
1349
+ 'last': last,
1350
+ 'previousClose': undefined,
1351
+ 'change': undefined,
1352
+ 'percentage': percentage,
1353
+ 'average': undefined,
1354
+ 'baseVolume': baseVolume,
1355
+ 'quoteVolume': quoteVolume,
1356
+ 'markPrice': undefined,
1357
+ 'indexPrice': undefined,
1358
+ 'info': ticker,
1359
+ }, market);
1360
+ }
1361
+ /**
1362
+ * @method
1363
+ * @name aster#fetchTicker
1364
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1365
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#24h-price-change
1366
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#24hr-ticker-price-change-statistics
1367
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
1368
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1369
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1370
+ */
1371
+ async fetchTicker(symbol, params = {}) {
1372
+ if (symbol === undefined) {
1373
+ throw new errors.ArgumentsRequired(this.id + ' fetchTicker() requires a symbol argument');
1374
+ }
1375
+ await this.loadMarkets();
1376
+ const market = this.market(symbol);
1377
+ const request = {
1378
+ 'symbol': market['id'],
1379
+ };
1380
+ let response = undefined;
1381
+ if (market['swap']) {
1382
+ response = await this.fapiPublicGetV1Ticker24hr(this.extend(request, params));
1383
+ //
1384
+ // {
1385
+ // "symbol": "BTCUSDT",
1386
+ // "priceChange": "1845.7",
1387
+ // "priceChangePercent": "1.755",
1388
+ // "weightedAvgPrice": "105515.5",
1389
+ // "lastPrice": "107037.7",
1390
+ // "lastQty": "0.004",
1391
+ // "openPrice": "105192.0",
1392
+ // "highPrice": "107223.5",
1393
+ // "lowPrice": "104431.6",
1394
+ // "volume": "8753.286",
1395
+ // "quoteVolume": "923607368.61",
1396
+ // "openTime": 1749976620000,
1397
+ // "closeTime": 1750063053754,
1398
+ // "firstId": 24195078,
1399
+ // "lastId": 24375783,
1400
+ // "count": 180706
1401
+ // }
1402
+ //
1403
+ }
1404
+ else {
1405
+ response = await this.sapiPublicGetV1Ticker24hr(this.extend(request, params));
1406
+ // {
1407
+ // "symbol": "BTCUSDT",
1408
+ // "priceChange": "-2274.38",
1409
+ // "priceChangePercent": "-2.049",
1410
+ // "weightedAvgPrice": "109524.37084136",
1411
+ // "lastPrice": "108738.78",
1412
+ // "lastQty": "0.00034",
1413
+ // "openPrice": "111013.16",
1414
+ // "highPrice": "111975.81",
1415
+ // "lowPrice": "107459.25",
1416
+ // "volume": "28.67876",
1417
+ // "quoteVolume": "3141023.14551030",
1418
+ // "openTime": "1760578800000",
1419
+ // "closeTime": "1760665024749",
1420
+ // "firstId": "37447",
1421
+ // "lastId": "39698",
1422
+ // "count": "2252",
1423
+ // "baseAsset": "BTC",
1424
+ // "quoteAsset": "USDT",
1425
+ // "bidPrice": "108705.11",
1426
+ // "bidQty": "0.03351",
1427
+ // "askPrice": "108725.99",
1428
+ // "askQty": "0.08724"
1429
+ // }
1430
+ }
1431
+ return this.parseTicker(response, market);
1432
+ }
1433
+ /**
1434
+ * @method
1435
+ * @name aster#fetchTickers
1436
+ * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1437
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#24h-price-change
1438
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#24hr-ticker-price-change-statistics
1439
+ * @param {string[]} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1440
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1441
+ * @param {string} [params.subType] "linear" or "inverse"
1442
+ * @param {string} [params.type] 'spot', 'option', use params["subType"] for swap and future markets
1443
+ * @returns {object} an array of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1444
+ */
1445
+ async fetchTickers(symbols = undefined, params = {}) {
1446
+ await this.loadMarkets();
1447
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
1448
+ const market = this.getMarketFromSymbols(symbols);
1449
+ let type = undefined;
1450
+ [type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
1451
+ let subType = undefined;
1452
+ [subType, params] = this.handleSubTypeAndParams('fetchTickers', market, params);
1453
+ let response = undefined;
1454
+ if (this.isLinear(type, subType)) {
1455
+ response = await this.fapiPublicGetV1Ticker24hr(params);
1456
+ }
1457
+ else if (type === 'spot') {
1458
+ response = await this.sapiPublicGetV1Ticker24hr(params);
1459
+ }
1460
+ else {
1461
+ throw new errors.NotSupported(this.id + ' fetchTickers() does not support ' + type + ' markets yet');
1462
+ }
1463
+ //
1464
+ // [
1465
+ // {
1466
+ // "symbol": "BTCUSDT",
1467
+ // "priceChange": "1845.7",
1468
+ // "priceChangePercent": "1.755",
1469
+ // "weightedAvgPrice": "105515.5",
1470
+ // "lastPrice": "107037.7",
1471
+ // "lastQty": "0.004",
1472
+ // "openPrice": "105192.0",
1473
+ // "highPrice": "107223.5",
1474
+ // "lowPrice": "104431.6",
1475
+ // "volume": "8753.286",
1476
+ // "quoteVolume": "923607368.61",
1477
+ // "openTime": 1749976620000,
1478
+ // "closeTime": 1750063053754,
1479
+ // "firstId": 24195078,
1480
+ // "lastId": 24375783,
1481
+ // "count": 180706
1482
+ // }
1483
+ // ]
1484
+ //
1485
+ return this.parseTickers(response, symbols);
1486
+ }
1487
+ parseFundingRate(contract, market = undefined) {
1488
+ //
1489
+ // {
1490
+ // "symbol": "BTCUSDT",
1491
+ // "markPrice": "106729.84047826",
1492
+ // "indexPrice": "106775.72673913",
1493
+ // "estimatedSettlePrice": "106708.84997006",
1494
+ // "lastFundingRate": "0.00010000",
1495
+ // "interestRate": "0.00010000",
1496
+ // "nextFundingTime": 1750147200000,
1497
+ // "time": 1750146970000
1498
+ // }
1499
+ // {
1500
+ // "symbol": "INJUSDT",
1501
+ // "interestRate": "0.00010000",
1502
+ // "time": 1756197479000,
1503
+ // "fundingIntervalHours": 8,
1504
+ // "fundingFeeCap": 0.03,
1505
+ // "fundingFeeFloor": -0.03
1506
+ // }
1507
+ //
1508
+ const marketId = this.safeString(contract, 'symbol');
1509
+ const nextFundingTimestamp = this.safeInteger(contract, 'nextFundingTime');
1510
+ const timestamp = this.safeInteger(contract, 'time');
1511
+ const interval = this.safeString(contract, 'fundingIntervalHours');
1512
+ let intervalString = undefined;
1513
+ if (interval !== undefined) {
1514
+ intervalString = interval + 'h';
1515
+ }
1516
+ return {
1517
+ 'info': contract,
1518
+ 'symbol': this.safeSymbol(marketId, market, undefined, 'contract'),
1519
+ 'markPrice': this.safeNumber(contract, 'markPrice'),
1520
+ 'indexPrice': this.safeNumber(contract, 'indexPrice'),
1521
+ 'interestRate': this.safeNumber(contract, 'interestRate'),
1522
+ 'estimatedSettlePrice': this.safeNumber(contract, 'estimatedSettlePrice'),
1523
+ 'timestamp': timestamp,
1524
+ 'datetime': this.iso8601(timestamp),
1525
+ 'fundingRate': this.safeNumber(contract, 'lastFundingRate'),
1526
+ 'fundingTimestamp': undefined,
1527
+ 'fundingDatetime': undefined,
1528
+ 'nextFundingRate': undefined,
1529
+ 'nextFundingTimestamp': nextFundingTimestamp,
1530
+ 'nextFundingDatetime': this.iso8601(nextFundingTimestamp),
1531
+ 'previousFundingRate': undefined,
1532
+ 'previousFundingTimestamp': undefined,
1533
+ 'previousFundingDatetime': undefined,
1534
+ 'interval': intervalString,
1535
+ };
1536
+ }
1537
+ /**
1538
+ * @method
1539
+ * @name aster#fetchFundingRate
1540
+ * @description fetch the current funding rate
1541
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price
1542
+ * @param {string} symbol unified market symbol
1543
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1544
+ * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
1545
+ */
1546
+ async fetchFundingRate(symbol, params = {}) {
1547
+ if (symbol === undefined) {
1548
+ throw new errors.ArgumentsRequired(this.id + ' fetchFundingRate() requires a symbol argument');
1549
+ }
1550
+ await this.loadMarkets();
1551
+ const market = this.market(symbol);
1552
+ const request = {
1553
+ 'symbol': market['id'],
1554
+ };
1555
+ const response = await this.fapiPublicGetV1PremiumIndex(this.extend(request, params));
1556
+ //
1557
+ // {
1558
+ // "symbol": "BTCUSDT",
1559
+ // "markPrice": "106729.84047826",
1560
+ // "indexPrice": "106775.72673913",
1561
+ // "estimatedSettlePrice": "106708.84997006",
1562
+ // "lastFundingRate": "0.00010000",
1563
+ // "interestRate": "0.00010000",
1564
+ // "nextFundingTime": 1750147200000,
1565
+ // "time": 1750146970000
1566
+ // }
1567
+ //
1568
+ return this.parseFundingRate(response, market);
1569
+ }
1570
+ /**
1571
+ * @method
1572
+ * @name aster#fetchFundingRates
1573
+ * @description fetch the current funding rate for multiple symbols
1574
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#24hr-ticker-price-change-statistics
1575
+ * @param {string[]} [symbols] list of unified market symbols
1576
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1577
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
1578
+ */
1579
+ async fetchFundingRates(symbols = undefined, params = {}) {
1580
+ await this.loadMarkets();
1581
+ symbols = this.marketSymbols(symbols);
1582
+ const response = await this.fapiPublicGetV1PremiumIndex(this.extend(params));
1583
+ //
1584
+ // [
1585
+ // {
1586
+ // "symbol": "BTCUSDT",
1587
+ // "markPrice": "106729.84047826",
1588
+ // "indexPrice": "106775.72673913",
1589
+ // "estimatedSettlePrice": "106708.84997006",
1590
+ // "lastFundingRate": "0.00010000",
1591
+ // "interestRate": "0.00010000",
1592
+ // "nextFundingTime": 1750147200000,
1593
+ // "time": 1750146970000
1594
+ // }
1595
+ // ]
1596
+ //
1597
+ return this.parseFundingRates(response, symbols);
1598
+ }
1599
+ /**
1600
+ * @method
1601
+ * @name aster#fetchFundingIntervals
1602
+ * @description fetch the funding rate interval for multiple markets
1603
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-funding-rate-config
1604
+ * @param {string[]} [symbols] list of unified market symbols
1605
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1606
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
1607
+ */
1608
+ async fetchFundingIntervals(symbols = undefined, params = {}) {
1609
+ await this.loadMarkets();
1610
+ if (symbols !== undefined) {
1611
+ symbols = this.marketSymbols(symbols);
1612
+ }
1613
+ const response = await this.fapiPublicGetV1FundingInfo(params);
1614
+ //
1615
+ // [
1616
+ // {
1617
+ // "symbol": "INJUSDT",
1618
+ // "interestRate": "0.00010000",
1619
+ // "time": 1756197479000,
1620
+ // "fundingIntervalHours": 8,
1621
+ // "fundingFeeCap": 0.03,
1622
+ // "fundingFeeFloor": -0.03
1623
+ // }
1624
+ // ]
1625
+ //
1626
+ return this.parseFundingRates(response, symbols);
1627
+ }
1628
+ parseBalance(response) {
1629
+ const result = { 'info': response };
1630
+ for (let i = 0; i < response.length; i++) {
1631
+ const balance = response[i];
1632
+ const currencyId = this.safeString(balance, 'asset');
1633
+ const code = this.safeCurrencyCode(currencyId);
1634
+ const account = this.account();
1635
+ account['free'] = this.safeString2(balance, 'free', 'maxWithdrawAmount');
1636
+ account['used'] = this.safeString(balance, 'locked');
1637
+ account['total'] = this.safeString(balance, 'walletBalance');
1638
+ result[code] = account;
1639
+ }
1640
+ return this.safeBalance(result);
1641
+ }
1642
+ /**
1643
+ * @method
1644
+ * @name aster#fetchBalance
1645
+ * @description query for balance and get the amount of funds available for trading or funds locked in orders
1646
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#account-information-v4-user_data
1647
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#account-information-user_data
1648
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1649
+ * @param {string} [params.subType] "linear" or "inverse"
1650
+ * @param {string} [params.type] 'spot', 'option', use params["subType"] for swap and future markets
1651
+ * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1652
+ */
1653
+ async fetchBalance(params = {}) {
1654
+ let type = undefined;
1655
+ [type, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
1656
+ let subType = undefined;
1657
+ [subType, params] = this.handleSubTypeAndParams('fetchBalance', undefined, params);
1658
+ let response = undefined;
1659
+ let data = undefined;
1660
+ if (this.isLinear(type, subType)) {
1661
+ response = await this.fapiPrivateGetV4Account(params);
1662
+ data = this.safeList(response, 'assets', []);
1663
+ //
1664
+ // [
1665
+ // {
1666
+ // "asset": "USDT", // asset name
1667
+ // "walletBalance": "23.72469206", // wallet balance
1668
+ // "unrealizedProfit": "0.00000000", // unrealized profit
1669
+ // "marginBalance": "23.72469206", // margin balance
1670
+ // "maintMargin": "0.00000000", // maintenance margin required
1671
+ // "initialMargin": "0.00000000", // total initial margin required with current mark price
1672
+ // "positionInitialMargin": "0.00000000", //initial margin required for positions with current mark price
1673
+ // "openOrderInitialMargin": "0.00000000", // initial margin required for open orders with current mark price
1674
+ // "crossWalletBalance": "23.72469206", // crossed wallet balance
1675
+ // "crossUnPnl": "0.00000000", // unrealized profit of crossed positions
1676
+ // "availableBalance": "23.72469206", // available balance
1677
+ // "maxWithdrawAmount": "23.72469206", // maximum amount for transfer out
1678
+ // "marginAvailable": true, // whether the asset can be used as margin in Multi-Assets mode
1679
+ // "updateTime": 1625474304765 // last update time
1680
+ // }
1681
+ // ]
1682
+ //
1683
+ }
1684
+ else if (type === 'spot') {
1685
+ response = await this.sapiPrivateGetV1Account(params);
1686
+ data = this.safeList(response, 'balances', []);
1687
+ //
1688
+ // [
1689
+ // {
1690
+ // "asset": "BTC",
1691
+ // "free": "4723846.89208129",
1692
+ // "locked": "0.00000000"
1693
+ // }
1694
+ // ]
1695
+ //
1696
+ }
1697
+ else {
1698
+ throw new errors.NotSupported(this.id + ' fetchBalance() does not support ' + type + ' markets yet');
1699
+ }
1700
+ return this.parseBalance(data);
1701
+ }
1702
+ /**
1703
+ * @method
1704
+ * @name aster#setMarginMode
1705
+ * @description set margin mode to 'cross' or 'isolated'
1706
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#change-margin-type-trade
1707
+ * @param {string} marginMode 'cross' or 'isolated'
1708
+ * @param {string} symbol unified market symbol
1709
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1710
+ * @returns {object} response from the exchange
1711
+ */
1712
+ async setMarginMode(marginMode, symbol = undefined, params = {}) {
1713
+ if (symbol === undefined) {
1714
+ throw new errors.ArgumentsRequired(this.id + ' setMarginMode() requires a symbol argument');
1715
+ }
1716
+ marginMode = marginMode.toUpperCase();
1717
+ if (marginMode === 'CROSS') {
1718
+ marginMode = 'CROSSED';
1719
+ }
1720
+ if ((marginMode !== 'ISOLATED') && (marginMode !== 'CROSSED')) {
1721
+ throw new errors.BadRequest(this.id + ' marginMode must be either isolated or cross');
1722
+ }
1723
+ await this.loadMarkets();
1724
+ const market = this.market(symbol);
1725
+ const request = {
1726
+ 'symbol': market['id'],
1727
+ 'marginType': marginMode,
1728
+ };
1729
+ const response = await this.fapiPrivatePostV1MarginType(this.extend(request, params));
1730
+ //
1731
+ // {
1732
+ // "amount": 100.0,
1733
+ // "code": 200,
1734
+ // "msg": "Successfully modify position margin.",
1735
+ // "type": 1
1736
+ // }
1737
+ //
1738
+ return response;
1739
+ }
1740
+ /**
1741
+ * @method
1742
+ * @name aster#fetchPositionMode
1743
+ * @description fetchs the position mode, hedged or one way, hedged for aster is set identically for all linear markets or all inverse markets
1744
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-current-position-modeuser_data
1745
+ * @param {string} symbol unified symbol of the market to fetch the order book for
1746
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1747
+ * @returns {object} an object detailing whether the market is in hedged or one-way mode
1748
+ */
1749
+ async fetchPositionMode(symbol = undefined, params = {}) {
1750
+ const response = await this.fapiPrivateGetV1PositionSideDual(params);
1751
+ //
1752
+ // {
1753
+ // "dualSidePosition": true // "true": Hedge Mode; "false": One-way Mode
1754
+ // }
1755
+ //
1756
+ const dualSidePosition = this.safeBool(response, 'dualSidePosition');
1757
+ return {
1758
+ 'info': response,
1759
+ 'hedged': (dualSidePosition === true),
1760
+ };
1761
+ }
1762
+ /**
1763
+ * @method
1764
+ * @name aster#setPositionMode
1765
+ * @description set hedged to true or false for a market
1766
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#change-position-modetrade
1767
+ * @param {bool} hedged set to true to use dualSidePosition
1768
+ * @param {string} symbol not used by bingx setPositionMode ()
1769
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1770
+ * @returns {object} response from the exchange
1771
+ */
1772
+ async setPositionMode(hedged, symbol = undefined, params = {}) {
1773
+ const request = {
1774
+ 'dualSidePosition': hedged,
1775
+ };
1776
+ //
1777
+ // {
1778
+ // "code": 200,
1779
+ // "msg": "success"
1780
+ // }
1781
+ //
1782
+ return await this.fapiPrivatePostV1PositionSideDual(this.extend(request, params));
1783
+ }
1784
+ parseTradingFee(fee, market = undefined) {
1785
+ const marketId = this.safeString(fee, 'symbol');
1786
+ market = this.safeMarket(marketId, market);
1787
+ const symbol = this.safeSymbol(marketId, market);
1788
+ return {
1789
+ 'info': fee,
1790
+ 'symbol': symbol,
1791
+ 'maker': this.safeNumber(fee, 'makerCommissionRate'),
1792
+ 'taker': this.safeNumber(fee, 'takerCommissionRate'),
1793
+ 'percentage': false,
1794
+ 'tierBased': false,
1795
+ };
1796
+ }
1797
+ /**
1798
+ * @method
1799
+ * @name aster#fetchTradingFee
1800
+ * @description fetch the trading fees for a market
1801
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#get-symbol-fees
1802
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#user-commission-rate-user_data
1803
+ * @param {string} symbol unified market symbol
1804
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1805
+ * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
1806
+ */
1807
+ async fetchTradingFee(symbol, params = {}) {
1808
+ await this.loadMarkets();
1809
+ const market = this.market(symbol);
1810
+ const request = {
1811
+ 'symbol': market['id'],
1812
+ };
1813
+ let response = undefined;
1814
+ if (market['swap']) {
1815
+ response = await this.fapiPrivateGetV1CommissionRate(this.extend(request, params));
1816
+ }
1817
+ else {
1818
+ response = await this.sapiPrivateGetV1CommissionRate(this.extend(request, params));
1819
+ }
1820
+ //
1821
+ // {
1822
+ // "symbol": "BTCUSDT",
1823
+ // "makerCommissionRate": "0.0002",
1824
+ // "takerCommissionRate": "0.0004"
1825
+ // }
1826
+ //
1827
+ return this.parseTradingFee(response, market);
1828
+ }
1829
+ parseOrderStatus(status) {
1830
+ const statuses = {
1831
+ 'NEW': 'open',
1832
+ 'PARTIALLY_FILLED': 'open',
1833
+ 'FILLED': 'closed',
1834
+ 'CANCELED': 'canceled',
1835
+ 'REJECTED': 'canceled',
1836
+ 'EXPIRED': 'canceled',
1837
+ };
1838
+ return this.safeString(statuses, status, status);
1839
+ }
1840
+ parseOrderType(type) {
1841
+ const types = {
1842
+ 'LIMIT': 'limit',
1843
+ 'MARKET': 'market',
1844
+ 'STOP': 'limit',
1845
+ 'STOP_MARKET': 'market',
1846
+ 'TAKE_PROFIT': 'limit',
1847
+ 'TAKE_PROFIT_MARKET': 'market',
1848
+ 'TRAILING_STOP_MARKET': 'market',
1849
+ };
1850
+ return this.safeString(types, type, type);
1851
+ }
1852
+ parseOrder(order, market = undefined) {
1853
+ //
1854
+ // swap
1855
+ // {
1856
+ // "avgPrice": "0.00000",
1857
+ // "clientOrderId": "abc",
1858
+ // "cumQuote": "0",
1859
+ // "executedQty": "0",
1860
+ // "orderId": 1917641,
1861
+ // "origQty": "0.40",
1862
+ // "origType": "TRAILING_STOP_MARKET",
1863
+ // "price": "0",
1864
+ // "reduceOnly": false,
1865
+ // "side": "BUY",
1866
+ // "positionSide": "SHORT",
1867
+ // "status": "NEW",
1868
+ // "stopPrice": "9300",
1869
+ // "closePosition": false,
1870
+ // "symbol": "BTCUSDT",
1871
+ // "time": 1579276756075,
1872
+ // "timeInForce": "GTC",
1873
+ // "type": "TRAILING_STOP_MARKET",
1874
+ // "activatePrice": "9020",
1875
+ // "priceRate": "0.3",
1876
+ // "updateTime": 1579276756075,
1877
+ // "workingType": "CONTRACT_PRICE",
1878
+ // "priceProtect": false
1879
+ // }
1880
+ // spot
1881
+ // {
1882
+ // "orderId": 38,
1883
+ // "symbol": "ADA25SLP25",
1884
+ // "status": "FILLED",
1885
+ // "clientOrderId": "afMd4GBQyHkHpGWdiy34Li",
1886
+ // "price": "20",
1887
+ // "avgPrice": "12.0000000000000000",
1888
+ // "origQty": "10",
1889
+ // "executedQty": "10",
1890
+ // "cumQuote": "120",
1891
+ // "timeInForce": "GTC",
1892
+ // "type": "LIMIT",
1893
+ // "side": "BUY",
1894
+ // "stopPrice": "0",
1895
+ // "origType": "LIMIT",
1896
+ // "time": 1649913186270,
1897
+ // "updateTime": 1649913186297
1898
+ // }
1899
+ //
1900
+ const info = order;
1901
+ const marketId = this.safeString(order, 'symbol');
1902
+ market = this.safeMarket(marketId, market);
1903
+ const side = this.safeStringLower(order, 'side');
1904
+ const timestamp = this.safeInteger(order, 'time');
1905
+ const lastTradeTimestamp = this.safeInteger(order, 'updateTime');
1906
+ const statusId = this.safeStringUpper(order, 'status');
1907
+ const rawType = this.safeStringUpper(order, 'type');
1908
+ const stopPriceString = this.safeString(order, 'stopPrice');
1909
+ const triggerPrice = this.parseNumber(this.omitZero(stopPriceString));
1910
+ return this.safeOrder({
1911
+ 'info': info,
1912
+ 'id': this.safeString(order, 'orderId'),
1913
+ 'clientOrderId': this.safeString(order, 'clientOrderId'),
1914
+ 'symbol': this.safeSymbol(marketId, market),
1915
+ 'timestamp': timestamp,
1916
+ 'datetime': this.iso8601(timestamp),
1917
+ 'lastTradeTimestamp': lastTradeTimestamp,
1918
+ 'lastUpdateTimestamp': this.safeInteger(order, 'updateTime'),
1919
+ 'type': this.parseOrderType(rawType),
1920
+ 'timeInForce': this.safeString(order, 'timeInForce'),
1921
+ 'postOnly': undefined,
1922
+ 'side': side,
1923
+ 'price': this.safeString(order, 'price'),
1924
+ 'triggerPrice': triggerPrice,
1925
+ 'average': this.safeString(order, 'avgPrice'),
1926
+ 'cost': this.safeString(order, 'cumQuote'),
1927
+ 'amount': this.safeString(order, 'origQty'),
1928
+ 'filled': this.safeString(order, 'executedQty'),
1929
+ 'remaining': undefined,
1930
+ 'status': this.parseOrderStatus(statusId),
1931
+ 'fee': undefined,
1932
+ 'trades': undefined,
1933
+ 'reduceOnly': this.safeBool2(order, 'reduceOnly', 'ro'),
1934
+ }, market);
1935
+ }
1936
+ /**
1937
+ * @method
1938
+ * @name aster#fetchOrder
1939
+ * @description fetches information on an order made by the user
1940
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#query-order-user_data
1941
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#query-order-user_data
1942
+ * @param {string} id the order id
1943
+ * @param {string} symbol unified symbol of the market the order was made in
1944
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1945
+ * @param {string} [params.clientOrderId] a unique id for the order
1946
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1947
+ */
1948
+ async fetchOrder(id, symbol = undefined, params = {}) {
1949
+ if (symbol === undefined) {
1950
+ throw new errors.ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument');
1951
+ }
1952
+ await this.loadMarkets();
1953
+ const market = this.market(symbol);
1954
+ const request = {
1955
+ 'symbol': market['id'],
1956
+ };
1957
+ const clientOrderId = this.safeString2(params, 'clientOrderId', 'clientOid');
1958
+ params = this.omit(params, ['clientOrderId', 'clientOid']);
1959
+ if (clientOrderId !== undefined) {
1960
+ request['origClientOrderId'] = clientOrderId;
1961
+ }
1962
+ else {
1963
+ request['orderId'] = id;
1964
+ }
1965
+ let response = undefined;
1966
+ if (market['swap']) {
1967
+ response = await this.fapiPrivateGetV1Order(this.extend(request, params));
1968
+ }
1969
+ else {
1970
+ response = await this.sapiPrivateGetV1Order(this.extend(request, params));
1971
+ }
1972
+ return this.parseOrder(response, market);
1973
+ }
1974
+ /**
1975
+ * @method
1976
+ * @name aster#fetchOpenOrder
1977
+ * @description fetch an open order by the id
1978
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#query-current-open-order-user_data
1979
+ * @param {string} id order id
1980
+ * @param {string} symbol unified market symbol
1981
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1982
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1983
+ */
1984
+ async fetchOpenOrder(id, symbol = undefined, params = {}) {
1985
+ if (symbol === undefined) {
1986
+ throw new errors.ArgumentsRequired(this.id + ' fetchOpenOrder() requires a symbol argument');
1987
+ }
1988
+ await this.loadMarkets();
1989
+ const market = this.market(symbol);
1990
+ const request = {
1991
+ 'symbol': market['id'],
1992
+ };
1993
+ const clientOrderId = this.safeString2(params, 'clientOrderId', 'clientOid');
1994
+ params = this.omit(params, ['clientOrderId', 'clientOid']);
1995
+ if (clientOrderId !== undefined) {
1996
+ request['origClientOrderId'] = clientOrderId;
1997
+ }
1998
+ else {
1999
+ request['orderId'] = id;
2000
+ }
2001
+ const response = await this.fapiPrivateGetV1OpenOrder(this.extend(request, params));
2002
+ return this.parseOrder(response, market);
2003
+ }
2004
+ /**
2005
+ * @method
2006
+ * @name aster#fetchOrders
2007
+ * @description fetches information on multiple orders made by the user
2008
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#query-all-orders-user_data
2009
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#all-orders-user_data
2010
+ * @param {string} symbol unified market symbol of the market orders were made in
2011
+ * @param {int} [since] the earliest time in ms to fetch orders for
2012
+ * @param {int} [limit] the maximum number of order structures to retrieve
2013
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2014
+ * @param {int} [params.until] the latest time in ms to fetch orders for
2015
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2016
+ */
2017
+ async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2018
+ await this.loadMarkets();
2019
+ if (symbol === undefined) {
2020
+ throw new errors.ArgumentsRequired(this.id + ' fetchOrders() requires a symbol argument');
2021
+ }
2022
+ const market = this.market(symbol);
2023
+ let request = {
2024
+ 'symbol': market['id'],
2025
+ };
2026
+ if (since !== undefined) {
2027
+ request['startTime'] = since;
2028
+ }
2029
+ if (limit !== undefined) {
2030
+ if (limit > 1000) {
2031
+ limit = 1000; // Default 500; max 1000
2032
+ }
2033
+ request['limit'] = limit;
2034
+ }
2035
+ [request, params] = this.handleUntilOption('endTime', request, params);
2036
+ let response = undefined;
2037
+ if (market['swap']) {
2038
+ response = await this.fapiPrivateGetV1AllOrders(this.extend(request, params));
2039
+ }
2040
+ else {
2041
+ response = await this.sapiPrivateGetV1AllOrders(this.extend(request, params));
2042
+ }
2043
+ return this.parseOrders(response, market, since, limit);
2044
+ }
2045
+ /**
2046
+ * @method
2047
+ * @name aster#fetchOpenOrders
2048
+ * @description fetch all unfilled currently open orders
2049
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#current-open-orders-user_data
2050
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#current-all-open-orders-user_data
2051
+ * @param {string} symbol unified market symbol
2052
+ * @param {int} [since] the earliest time in ms to fetch open orders for
2053
+ * @param {int} [limit] the maximum number of open orders structures to retrieve
2054
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2055
+ * @param {string} [params.subType] "linear" or "inverse"
2056
+ * @param {string} [params.type] 'spot', 'option', use params["subType"] for swap and future markets
2057
+ * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2058
+ */
2059
+ async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2060
+ await this.loadMarkets();
2061
+ const request = {};
2062
+ let market = undefined;
2063
+ let type = undefined;
2064
+ let subType = undefined;
2065
+ [subType, params] = this.handleSubTypeAndParams('fetchOpenOrders', market, params);
2066
+ if (symbol !== undefined) {
2067
+ market = this.market(symbol);
2068
+ request['symbol'] = market['id'];
2069
+ }
2070
+ [type, params] = this.handleMarketTypeAndParams('fetchOpenOrders', market, params);
2071
+ let response = undefined;
2072
+ if (this.isLinear(type, subType)) {
2073
+ response = await this.fapiPrivateGetV1OpenOrders(this.extend(request, params));
2074
+ }
2075
+ else if (type === 'spot') {
2076
+ response = await this.sapiPrivateGetV1OpenOrders(this.extend(request, params));
2077
+ }
2078
+ else {
2079
+ throw new errors.NotSupported(this.id + ' fetchOpenOrders() does not support ' + type + ' markets yet');
2080
+ }
2081
+ //
2082
+ // [
2083
+ // {
2084
+ // "avgPrice": "0.00000",
2085
+ // "clientOrderId": "abc",
2086
+ // "cumQuote": "0",
2087
+ // "executedQty": "0",
2088
+ // "orderId": 1917641,
2089
+ // "origQty": "0.40",
2090
+ // "origType": "TRAILING_STOP_MARKET",
2091
+ // "price": "0",
2092
+ // "reduceOnly": false,
2093
+ // "side": "BUY",
2094
+ // "positionSide": "SHORT",
2095
+ // "status": "NEW",
2096
+ // "stopPrice": "9300",
2097
+ // "closePosition": false,
2098
+ // "symbol": "BTCUSDT",
2099
+ // "time": 1579276756075,
2100
+ // "timeInForce": "GTC",
2101
+ // "type": "TRAILING_STOP_MARKET",
2102
+ // "activatePrice": "9020",
2103
+ // "priceRate": "0.3",
2104
+ // "updateTime": 1579276756075,
2105
+ // "workingType": "CONTRACT_PRICE",
2106
+ // "priceProtect": false
2107
+ // }
2108
+ // ]
2109
+ //
2110
+ return this.parseOrders(response, market, since, limit);
2111
+ }
2112
+ /**
2113
+ * @method
2114
+ * @name aster#createOrder
2115
+ * @description create a trade order
2116
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#place-order-trade
2117
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#new-order--trade
2118
+ * @param {string} symbol unified symbol of the market to create an order in
2119
+ * @param {string} type 'market' or 'limit' or 'STOP' or 'STOP_MARKET' or 'TAKE_PROFIT' or 'TAKE_PROFIT_MARKET' or 'TRAILING_STOP_MARKET'
2120
+ * @param {string} side 'buy' or 'sell'
2121
+ * @param {float} amount how much of you want to trade in units of the base currency
2122
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2123
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2124
+ * @param {string} [params.reduceOnly] for swap and future reduceOnly is a string 'true' or 'false' that cant be sent with close position set to true or in hedge mode. For spot margin and option reduceOnly is a boolean.
2125
+ * @param {boolean} [params.test] whether to use the test endpoint or not, default is false
2126
+ * @param {float} [params.trailingPercent] the percent to trail away from the current market price
2127
+ * @param {float} [params.trailingTriggerPrice] the price to trigger a trailing order, default uses the price argument
2128
+ * @param {string} [params.positionSide] "BOTH" for one-way mode, "LONG" for buy side of hedged mode, "SHORT" for sell side of hedged mode
2129
+ * @param {float} [params.triggerPrice] the price that a trigger order is triggered at
2130
+ * @param {float} [params.stopLossPrice] the price that a stop loss order is triggered at
2131
+ * @param {float} [params.takeProfitPrice] the price that a take profit order is triggered at
2132
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2133
+ */
2134
+ async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
2135
+ await this.loadMarkets();
2136
+ const market = this.market(symbol);
2137
+ const test = this.safeBool(params, 'test', false);
2138
+ params = this.omit(params, 'test');
2139
+ const request = this.createOrderRequest(symbol, type, side, amount, price, params);
2140
+ let response = undefined;
2141
+ if (market['swap']) {
2142
+ if (test) {
2143
+ response = await this.fapiPrivatePostV1OrderTest(request);
2144
+ }
2145
+ else {
2146
+ response = await this.fapiPrivatePostV1Order(request);
2147
+ }
2148
+ }
2149
+ else {
2150
+ response = await this.sapiPrivatePostV1Order(request);
2151
+ }
2152
+ return this.parseOrder(response, market);
2153
+ }
2154
+ /**
2155
+ * @method
2156
+ * @name aster#createOrders
2157
+ * @description create a list of trade orders
2158
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#place-multiple-orders--trade
2159
+ * @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
2160
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2161
+ * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2162
+ */
2163
+ async createOrders(orders, params = {}) {
2164
+ await this.loadMarkets();
2165
+ const ordersRequests = [];
2166
+ let orderSymbols = [];
2167
+ if (orders.length > 5) {
2168
+ throw new errors.InvalidOrder(this.id + ' createOrders() order list max 5 orders');
2169
+ }
2170
+ for (let i = 0; i < orders.length; i++) {
2171
+ const rawOrder = orders[i];
2172
+ const marketId = this.safeString(rawOrder, 'symbol');
2173
+ const type = this.safeString(rawOrder, 'type');
2174
+ const side = this.safeString(rawOrder, 'side');
2175
+ const amount = this.safeValue(rawOrder, 'amount');
2176
+ const price = this.safeValue(rawOrder, 'price');
2177
+ const orderParams = this.safeDict(rawOrder, 'params', {});
2178
+ const orderRequest = this.createOrderRequest(marketId, type, side, amount, price, orderParams);
2179
+ ordersRequests.push(orderRequest);
2180
+ }
2181
+ orderSymbols = this.marketSymbols(orderSymbols, undefined, false, true, true);
2182
+ const market = this.market(orderSymbols[0]);
2183
+ if (market['spot']) {
2184
+ throw new errors.NotSupported(this.id + ' createOrders() does not support ' + market['type'] + ' orders');
2185
+ }
2186
+ const request = {
2187
+ 'batchOrders': ordersRequests,
2188
+ };
2189
+ const response = await this.fapiPrivatePostV1BatchOrders(this.extend(request, params));
2190
+ return this.parseOrders(response);
2191
+ }
2192
+ createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
2193
+ /**
2194
+ * @method
2195
+ * @ignore
2196
+ * @name aster#createOrderRequest
2197
+ * @description helper function to build the request
2198
+ * @param {string} symbol unified symbol of the market to create an order in
2199
+ * @param {string} type 'market' or 'limit'
2200
+ * @param {string} side 'buy' or 'sell'
2201
+ * @param {float} amount how much you want to trade in units of the base currency
2202
+ * @param {float} [price] the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2203
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2204
+ * @returns {object} request to be sent to the exchange
2205
+ */
2206
+ const market = this.market(symbol);
2207
+ const initialUppercaseType = type.toUpperCase();
2208
+ const isMarketOrder = initialUppercaseType === 'MARKET';
2209
+ const isLimitOrder = initialUppercaseType === 'LIMIT';
2210
+ const request = {
2211
+ 'symbol': market['id'],
2212
+ 'side': side.toUpperCase(),
2213
+ };
2214
+ const clientOrderId = this.safeString2(params, 'newClientOrderId', 'clientOrderId');
2215
+ if (clientOrderId !== undefined) {
2216
+ request['newClientOrderId'] = clientOrderId;
2217
+ }
2218
+ const triggerPrice = this.safeString2(params, 'triggerPrice', 'stopPrice');
2219
+ const stopLossPrice = this.safeString(params, 'stopLossPrice', triggerPrice);
2220
+ const takeProfitPrice = this.safeString(params, 'takeProfitPrice');
2221
+ const trailingDelta = this.safeString(params, 'trailingDelta');
2222
+ const trailingTriggerPrice = this.safeString2(params, 'trailingTriggerPrice', 'activationPrice');
2223
+ const trailingPercent = this.safeStringN(params, ['trailingPercent', 'callbackRate', 'trailingDelta']);
2224
+ const isTrailingPercentOrder = trailingPercent !== undefined;
2225
+ const isStopLoss = stopLossPrice !== undefined || trailingDelta !== undefined;
2226
+ const isTakeProfit = takeProfitPrice !== undefined;
2227
+ let uppercaseType = initialUppercaseType;
2228
+ let stopPrice = undefined;
2229
+ if (isTrailingPercentOrder) {
2230
+ if (market['swap']) {
2231
+ uppercaseType = 'TRAILING_STOP_MARKET';
2232
+ request['callbackRate'] = trailingPercent;
2233
+ if (trailingTriggerPrice !== undefined) {
2234
+ request['activationPrice'] = this.priceToPrecision(symbol, trailingTriggerPrice);
2235
+ }
2236
+ }
2237
+ }
2238
+ else if (isStopLoss) {
2239
+ stopPrice = stopLossPrice;
2240
+ if (isMarketOrder) {
2241
+ uppercaseType = 'STOP_MARKET';
2242
+ }
2243
+ else if (isLimitOrder) {
2244
+ uppercaseType = 'STOP';
2245
+ }
2246
+ }
2247
+ else if (isTakeProfit) {
2248
+ stopPrice = takeProfitPrice;
2249
+ if (isMarketOrder) {
2250
+ uppercaseType = 'TAKE_PROFIT_MARKET';
2251
+ }
2252
+ else if (isLimitOrder) {
2253
+ uppercaseType = 'TAKE_PROFIT';
2254
+ }
2255
+ }
2256
+ const postOnly = this.isPostOnly(isMarketOrder, undefined, params);
2257
+ if (postOnly) {
2258
+ request['timeInForce'] = 'GTX';
2259
+ }
2260
+ //
2261
+ // spot
2262
+ // LIMIT timeInForce, quantity, price
2263
+ // MARKET quantity or quoteOrderQty
2264
+ // STOP and TAKE_PROFIT quantity, price, stopPrice
2265
+ // STOP_MARKET and TAKE_PROFIT_MARKET quantity, stopPrice
2266
+ // future
2267
+ // LIMIT timeInForce, quantity, price
2268
+ // MARKET quantity
2269
+ // STOP/TAKE_PROFIT quantity, price, stopPrice
2270
+ // STOP_MARKET/TAKE_PROFIT_MARKET stopPrice
2271
+ // TRAILING_STOP_MARKET callbackRate
2272
+ //
2273
+ // additional required fields depending on the order type
2274
+ const closePosition = this.safeBool(params, 'closePosition', false);
2275
+ let timeInForceIsRequired = false;
2276
+ let priceIsRequired = false;
2277
+ let triggerPriceIsRequired = false;
2278
+ let quantityIsRequired = false;
2279
+ request['type'] = uppercaseType;
2280
+ if (uppercaseType === 'MARKET') {
2281
+ if (market['spot']) {
2282
+ const quoteOrderQty = this.safeBool(this.options, 'quoteOrderQty', true);
2283
+ if (quoteOrderQty) {
2284
+ const quoteOrderQtyNew = this.safeString2(params, 'quoteOrderQty', 'cost');
2285
+ const precision = market['precision']['price'];
2286
+ if (quoteOrderQtyNew !== undefined) {
2287
+ request['quoteOrderQty'] = this.decimalToPrecision(quoteOrderQtyNew, number.TRUNCATE, precision, this.precisionMode);
2288
+ }
2289
+ else if (price !== undefined) {
2290
+ const amountString = this.numberToString(amount);
2291
+ const priceString = this.numberToString(price);
2292
+ const quoteOrderQuantity = Precise["default"].stringMul(amountString, priceString);
2293
+ request['quoteOrderQty'] = this.decimalToPrecision(quoteOrderQuantity, number.TRUNCATE, precision, this.precisionMode);
2294
+ }
2295
+ else {
2296
+ quantityIsRequired = true;
2297
+ }
2298
+ }
2299
+ else {
2300
+ quantityIsRequired = true;
2301
+ }
2302
+ }
2303
+ else {
2304
+ quantityIsRequired = true;
2305
+ }
2306
+ }
2307
+ else if (uppercaseType === 'LIMIT') {
2308
+ timeInForceIsRequired = true;
2309
+ quantityIsRequired = true;
2310
+ priceIsRequired = true;
2311
+ }
2312
+ else if ((uppercaseType === 'STOP') || (uppercaseType === 'TAKE_PROFIT')) {
2313
+ quantityIsRequired = true;
2314
+ priceIsRequired = true;
2315
+ triggerPriceIsRequired = true;
2316
+ }
2317
+ else if ((uppercaseType === 'STOP_MARKET') || (uppercaseType === 'TAKE_PROFIT_MARKET')) {
2318
+ if (!closePosition) {
2319
+ quantityIsRequired = true;
2320
+ }
2321
+ triggerPriceIsRequired = true;
2322
+ }
2323
+ else if (uppercaseType === 'TRAILING_STOP_MARKET') {
2324
+ request['callbackRate'] = trailingPercent;
2325
+ if (trailingTriggerPrice !== undefined) {
2326
+ request['activationPrice'] = this.priceToPrecision(symbol, trailingTriggerPrice);
2327
+ }
2328
+ }
2329
+ if (quantityIsRequired) {
2330
+ const marketAmountPrecision = this.safeString(market['precision'], 'amount');
2331
+ const isPrecisionAvailable = (marketAmountPrecision !== undefined);
2332
+ if (isPrecisionAvailable) {
2333
+ request['quantity'] = this.amountToPrecision(symbol, amount);
2334
+ }
2335
+ else {
2336
+ request['quantity'] = this.parseToNumeric(amount);
2337
+ }
2338
+ }
2339
+ if (priceIsRequired) {
2340
+ if (price === undefined) {
2341
+ throw new errors.InvalidOrder(this.id + ' createOrder() requires a price argument for a ' + type + ' order');
2342
+ }
2343
+ const pricePrecision = this.safeString(market['precision'], 'price');
2344
+ const isPricePrecisionAvailable = (pricePrecision !== undefined);
2345
+ if (isPricePrecisionAvailable) {
2346
+ request['price'] = this.priceToPrecision(symbol, price);
2347
+ }
2348
+ else {
2349
+ request['price'] = this.parseToNumeric(price);
2350
+ }
2351
+ }
2352
+ if (triggerPriceIsRequired) {
2353
+ if (stopPrice === undefined) {
2354
+ throw new errors.InvalidOrder(this.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order');
2355
+ }
2356
+ if (stopPrice !== undefined) {
2357
+ request['stopPrice'] = this.priceToPrecision(symbol, stopPrice);
2358
+ }
2359
+ }
2360
+ if (timeInForceIsRequired && (this.safeString(params, 'timeInForce') === undefined) && (this.safeString(request, 'timeInForce') === undefined)) {
2361
+ request['timeInForce'] = this.safeString(this.options, 'defaultTimeInForce'); // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
2362
+ }
2363
+ const requestParams = this.omit(params, ['newClientOrderId', 'clientOrderId', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'trailingDelta', 'stopPrice', 'stopLossPrice', 'takeProfitPrice']);
2364
+ return this.extend(request, requestParams);
2365
+ }
2366
+ /**
2367
+ * @method
2368
+ * @name aster#cancelAllOrders
2369
+ * @description cancel all open orders in a market
2370
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#cancel-all-open-orders-trade
2371
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#cancel-all-open-orders-trade
2372
+ * @param {string} symbol unified market symbol of the market to cancel orders in
2373
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2374
+ * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2375
+ */
2376
+ async cancelAllOrders(symbol = undefined, params = {}) {
2377
+ if (symbol === undefined) {
2378
+ throw new errors.ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument');
2379
+ }
2380
+ await this.loadMarkets();
2381
+ const market = this.market(symbol);
2382
+ const request = {
2383
+ 'symbol': market['id'],
2384
+ };
2385
+ let response = undefined;
2386
+ if (market['swap']) {
2387
+ response = await this.fapiPrivateDeleteV1AllOpenOrders(this.extend(request, params));
2388
+ }
2389
+ else {
2390
+ response = await this.sapiPrivateDeleteV1AllOpenOrders(this.extend(request, params));
2391
+ }
2392
+ //
2393
+ // {
2394
+ // "code": "200",
2395
+ // "msg": "The operation of cancel all open order is done."
2396
+ // }
2397
+ //
2398
+ return [
2399
+ this.safeOrder({
2400
+ 'info': response,
2401
+ }),
2402
+ ];
2403
+ }
2404
+ /**
2405
+ * @method
2406
+ * @name aster#cancelOrder
2407
+ * @description cancels an open order
2408
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#cancel-order-trade
2409
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#cancel-order-trade
2410
+ * @param {string} id order id
2411
+ * @param {string} symbol unified symbol of the market the order was made in
2412
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2413
+ * @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2414
+ */
2415
+ async cancelOrder(id, symbol = undefined, params = {}) {
2416
+ if (symbol === undefined) {
2417
+ throw new errors.ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
2418
+ }
2419
+ await this.loadMarkets();
2420
+ const market = this.market(symbol);
2421
+ const request = {
2422
+ 'symbol': market['id'],
2423
+ };
2424
+ const clientOrderId = this.safeStringN(params, ['origClientOrderId', 'clientOrderId', 'newClientStrategyId']);
2425
+ if (clientOrderId !== undefined) {
2426
+ request['origClientOrderId'] = clientOrderId;
2427
+ }
2428
+ else {
2429
+ request['orderId'] = id;
2430
+ }
2431
+ params = this.omit(params, ['origClientOrderId', 'clientOrderId', 'newClientStrategyId']);
2432
+ let response = undefined;
2433
+ if (market['swap']) {
2434
+ response = await this.fapiPrivateDeleteV1Order(this.extend(request, params));
2435
+ }
2436
+ else {
2437
+ response = await this.sapiPrivateDeleteV1Order(this.extend(request, params));
2438
+ }
2439
+ return this.parseOrder(response, market);
2440
+ }
2441
+ /**
2442
+ * @method
2443
+ * @name aster#cancelOrders
2444
+ * @description cancel multiple orders
2445
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#cancel-multiple-orders-trade
2446
+ * @param {string[]} ids order ids
2447
+ * @param {string} [symbol] unified market symbol
2448
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2449
+ *
2450
+ * EXCHANGE SPECIFIC PARAMETERS
2451
+ * @param {string[]} [params.origClientOrderIdList] max length 10 e.g. ["my_id_1","my_id_2"], encode the double quotes. No space after comma
2452
+ * @param {int[]} [params.recvWindow]
2453
+ * @returns {object} an list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2454
+ */
2455
+ async cancelOrders(ids, symbol = undefined, params = {}) {
2456
+ if (symbol === undefined) {
2457
+ throw new errors.ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument');
2458
+ }
2459
+ await this.loadMarkets();
2460
+ const market = this.market(symbol);
2461
+ if (market['spot']) {
2462
+ throw new errors.NotSupported(this.id + ' cancelOrders() does not support ' + market['type'] + ' orders');
2463
+ }
2464
+ const request = {
2465
+ 'symbol': market['id'],
2466
+ };
2467
+ const clientOrderIdList = this.safeList(params, 'origClientOrderIdList');
2468
+ if (clientOrderIdList !== undefined) {
2469
+ request['origClientOrderIdList'] = clientOrderIdList;
2470
+ }
2471
+ else {
2472
+ request['orderIdList'] = ids;
2473
+ }
2474
+ const response = await this.fapiPrivateDeleteV1BatchOrders(this.extend(request, params));
2475
+ //
2476
+ // [
2477
+ // {
2478
+ // "clientOrderId": "myOrder1",
2479
+ // "cumQty": "0",
2480
+ // "cumQuote": "0",
2481
+ // "executedQty": "0",
2482
+ // "orderId": 283194212,
2483
+ // "origQty": "11",
2484
+ // "origType": "TRAILING_STOP_MARKET",
2485
+ // "price": "0",
2486
+ // "reduceOnly": false,
2487
+ // "side": "BUY",
2488
+ // "positionSide": "SHORT",
2489
+ // "status": "CANCELED",
2490
+ // "stopPrice": "9300", // please ignore when order type is TRAILING_STOP_MARKET
2491
+ // "closePosition": false, // if Close-All
2492
+ // "symbol": "BTCUSDT",
2493
+ // "timeInForce": "GTC",
2494
+ // "type": "TRAILING_STOP_MARKET",
2495
+ // "activatePrice": "9020", // activation price, only return with TRAILING_STOP_MARKET order
2496
+ // "priceRate": "0.3", // callback rate, only return with TRAILING_STOP_MARKET order
2497
+ // "updateTime": 1571110484038,
2498
+ // "workingType": "CONTRACT_PRICE",
2499
+ // "priceProtect": false, // if conditional order trigger is protected
2500
+ // },
2501
+ // {
2502
+ // "code": -2011,
2503
+ // "msg": "Unknown order sent."
2504
+ // }
2505
+ // ]
2506
+ //
2507
+ return this.parseOrders(response, market);
2508
+ }
2509
+ /**
2510
+ * @method
2511
+ * @name aster#setLeverage
2512
+ * @description set the level of leverage for a market
2513
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#change-initial-leverage-trade
2514
+ * @param {float} leverage the rate of leverage
2515
+ * @param {string} symbol unified market symbol
2516
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2517
+ * @returns {object} response from the exchange
2518
+ */
2519
+ async setLeverage(leverage, symbol = undefined, params = {}) {
2520
+ if (symbol === undefined) {
2521
+ throw new errors.ArgumentsRequired(this.id + ' setLeverage() requires a symbol argument');
2522
+ }
2523
+ if ((leverage < 1) || (leverage > 125)) {
2524
+ throw new errors.BadRequest(this.id + ' leverage should be between 1 and 125');
2525
+ }
2526
+ await this.loadMarkets();
2527
+ const market = this.market(symbol);
2528
+ const request = {
2529
+ 'symbol': market['id'],
2530
+ 'leverage': leverage,
2531
+ };
2532
+ const response = await this.fapiPrivatePostV1Leverage(this.extend(request, params));
2533
+ //
2534
+ // {
2535
+ // "leverage": 21,
2536
+ // "maxNotionalValue": "1000000",
2537
+ // "symbol": "BTCUSDT"
2538
+ // }
2539
+ //
2540
+ return response;
2541
+ }
2542
+ /**
2543
+ * @method
2544
+ * @name aster#fetchLeverages
2545
+ * @description fetch the set leverage for all markets
2546
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
2547
+ * @param {string[]} [symbols] a list of unified market symbols
2548
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2549
+ * @returns {object} a list of [leverage structures]{@link https://docs.ccxt.com/#/?id=leverage-structure}
2550
+ */
2551
+ async fetchLeverages(symbols = undefined, params = {}) {
2552
+ await this.loadMarkets();
2553
+ const response = await this.fapiPrivateGetV2PositionRisk(params);
2554
+ //
2555
+ // [
2556
+ // {
2557
+ // "symbol": "INJUSDT",
2558
+ // "positionAmt": "0.0",
2559
+ // "entryPrice": "0.0",
2560
+ // "markPrice": "0.00000000",
2561
+ // "unRealizedProfit": "0.00000000",
2562
+ // "liquidationPrice": "0",
2563
+ // "leverage": "20",
2564
+ // "maxNotionalValue": "25000",
2565
+ // "marginType": "cross",
2566
+ // "isolatedMargin": "0.00000000",
2567
+ // "isAutoAddMargin": "false",
2568
+ // "positionSide": "BOTH",
2569
+ // "notional": "0",
2570
+ // "isolatedWallet": "0",
2571
+ // "updateTime": 0
2572
+ // }
2573
+ // ]
2574
+ //
2575
+ return this.parseLeverages(response, symbols, 'symbol');
2576
+ }
2577
+ parseLeverage(leverage, market = undefined) {
2578
+ //
2579
+ // {
2580
+ // "symbol": "INJUSDT",
2581
+ // "positionAmt": "0.0",
2582
+ // "entryPrice": "0.0",
2583
+ // "markPrice": "0.00000000",
2584
+ // "unRealizedProfit": "0.00000000",
2585
+ // "liquidationPrice": "0",
2586
+ // "leverage": "20",
2587
+ // "maxNotionalValue": "25000",
2588
+ // "marginType": "cross",
2589
+ // "isolatedMargin": "0.00000000",
2590
+ // "isAutoAddMargin": "false",
2591
+ // "positionSide": "BOTH",
2592
+ // "notional": "0",
2593
+ // "isolatedWallet": "0",
2594
+ // "updateTime": 0
2595
+ // }
2596
+ //
2597
+ const marketId = this.safeString(leverage, 'symbol');
2598
+ const marginMode = this.safeStringLower(leverage, 'marginType');
2599
+ const side = this.safeStringLower(leverage, 'positionSide');
2600
+ let longLeverage = undefined;
2601
+ let shortLeverage = undefined;
2602
+ const leverageValue = this.safeInteger(leverage, 'leverage');
2603
+ if ((side === undefined) || (side === 'both')) {
2604
+ longLeverage = leverageValue;
2605
+ shortLeverage = leverageValue;
2606
+ }
2607
+ else if (side === 'long') {
2608
+ longLeverage = leverageValue;
2609
+ }
2610
+ else if (side === 'short') {
2611
+ shortLeverage = leverageValue;
2612
+ }
2613
+ return {
2614
+ 'info': leverage,
2615
+ 'symbol': this.safeSymbol(marketId, market),
2616
+ 'marginMode': marginMode,
2617
+ 'longLeverage': longLeverage,
2618
+ 'shortLeverage': shortLeverage,
2619
+ };
2620
+ }
2621
+ /**
2622
+ * @method
2623
+ * @name aster#fetchMarginModes
2624
+ * @description fetches margin mode of the user
2625
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
2626
+ * @param {string[]} symbols unified market symbols
2627
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2628
+ * @returns {object} a list of [margin mode structures]{@link https://docs.ccxt.com/#/?id=margin-mode-structure}
2629
+ */
2630
+ async fetchMarginModes(symbols = undefined, params = {}) {
2631
+ await this.loadMarkets();
2632
+ const response = await this.fapiPrivateGetV2PositionRisk(params);
2633
+ //
2634
+ //
2635
+ // [
2636
+ // {
2637
+ // "symbol": "INJUSDT",
2638
+ // "positionAmt": "0.0",
2639
+ // "entryPrice": "0.0",
2640
+ // "markPrice": "0.00000000",
2641
+ // "unRealizedProfit": "0.00000000",
2642
+ // "liquidationPrice": "0",
2643
+ // "leverage": "20",
2644
+ // "maxNotionalValue": "25000",
2645
+ // "marginType": "cross",
2646
+ // "isolatedMargin": "0.00000000",
2647
+ // "isAutoAddMargin": "false",
2648
+ // "positionSide": "BOTH",
2649
+ // "notional": "0",
2650
+ // "isolatedWallet": "0",
2651
+ // "updateTime": 0
2652
+ // }
2653
+ // ]
2654
+ //
2655
+ //
2656
+ return this.parseMarginModes(response, symbols, 'symbol', 'swap');
2657
+ }
2658
+ parseMarginMode(marginMode, market = undefined) {
2659
+ //
2660
+ // {
2661
+ // "symbol": "INJUSDT",
2662
+ // "positionAmt": "0.0",
2663
+ // "entryPrice": "0.0",
2664
+ // "markPrice": "0.00000000",
2665
+ // "unRealizedProfit": "0.00000000",
2666
+ // "liquidationPrice": "0",
2667
+ // "leverage": "20",
2668
+ // "maxNotionalValue": "25000",
2669
+ // "marginType": "cross",
2670
+ // "isolatedMargin": "0.00000000",
2671
+ // "isAutoAddMargin": "false",
2672
+ // "positionSide": "BOTH",
2673
+ // "notional": "0",
2674
+ // "isolatedWallet": "0",
2675
+ // "updateTime": 0
2676
+ // }
2677
+ //
2678
+ const marketId = this.safeString(marginMode, 'symbol');
2679
+ market = this.safeMarket(marketId, market);
2680
+ return {
2681
+ 'info': marginMode,
2682
+ 'symbol': market['symbol'],
2683
+ 'marginMode': this.safeStringLower(marginMode, 'marginType'),
2684
+ };
2685
+ }
2686
+ /**
2687
+ * @method
2688
+ * @name aster#fetchMarginAdjustmentHistory
2689
+ * @description fetches the history of margin added or reduced from contract isolated positions
2690
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-position-margin-change-history-trade
2691
+ * @param {string} symbol unified market symbol
2692
+ * @param {string} [type] "add" or "reduce"
2693
+ * @param {int} [since] timestamp in ms of the earliest change to fetch
2694
+ * @param {int} [limit] the maximum amount of changes to fetch
2695
+ * @param {object} params extra parameters specific to the exchange api endpoint
2696
+ * @param {int} [params.until] timestamp in ms of the latest change to fetch
2697
+ * @returns {object[]} a list of [margin structures]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
2698
+ */
2699
+ async fetchMarginAdjustmentHistory(symbol = undefined, type = undefined, since = undefined, limit = undefined, params = {}) {
2700
+ await this.loadMarkets();
2701
+ if (symbol === undefined) {
2702
+ throw new errors.ArgumentsRequired(this.id + ' fetchMarginAdjustmentHistory () requires a symbol argument');
2703
+ }
2704
+ const market = this.market(symbol);
2705
+ const until = this.safeInteger(params, 'until');
2706
+ params = this.omit(params, 'until');
2707
+ const request = {
2708
+ 'symbol': market['id'],
2709
+ };
2710
+ if (type !== undefined) {
2711
+ request['type'] = (type === 'add') ? 1 : 2;
2712
+ }
2713
+ if (since !== undefined) {
2714
+ request['startTime'] = since;
2715
+ }
2716
+ if (limit !== undefined) {
2717
+ request['limit'] = limit;
2718
+ }
2719
+ if (until !== undefined) {
2720
+ request['endTime'] = until;
2721
+ }
2722
+ const response = await this.fapiPrivateGetV1PositionMarginHistory(this.extend(request, params));
2723
+ //
2724
+ // [
2725
+ // {
2726
+ // "amount": "23.36332311",
2727
+ // "asset": "USDT",
2728
+ // "symbol": "BTCUSDT",
2729
+ // "time": 1578047897183,
2730
+ // "type": 1,
2731
+ // "positionSide": "BOTH"
2732
+ // }
2733
+ // ]
2734
+ //
2735
+ const modifications = this.parseMarginModifications(response);
2736
+ return this.filterBySymbolSinceLimit(modifications, symbol, since, limit);
2737
+ }
2738
+ parseMarginModification(data, market = undefined) {
2739
+ //
2740
+ // {
2741
+ // "amount": "100",
2742
+ // "asset": "USDT",
2743
+ // "symbol": "BTCUSDT",
2744
+ // "time": 1578047900425,
2745
+ // "type": 1,
2746
+ // "positionSide": "LONG"
2747
+ // }
2748
+ //
2749
+ // {
2750
+ // "amount": 100.0,
2751
+ // "code": 200,
2752
+ // "msg": "Successfully modify position margin.",
2753
+ // "type": 1
2754
+ // }
2755
+ //
2756
+ const rawType = this.safeInteger(data, 'type');
2757
+ const errorCode = this.safeString(data, 'code');
2758
+ const marketId = this.safeString(data, 'symbol');
2759
+ const timestamp = this.safeInteger(data, 'time');
2760
+ market = this.safeMarket(marketId, market, undefined, 'swap');
2761
+ const noErrorCode = errorCode === undefined;
2762
+ const success = errorCode === '200';
2763
+ return {
2764
+ 'info': data,
2765
+ 'symbol': market['symbol'],
2766
+ 'type': (rawType === 1) ? 'add' : 'reduce',
2767
+ 'marginMode': 'isolated',
2768
+ 'amount': this.safeNumber(data, 'amount'),
2769
+ 'code': this.safeString(data, 'asset'),
2770
+ 'total': undefined,
2771
+ 'status': (success || noErrorCode) ? 'ok' : 'failed',
2772
+ 'timestamp': timestamp,
2773
+ 'datetime': this.iso8601(timestamp),
2774
+ };
2775
+ }
2776
+ async modifyMarginHelper(symbol, amount, addOrReduce, params = {}) {
2777
+ await this.loadMarkets();
2778
+ const market = this.market(symbol);
2779
+ amount = this.amountToPrecision(symbol, amount);
2780
+ const request = {
2781
+ 'type': addOrReduce,
2782
+ 'symbol': market['id'],
2783
+ 'amount': amount,
2784
+ };
2785
+ const code = market['quote'];
2786
+ const response = await this.fapiPrivatePostV1PositionMargin(this.extend(request, params));
2787
+ //
2788
+ // {
2789
+ // "amount": 100.0,
2790
+ // "code": 200,
2791
+ // "msg": "Successfully modify position margin.",
2792
+ // "type": 1
2793
+ // }
2794
+ //
2795
+ return this.extend(this.parseMarginModification(response, market), {
2796
+ 'code': code,
2797
+ });
2798
+ }
2799
+ /**
2800
+ * @method
2801
+ * @name aster#reduceMargin
2802
+ * @description remove margin from a position
2803
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#modify-isolated-position-margin-trade
2804
+ * @param {string} symbol unified market symbol
2805
+ * @param {float} amount the amount of margin to remove
2806
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2807
+ * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=reduce-margin-structure}
2808
+ */
2809
+ async reduceMargin(symbol, amount, params = {}) {
2810
+ return await this.modifyMarginHelper(symbol, amount, 2, params);
2811
+ }
2812
+ /**
2813
+ * @method
2814
+ * @name aster#addMargin
2815
+ * @description add margin
2816
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#modify-isolated-position-margin-trade
2817
+ * @param {string} symbol unified market symbol
2818
+ * @param {float} amount amount of margin to add
2819
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2820
+ * @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
2821
+ */
2822
+ async addMargin(symbol, amount, params = {}) {
2823
+ return await this.modifyMarginHelper(symbol, amount, 1, params);
2824
+ }
2825
+ parseIncome(income, market = undefined) {
2826
+ //
2827
+ // {
2828
+ // "symbol": "ETHUSDT",
2829
+ // "incomeType": "FUNDING_FEE",
2830
+ // "income": "0.00134317",
2831
+ // "asset": "USDT",
2832
+ // "time": "1621584000000",
2833
+ // "info": "FUNDING_FEE",
2834
+ // "tranId": "4480321991774044580",
2835
+ // "tradeId": ""
2836
+ // }
2837
+ //
2838
+ const marketId = this.safeString(income, 'symbol');
2839
+ const currencyId = this.safeString(income, 'asset');
2840
+ const timestamp = this.safeInteger(income, 'time');
2841
+ return {
2842
+ 'info': income,
2843
+ 'symbol': this.safeSymbol(marketId, market, undefined, 'swap'),
2844
+ 'code': this.safeCurrencyCode(currencyId),
2845
+ 'timestamp': timestamp,
2846
+ 'datetime': this.iso8601(timestamp),
2847
+ 'id': this.safeString(income, 'tranId'),
2848
+ 'amount': this.safeNumber(income, 'income'),
2849
+ };
2850
+ }
2851
+ /**
2852
+ * @method
2853
+ * @name aster#fetchFundingHistory
2854
+ * @description fetch the history of funding payments paid and received on this account
2855
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-income-historyuser_data
2856
+ * @param {string} symbol unified market symbol
2857
+ * @param {int} [since] the earliest time in ms to fetch funding history for
2858
+ * @param {int} [limit] the maximum number of funding history structures to retrieve
2859
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2860
+ * @param {int} [params.until] timestamp in ms of the latest funding history entry
2861
+ * @param {boolean} [params.portfolioMargin] set to true if you would like to fetch the funding history for a portfolio margin account
2862
+ * @param {string} [params.subType] "linear" or "inverse"
2863
+ * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/#/?id=funding-history-structure}
2864
+ */
2865
+ async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2866
+ await this.loadMarkets();
2867
+ let market = undefined;
2868
+ let request = {
2869
+ 'incomeType': 'FUNDING_FEE', // "TRANSFER","WELCOME_BONUS", "REALIZED_PNL","FUNDING_FEE", "COMMISSION", "INSURANCE_CLEAR", and "MARKET_MERCHANT_RETURN_REWARD"
2870
+ };
2871
+ if (symbol !== undefined) {
2872
+ market = this.market(symbol);
2873
+ request['symbol'] = market['id'];
2874
+ }
2875
+ [request, params] = this.handleUntilOption('endTime', request, params);
2876
+ if (since !== undefined) {
2877
+ request['startTime'] = since;
2878
+ }
2879
+ if (limit !== undefined) {
2880
+ request['limit'] = Math.min(limit, 1000); // max 1000
2881
+ }
2882
+ const response = await this.fapiPrivateGetV1Income(this.extend(request, params));
2883
+ return this.parseIncomes(response, market, since, limit);
2884
+ }
2885
+ parseLedgerEntry(item, currency = undefined) {
2886
+ //
2887
+ // {
2888
+ // "symbol": "",
2889
+ // "incomeType": "TRANSFER",
2890
+ // "income": "10.00000000",
2891
+ // "asset": "USDT",
2892
+ // "time": 1677645250000,
2893
+ // "info": "TRANSFER",
2894
+ // "tranId": 131001573082,
2895
+ // "tradeId": ""
2896
+ // }
2897
+ //
2898
+ let amount = this.safeString(item, 'income');
2899
+ let direction = undefined;
2900
+ if (Precise["default"].stringLe(amount, '0')) {
2901
+ direction = 'out';
2902
+ amount = Precise["default"].stringMul('-1', amount);
2903
+ }
2904
+ else {
2905
+ direction = 'in';
2906
+ }
2907
+ const currencyId = this.safeString(item, 'asset');
2908
+ const code = this.safeCurrencyCode(currencyId, currency);
2909
+ currency = this.safeCurrency(currencyId, currency);
2910
+ const timestamp = this.safeInteger(item, 'time');
2911
+ const type = this.safeString(item, 'incomeType');
2912
+ return this.safeLedgerEntry({
2913
+ 'info': item,
2914
+ 'id': this.safeString(item, 'tranId'),
2915
+ 'direction': direction,
2916
+ 'account': undefined,
2917
+ 'referenceAccount': undefined,
2918
+ 'referenceId': this.safeString(item, 'tradeId'),
2919
+ 'type': this.parseLedgerEntryType(type),
2920
+ 'currency': code,
2921
+ 'amount': this.parseNumber(amount),
2922
+ 'timestamp': timestamp,
2923
+ 'datetime': this.iso8601(timestamp),
2924
+ 'before': undefined,
2925
+ 'after': undefined,
2926
+ 'status': undefined,
2927
+ 'fee': undefined,
2928
+ }, currency);
2929
+ }
2930
+ parseLedgerEntryType(type) {
2931
+ const ledgerType = {
2932
+ 'TRANSFER': 'transfer',
2933
+ 'WELCOME_BONUS': 'cashback',
2934
+ 'REALIZED_PNL': 'trade',
2935
+ 'FUNDING_FEE': 'fee',
2936
+ 'COMMISSION': 'commission',
2937
+ 'INSURANCE_CLEAR': 'settlement',
2938
+ 'MARKET_MERCHANT_RETURN_REWARD': 'cashback',
2939
+ };
2940
+ return this.safeString(ledgerType, type, type);
2941
+ }
2942
+ /**
2943
+ * @method
2944
+ * @name aster#fetchLedger
2945
+ * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
2946
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-income-historyuser_data
2947
+ * @param {string} [code] unified currency code
2948
+ * @param {int} [since] timestamp in ms of the earliest ledger entry
2949
+ * @param {int} [limit] max number of ledger entries to return
2950
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
2951
+ * @param {int} [params.until] timestamp in ms of the latest ledger entry
2952
+ * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger}
2953
+ */
2954
+ async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
2955
+ await this.loadMarkets();
2956
+ let currency = undefined;
2957
+ if (code !== undefined) {
2958
+ currency = this.currency(code);
2959
+ }
2960
+ const request = {};
2961
+ if (since !== undefined) {
2962
+ request['startTime'] = since;
2963
+ }
2964
+ if (limit !== undefined) {
2965
+ request['limit'] = Math.min(limit, 1000); // max 1000
2966
+ }
2967
+ const until = this.safeInteger(params, 'until');
2968
+ if (until !== undefined) {
2969
+ params = this.omit(params, 'until');
2970
+ request['endTime'] = until;
2971
+ }
2972
+ const response = await this.fapiPrivateGetV1Income(this.extend(request, params));
2973
+ //
2974
+ // [
2975
+ // {
2976
+ // "symbol": "",
2977
+ // "incomeType": "TRANSFER",
2978
+ // "income": "10.00000000",
2979
+ // "asset": "USDT",
2980
+ // "time": 1677645250000,
2981
+ // "info": "TRANSFER",
2982
+ // "tranId": 131001573082,
2983
+ // "tradeId": ""
2984
+ // }
2985
+ // ]
2986
+ //
2987
+ return this.parseLedger(response, currency, since, limit);
2988
+ }
2989
+ parsePositionRisk(position, market = undefined) {
2990
+ //
2991
+ // {
2992
+ // "entryPrice": "6563.66500",
2993
+ // "marginType": "isolated",
2994
+ // "isAutoAddMargin": "false",
2995
+ // "isolatedMargin": "15517.54150468",
2996
+ // "leverage": "10",
2997
+ // "liquidationPrice": "5930.78",
2998
+ // "markPrice": "6679.50671178",
2999
+ // "maxNotionalValue": "20000000",
3000
+ // "positionSide": "LONG",
3001
+ // "positionAmt": "20.000",
3002
+ // "symbol": "BTCUSDT",
3003
+ // "unRealizedProfit": "2316.83423560",
3004
+ // "updateTime": 1625474304765
3005
+ // }
3006
+ //
3007
+ const marketId = this.safeString(position, 'symbol');
3008
+ market = this.safeMarket(marketId, market, undefined, 'contract');
3009
+ const symbol = this.safeString(market, 'symbol');
3010
+ const isolatedMarginString = this.safeString(position, 'isolatedMargin');
3011
+ const leverageBrackets = this.safeDict(this.options, 'leverageBrackets', {});
3012
+ const leverageBracket = this.safeList(leverageBrackets, symbol, []);
3013
+ const notionalString = this.safeString2(position, 'notional', 'notionalValue');
3014
+ const notionalStringAbs = Precise["default"].stringAbs(notionalString);
3015
+ let maintenanceMarginPercentageString = undefined;
3016
+ for (let i = 0; i < leverageBracket.length; i++) {
3017
+ const bracket = leverageBracket[i];
3018
+ if (Precise["default"].stringLt(notionalStringAbs, bracket[0])) {
3019
+ break;
3020
+ }
3021
+ maintenanceMarginPercentageString = bracket[1];
3022
+ }
3023
+ const notional = this.parseNumber(notionalStringAbs);
3024
+ const contractsAbs = Precise["default"].stringAbs(this.safeString(position, 'positionAmt'));
3025
+ const contracts = this.parseNumber(contractsAbs);
3026
+ const unrealizedPnlString = this.safeString(position, 'unRealizedProfit');
3027
+ const unrealizedPnl = this.parseNumber(unrealizedPnlString);
3028
+ const liquidationPriceString = this.omitZero(this.safeString(position, 'liquidationPrice'));
3029
+ const liquidationPrice = this.parseNumber(liquidationPriceString);
3030
+ let collateralString = undefined;
3031
+ let marginMode = this.safeString(position, 'marginType');
3032
+ if (marginMode === undefined && isolatedMarginString !== undefined) {
3033
+ marginMode = Precise["default"].stringEq(isolatedMarginString, '0') ? 'cross' : 'isolated';
3034
+ }
3035
+ let side = undefined;
3036
+ if (Precise["default"].stringGt(notionalString, '0')) {
3037
+ side = 'long';
3038
+ }
3039
+ else if (Precise["default"].stringLt(notionalString, '0')) {
3040
+ side = 'short';
3041
+ }
3042
+ const entryPriceString = this.safeString(position, 'entryPrice');
3043
+ const entryPrice = this.parseNumber(entryPriceString);
3044
+ const contractSize = this.safeValue(market, 'contractSize');
3045
+ const contractSizeString = this.numberToString(contractSize);
3046
+ // as oppose to notionalValue
3047
+ const linear = ('notional' in position);
3048
+ if (marginMode === 'cross') {
3049
+ // calculate collateral
3050
+ const precision = this.safeDict(market, 'precision', {});
3051
+ const basePrecisionValue = this.safeString(precision, 'base');
3052
+ const quotePrecisionValue = this.safeString2(precision, 'quote', 'price');
3053
+ const precisionIsUndefined = (basePrecisionValue === undefined) && (quotePrecisionValue === undefined);
3054
+ if (!precisionIsUndefined) {
3055
+ if (linear) {
3056
+ // walletBalance = (liquidationPrice * (±1 + mmp) ± entryPrice) * contracts
3057
+ let onePlusMaintenanceMarginPercentageString = undefined;
3058
+ let entryPriceSignString = entryPriceString;
3059
+ if (side === 'short') {
3060
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringAdd('1', maintenanceMarginPercentageString);
3061
+ entryPriceSignString = Precise["default"].stringMul('-1', entryPriceSignString);
3062
+ }
3063
+ else {
3064
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringAdd('-1', maintenanceMarginPercentageString);
3065
+ }
3066
+ const inner = Precise["default"].stringMul(liquidationPriceString, onePlusMaintenanceMarginPercentageString);
3067
+ const leftSide = Precise["default"].stringAdd(inner, entryPriceSignString);
3068
+ const quotePrecision = this.precisionFromString(this.safeString2(precision, 'quote', 'price'));
3069
+ if (quotePrecision !== undefined) {
3070
+ collateralString = Precise["default"].stringDiv(Precise["default"].stringMul(leftSide, contractsAbs), '1', quotePrecision);
3071
+ }
3072
+ }
3073
+ else {
3074
+ // walletBalance = (contracts * contractSize) * (±1/entryPrice - (±1 - mmp) / liquidationPrice)
3075
+ let onePlusMaintenanceMarginPercentageString = undefined;
3076
+ let entryPriceSignString = entryPriceString;
3077
+ if (side === 'short') {
3078
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringSub('1', maintenanceMarginPercentageString);
3079
+ }
3080
+ else {
3081
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringSub('-1', maintenanceMarginPercentageString);
3082
+ entryPriceSignString = Precise["default"].stringMul('-1', entryPriceSignString);
3083
+ }
3084
+ const leftSide = Precise["default"].stringMul(contractsAbs, contractSizeString);
3085
+ const rightSide = Precise["default"].stringSub(Precise["default"].stringDiv('1', entryPriceSignString), Precise["default"].stringDiv(onePlusMaintenanceMarginPercentageString, liquidationPriceString));
3086
+ const basePrecision = this.precisionFromString(this.safeString(precision, 'base'));
3087
+ if (basePrecision !== undefined) {
3088
+ collateralString = Precise["default"].stringDiv(Precise["default"].stringMul(leftSide, rightSide), '1', basePrecision);
3089
+ }
3090
+ }
3091
+ }
3092
+ }
3093
+ else {
3094
+ collateralString = this.safeString(position, 'isolatedMargin');
3095
+ }
3096
+ collateralString = (collateralString === undefined) ? '0' : collateralString;
3097
+ const collateral = this.parseNumber(collateralString);
3098
+ const markPrice = this.parseNumber(this.omitZero(this.safeString(position, 'markPrice')));
3099
+ let timestamp = this.safeInteger(position, 'updateTime');
3100
+ if (timestamp === 0) {
3101
+ timestamp = undefined;
3102
+ }
3103
+ const maintenanceMarginPercentage = this.parseNumber(maintenanceMarginPercentageString);
3104
+ let maintenanceMarginString = Precise["default"].stringMul(maintenanceMarginPercentageString, notionalStringAbs);
3105
+ if (maintenanceMarginString === undefined) {
3106
+ // for a while, this new value was a backup to the existing calculations, but in future we might prioritize this
3107
+ maintenanceMarginString = this.safeString(position, 'maintMargin');
3108
+ }
3109
+ const maintenanceMargin = this.parseNumber(maintenanceMarginString);
3110
+ let initialMarginString = undefined;
3111
+ let initialMarginPercentageString = undefined;
3112
+ const leverageString = this.safeString(position, 'leverage');
3113
+ if (leverageString !== undefined) {
3114
+ const leverage = parseInt(leverageString);
3115
+ const rational = this.isRoundNumber(1000 % leverage);
3116
+ initialMarginPercentageString = Precise["default"].stringDiv('1', leverageString, 8);
3117
+ if (!rational) {
3118
+ initialMarginPercentageString = Precise["default"].stringAdd(initialMarginPercentageString, '1e-8');
3119
+ }
3120
+ const unrounded = Precise["default"].stringMul(notionalStringAbs, initialMarginPercentageString);
3121
+ initialMarginString = Precise["default"].stringDiv(unrounded, '1', 8);
3122
+ }
3123
+ else {
3124
+ initialMarginString = this.safeString(position, 'initialMargin');
3125
+ const unrounded = Precise["default"].stringMul(initialMarginString, '1');
3126
+ initialMarginPercentageString = Precise["default"].stringDiv(unrounded, notionalStringAbs, 8);
3127
+ }
3128
+ let marginRatio = undefined;
3129
+ let percentage = undefined;
3130
+ if (!Precise["default"].stringEquals(collateralString, '0')) {
3131
+ marginRatio = this.parseNumber(Precise["default"].stringDiv(Precise["default"].stringAdd(Precise["default"].stringDiv(maintenanceMarginString, collateralString), '5e-5'), '1', 4));
3132
+ percentage = this.parseNumber(Precise["default"].stringMul(Precise["default"].stringDiv(unrealizedPnlString, initialMarginString, 4), '100'));
3133
+ }
3134
+ const positionSide = this.safeString(position, 'positionSide');
3135
+ const hedged = positionSide !== 'BOTH';
3136
+ return this.safePosition({
3137
+ 'info': position,
3138
+ 'id': undefined,
3139
+ 'symbol': symbol,
3140
+ 'contracts': contracts,
3141
+ 'contractSize': contractSize,
3142
+ 'unrealizedPnl': unrealizedPnl,
3143
+ 'leverage': this.parseNumber(leverageString),
3144
+ 'liquidationPrice': liquidationPrice,
3145
+ 'collateral': collateral,
3146
+ 'notional': notional,
3147
+ 'markPrice': markPrice,
3148
+ 'entryPrice': entryPrice,
3149
+ 'timestamp': timestamp,
3150
+ 'initialMargin': this.parseNumber(initialMarginString),
3151
+ 'initialMarginPercentage': this.parseNumber(initialMarginPercentageString),
3152
+ 'maintenanceMargin': maintenanceMargin,
3153
+ 'maintenanceMarginPercentage': maintenanceMarginPercentage,
3154
+ 'marginRatio': marginRatio,
3155
+ 'datetime': this.iso8601(timestamp),
3156
+ 'marginMode': marginMode,
3157
+ 'side': side,
3158
+ 'hedged': hedged,
3159
+ 'percentage': percentage,
3160
+ 'stopLossPrice': undefined,
3161
+ 'takeProfitPrice': undefined,
3162
+ });
3163
+ }
3164
+ /**
3165
+ * @method
3166
+ * @name aster#fetchPositionsRisk
3167
+ * @description fetch positions risk
3168
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
3169
+ * @param {string[]|undefined} symbols list of unified market symbols
3170
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3171
+ * @returns {object} data on the positions risk
3172
+ */
3173
+ async fetchPositionsRisk(symbols = undefined, params = {}) {
3174
+ if (symbols !== undefined) {
3175
+ if (!Array.isArray(symbols)) {
3176
+ throw new errors.ArgumentsRequired(this.id + ' fetchPositionsRisk() requires an array argument for symbols');
3177
+ }
3178
+ }
3179
+ await this.loadMarkets();
3180
+ await this.loadLeverageBrackets(false, params);
3181
+ const request = {};
3182
+ const response = await this.fapiPrivateGetV2PositionRisk(this.extend(request, params));
3183
+ //
3184
+ // [
3185
+ // {
3186
+ // "entryPrice": "6563.66500",
3187
+ // "marginType": "isolated",
3188
+ // "isAutoAddMargin": "false",
3189
+ // "isolatedMargin": "15517.54150468",
3190
+ // "leverage": "10",
3191
+ // "liquidationPrice": "5930.78",
3192
+ // "markPrice": "6679.50671178",
3193
+ // "maxNotionalValue": "20000000",
3194
+ // "positionSide": "LONG",
3195
+ // "positionAmt": "20.000", // negative value for 'SHORT'
3196
+ // "symbol": "BTCUSDT",
3197
+ // "unRealizedProfit": "2316.83423560",
3198
+ // "updateTime": 1625474304765
3199
+ // }
3200
+ // ]
3201
+ //
3202
+ const result = [];
3203
+ for (let i = 0; i < response.length; i++) {
3204
+ const rawPosition = response[i];
3205
+ const entryPriceString = this.safeString(rawPosition, 'entryPrice');
3206
+ if (Precise["default"].stringGt(entryPriceString, '0')) {
3207
+ result.push(this.parsePositionRisk(response[i]));
3208
+ }
3209
+ }
3210
+ symbols = this.marketSymbols(symbols);
3211
+ return this.filterByArrayPositions(result, 'symbol', symbols, false);
3212
+ }
3213
+ /**
3214
+ * @method
3215
+ * @name aster#fetchPositions
3216
+ * @description fetch all open positions
3217
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
3218
+ * @param {string[]} [symbols] list of unified market symbols
3219
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3220
+ * @param {string} [params.method] method name to call, "positionRisk", "account" or "option", default is "positionRisk"
3221
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
3222
+ */
3223
+ async fetchPositions(symbols = undefined, params = {}) {
3224
+ let defaultMethod = undefined;
3225
+ [defaultMethod, params] = this.handleOptionAndParams(params, 'fetchPositions', 'method');
3226
+ if (defaultMethod === undefined) {
3227
+ const options = this.safeDict(this.options, 'fetchPositions');
3228
+ if (options === undefined) {
3229
+ defaultMethod = this.safeString(this.options, 'fetchPositions', 'positionRisk');
3230
+ }
3231
+ else {
3232
+ defaultMethod = 'positionRisk';
3233
+ }
3234
+ }
3235
+ if (defaultMethod === 'positionRisk') {
3236
+ return await this.fetchPositionsRisk(symbols, params);
3237
+ }
3238
+ else if (defaultMethod === 'account') {
3239
+ return await this.fetchAccountPositions(symbols, params);
3240
+ }
3241
+ else {
3242
+ throw new errors.NotSupported(this.id + '.options["fetchPositions"]["method"] or params["method"] = "' + defaultMethod + '" is invalid, please choose between "account" and "positionRisk"');
3243
+ }
3244
+ }
3245
+ parseAccountPositions(account, filterClosed = false) {
3246
+ const positions = this.safeList(account, 'positions');
3247
+ const assets = this.safeList(account, 'assets', []);
3248
+ const balances = {};
3249
+ for (let i = 0; i < assets.length; i++) {
3250
+ const entry = assets[i];
3251
+ const currencyId = this.safeString(entry, 'asset');
3252
+ const code = this.safeCurrencyCode(currencyId);
3253
+ const crossWalletBalance = this.safeString(entry, 'crossWalletBalance');
3254
+ const crossUnPnl = this.safeString(entry, 'crossUnPnl');
3255
+ balances[code] = {
3256
+ 'crossMargin': Precise["default"].stringAdd(crossWalletBalance, crossUnPnl),
3257
+ 'crossWalletBalance': crossWalletBalance,
3258
+ };
3259
+ }
3260
+ const result = [];
3261
+ for (let i = 0; i < positions.length; i++) {
3262
+ const position = positions[i];
3263
+ const marketId = this.safeString(position, 'symbol');
3264
+ const market = this.safeMarket(marketId, undefined, undefined, 'contract');
3265
+ const code = market['linear'] ? market['quote'] : market['base'];
3266
+ const maintenanceMargin = this.safeString(position, 'maintMargin');
3267
+ // check for maintenance margin so empty positions are not returned
3268
+ const isPositionOpen = (maintenanceMargin !== '0') && (maintenanceMargin !== '0.00000000');
3269
+ if (!filterClosed || isPositionOpen) {
3270
+ // sometimes not all the codes are correctly returned...
3271
+ if (code in balances) {
3272
+ const parsed = this.parseAccountPosition(this.extend(position, {
3273
+ 'crossMargin': balances[code]['crossMargin'],
3274
+ 'crossWalletBalance': balances[code]['crossWalletBalance'],
3275
+ }), market);
3276
+ result.push(parsed);
3277
+ }
3278
+ }
3279
+ }
3280
+ return result;
3281
+ }
3282
+ parseAccountPosition(position, market = undefined) {
3283
+ const marketId = this.safeString(position, 'symbol');
3284
+ market = this.safeMarket(marketId, market, undefined, 'contract');
3285
+ const symbol = this.safeString(market, 'symbol');
3286
+ const leverageString = this.safeString(position, 'leverage');
3287
+ const leverage = (leverageString !== undefined) ? parseInt(leverageString) : undefined;
3288
+ const initialMarginString = this.safeString(position, 'initialMargin');
3289
+ const initialMargin = this.parseNumber(initialMarginString);
3290
+ let initialMarginPercentageString = undefined;
3291
+ if (leverageString !== undefined) {
3292
+ initialMarginPercentageString = Precise["default"].stringDiv('1', leverageString, 8);
3293
+ const rational = this.isRoundNumber(1000 % leverage);
3294
+ if (!rational) {
3295
+ initialMarginPercentageString = Precise["default"].stringDiv(Precise["default"].stringAdd(initialMarginPercentageString, '1e-8'), '1', 8);
3296
+ }
3297
+ }
3298
+ // as oppose to notionalValue
3299
+ const usdm = ('notional' in position);
3300
+ const maintenanceMarginString = this.safeString(position, 'maintMargin');
3301
+ const maintenanceMargin = this.parseNumber(maintenanceMarginString);
3302
+ const entryPriceString = this.safeString(position, 'entryPrice');
3303
+ let entryPrice = this.parseNumber(entryPriceString);
3304
+ const notionalString = this.safeString2(position, 'notional', 'notionalValue');
3305
+ const notionalStringAbs = Precise["default"].stringAbs(notionalString);
3306
+ const notional = this.parseNumber(notionalStringAbs);
3307
+ let contractsString = this.safeString(position, 'positionAmt');
3308
+ let contractsStringAbs = Precise["default"].stringAbs(contractsString);
3309
+ if (contractsString === undefined) {
3310
+ const entryNotional = Precise["default"].stringMul(Precise["default"].stringMul(leverageString, initialMarginString), entryPriceString);
3311
+ const contractSizeNew = this.safeString(market, 'contractSize');
3312
+ contractsString = Precise["default"].stringDiv(entryNotional, contractSizeNew);
3313
+ contractsStringAbs = Precise["default"].stringDiv(Precise["default"].stringAdd(contractsString, '0.5'), '1', 0);
3314
+ }
3315
+ const contracts = this.parseNumber(contractsStringAbs);
3316
+ const leverageBrackets = this.safeDict(this.options, 'leverageBrackets', {});
3317
+ const leverageBracket = this.safeList(leverageBrackets, symbol, []);
3318
+ let maintenanceMarginPercentageString = undefined;
3319
+ for (let i = 0; i < leverageBracket.length; i++) {
3320
+ const bracket = leverageBracket[i];
3321
+ if (Precise["default"].stringLt(notionalStringAbs, bracket[0])) {
3322
+ break;
3323
+ }
3324
+ maintenanceMarginPercentageString = bracket[1];
3325
+ }
3326
+ const maintenanceMarginPercentage = this.parseNumber(maintenanceMarginPercentageString);
3327
+ const unrealizedPnlString = this.safeString(position, 'unrealizedProfit');
3328
+ const unrealizedPnl = this.parseNumber(unrealizedPnlString);
3329
+ let timestamp = this.safeInteger(position, 'updateTime');
3330
+ if (timestamp === 0) {
3331
+ timestamp = undefined;
3332
+ }
3333
+ let isolated = this.safeBool(position, 'isolated');
3334
+ if (isolated === undefined) {
3335
+ const isolatedMarginRaw = this.safeString(position, 'isolatedMargin');
3336
+ isolated = !Precise["default"].stringEq(isolatedMarginRaw, '0');
3337
+ }
3338
+ let marginMode = undefined;
3339
+ let collateralString = undefined;
3340
+ let walletBalance = undefined;
3341
+ if (isolated) {
3342
+ marginMode = 'isolated';
3343
+ walletBalance = this.safeString(position, 'isolatedWallet');
3344
+ collateralString = Precise["default"].stringAdd(walletBalance, unrealizedPnlString);
3345
+ }
3346
+ else {
3347
+ marginMode = 'cross';
3348
+ walletBalance = this.safeString(position, 'crossWalletBalance');
3349
+ collateralString = this.safeString(position, 'crossMargin');
3350
+ }
3351
+ const collateral = this.parseNumber(collateralString);
3352
+ let marginRatio = undefined;
3353
+ let side = undefined;
3354
+ let percentage = undefined;
3355
+ let liquidationPriceStringRaw = undefined;
3356
+ let liquidationPrice = undefined;
3357
+ const contractSize = this.safeValue(market, 'contractSize');
3358
+ const contractSizeString = this.numberToString(contractSize);
3359
+ if (Precise["default"].stringEquals(notionalString, '0')) {
3360
+ entryPrice = undefined;
3361
+ }
3362
+ else {
3363
+ side = Precise["default"].stringLt(notionalString, '0') ? 'short' : 'long';
3364
+ marginRatio = this.parseNumber(Precise["default"].stringDiv(Precise["default"].stringAdd(Precise["default"].stringDiv(maintenanceMarginString, collateralString), '5e-5'), '1', 4));
3365
+ percentage = this.parseNumber(Precise["default"].stringMul(Precise["default"].stringDiv(unrealizedPnlString, initialMarginString, 4), '100'));
3366
+ if (usdm) {
3367
+ // calculate liquidation price
3368
+ //
3369
+ // liquidationPrice = (walletBalance / (contracts * (±1 + mmp))) + (±entryPrice / (±1 + mmp))
3370
+ //
3371
+ // mmp = maintenanceMarginPercentage
3372
+ // where ± is negative for long and positive for short
3373
+ // TODO: calculate liquidation price for coinm contracts
3374
+ let onePlusMaintenanceMarginPercentageString = undefined;
3375
+ let entryPriceSignString = entryPriceString;
3376
+ if (side === 'short') {
3377
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringAdd('1', maintenanceMarginPercentageString);
3378
+ }
3379
+ else {
3380
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringAdd('-1', maintenanceMarginPercentageString);
3381
+ entryPriceSignString = Precise["default"].stringMul('-1', entryPriceSignString);
3382
+ }
3383
+ const leftSide = Precise["default"].stringDiv(walletBalance, Precise["default"].stringMul(contractsStringAbs, onePlusMaintenanceMarginPercentageString));
3384
+ const rightSide = Precise["default"].stringDiv(entryPriceSignString, onePlusMaintenanceMarginPercentageString);
3385
+ liquidationPriceStringRaw = Precise["default"].stringAdd(leftSide, rightSide);
3386
+ }
3387
+ else {
3388
+ // calculate liquidation price
3389
+ //
3390
+ // liquidationPrice = (contracts * contractSize(±1 - mmp)) / (±1/entryPrice * contracts * contractSize - walletBalance)
3391
+ //
3392
+ let onePlusMaintenanceMarginPercentageString = undefined;
3393
+ let entryPriceSignString = entryPriceString;
3394
+ if (side === 'short') {
3395
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringSub('1', maintenanceMarginPercentageString);
3396
+ }
3397
+ else {
3398
+ onePlusMaintenanceMarginPercentageString = Precise["default"].stringSub('-1', maintenanceMarginPercentageString);
3399
+ entryPriceSignString = Precise["default"].stringMul('-1', entryPriceSignString);
3400
+ }
3401
+ const size = Precise["default"].stringMul(contractsStringAbs, contractSizeString);
3402
+ const leftSide = Precise["default"].stringMul(size, onePlusMaintenanceMarginPercentageString);
3403
+ const rightSide = Precise["default"].stringSub(Precise["default"].stringMul(Precise["default"].stringDiv('1', entryPriceSignString), size), walletBalance);
3404
+ liquidationPriceStringRaw = Precise["default"].stringDiv(leftSide, rightSide);
3405
+ }
3406
+ const pricePrecision = this.precisionFromString(this.safeString(market['precision'], 'price'));
3407
+ const pricePrecisionPlusOne = pricePrecision + 1;
3408
+ const pricePrecisionPlusOneString = pricePrecisionPlusOne.toString();
3409
+ // round half up
3410
+ const rounder = new Precise["default"]('5e-' + pricePrecisionPlusOneString);
3411
+ const rounderString = rounder.toString();
3412
+ const liquidationPriceRoundedString = Precise["default"].stringAdd(rounderString, liquidationPriceStringRaw);
3413
+ let truncatedLiquidationPrice = Precise["default"].stringDiv(liquidationPriceRoundedString, '1', pricePrecision);
3414
+ if (truncatedLiquidationPrice[0] === '-') {
3415
+ // user cannot be liquidated
3416
+ // since he has more collateral than the size of the position
3417
+ truncatedLiquidationPrice = undefined;
3418
+ }
3419
+ liquidationPrice = this.parseNumber(truncatedLiquidationPrice);
3420
+ }
3421
+ const positionSide = this.safeString(position, 'positionSide');
3422
+ const hedged = positionSide !== 'BOTH';
3423
+ return {
3424
+ 'info': position,
3425
+ 'id': undefined,
3426
+ 'symbol': symbol,
3427
+ 'timestamp': timestamp,
3428
+ 'datetime': this.iso8601(timestamp),
3429
+ 'initialMargin': initialMargin,
3430
+ 'initialMarginPercentage': this.parseNumber(initialMarginPercentageString),
3431
+ 'maintenanceMargin': maintenanceMargin,
3432
+ 'maintenanceMarginPercentage': maintenanceMarginPercentage,
3433
+ 'entryPrice': entryPrice,
3434
+ 'notional': notional,
3435
+ 'leverage': this.parseNumber(leverageString),
3436
+ 'unrealizedPnl': unrealizedPnl,
3437
+ 'contracts': contracts,
3438
+ 'contractSize': contractSize,
3439
+ 'marginRatio': marginRatio,
3440
+ 'liquidationPrice': liquidationPrice,
3441
+ 'markPrice': undefined,
3442
+ 'collateral': collateral,
3443
+ 'marginMode': marginMode,
3444
+ 'side': side,
3445
+ 'hedged': hedged,
3446
+ 'percentage': percentage,
3447
+ };
3448
+ }
3449
+ /**
3450
+ * @method
3451
+ * @name aster#fetchAccountPositions
3452
+ * @ignore
3453
+ * @description fetch account positions
3454
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
3455
+ * @param {string[]} [symbols] list of unified market symbols
3456
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3457
+ * @returns {object} data on account positions
3458
+ */
3459
+ async fetchAccountPositions(symbols = undefined, params = {}) {
3460
+ if (symbols !== undefined) {
3461
+ if (!Array.isArray(symbols)) {
3462
+ throw new errors.ArgumentsRequired(this.id + ' fetchPositions() requires an array argument for symbols');
3463
+ }
3464
+ }
3465
+ await this.loadMarkets();
3466
+ await this.loadLeverageBrackets(false, params);
3467
+ const response = await this.fapiPrivateGetV4Account(params);
3468
+ let filterClosed = undefined;
3469
+ [filterClosed, params] = this.handleOptionAndParams(params, 'fetchAccountPositions', 'filterClosed', false);
3470
+ const result = this.parseAccountPositions(response, filterClosed);
3471
+ symbols = this.marketSymbols(symbols);
3472
+ return this.filterByArrayPositions(result, 'symbol', symbols, false);
3473
+ }
3474
+ async loadLeverageBrackets(reload = false, params = {}) {
3475
+ await this.loadMarkets();
3476
+ // by default cache the leverage bracket
3477
+ // it contains useful stuff like the maintenance margin and initial margin for positions
3478
+ const leverageBrackets = this.safeDict(this.options, 'leverageBrackets');
3479
+ if ((leverageBrackets === undefined) || (reload)) {
3480
+ const response = await this.fapiPrivateGetV1LeverageBracket(params);
3481
+ this.options['leverageBrackets'] = this.createSafeDictionary();
3482
+ for (let i = 0; i < response.length; i++) {
3483
+ const entry = response[i];
3484
+ const marketId = this.safeString(entry, 'symbol');
3485
+ const symbol = this.safeSymbol(marketId, undefined, undefined, 'contract');
3486
+ const brackets = this.safeList(entry, 'brackets', []);
3487
+ const result = [];
3488
+ for (let j = 0; j < brackets.length; j++) {
3489
+ const bracket = brackets[j];
3490
+ const floorValue = this.safeString(bracket, 'notionalFloor');
3491
+ const maintenanceMarginPercentage = this.safeString(bracket, 'maintMarginRatio');
3492
+ result.push([floorValue, maintenanceMarginPercentage]);
3493
+ }
3494
+ this.options['leverageBrackets'][symbol] = result;
3495
+ }
3496
+ }
3497
+ return this.options['leverageBrackets'];
3498
+ }
3499
+ keccakMessage(message) {
3500
+ return '0x' + this.hash(message, sha3.keccak_256, 'hex');
3501
+ }
3502
+ signMessage(message, privateKey) {
3503
+ return this.signHash(this.keccakMessage(message), privateKey.slice(-64));
3504
+ }
3505
+ signWithdrawPayload(withdrawPayload, network) {
3506
+ const zeroAddress = this.safeString(this.options, 'zeroAddress');
3507
+ const chainId = this.safeInteger(withdrawPayload, 'chainId');
3508
+ const domain = {
3509
+ 'chainId': chainId,
3510
+ 'name': 'Aster',
3511
+ 'verifyingContract': zeroAddress,
3512
+ 'version': '1',
3513
+ };
3514
+ const messageTypes = {
3515
+ 'Action': [
3516
+ { 'name': 'type', 'type': 'string' },
3517
+ { 'name': 'destination', 'type': 'address' },
3518
+ { 'name': 'destination Chain', 'type': 'string' },
3519
+ { 'name': 'token', 'type': 'string' },
3520
+ { 'name': 'amount', 'type': 'string' },
3521
+ { 'name': 'fee', 'type': 'string' },
3522
+ { 'name': 'nonce', 'type': 'uint256' },
3523
+ { 'name': 'aster chain', 'type': 'string' },
3524
+ ],
3525
+ };
3526
+ const withdraw = {
3527
+ 'type': 'Withdraw',
3528
+ 'destination': this.safeString(withdrawPayload, 'receiver'),
3529
+ 'destination Chain': network,
3530
+ 'token': this.safeString(withdrawPayload, 'asset'),
3531
+ 'amount': this.safeString(withdrawPayload, 'amount'),
3532
+ 'fee': this.safeString(withdrawPayload, 'fee'),
3533
+ 'nonce': this.safeInteger(withdrawPayload, 'nonce'),
3534
+ 'aster chain': 'Mainnet',
3535
+ };
3536
+ const msg = this.ethEncodeStructuredData(domain, messageTypes, withdraw);
3537
+ const signature = this.signMessage(msg, this.privateKey);
3538
+ return signature;
3539
+ }
3540
+ /**
3541
+ * @method
3542
+ * @name aster#withdraw
3543
+ * @description make a withdrawal
3544
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#withdraw-user_data
3545
+ * @param {string} code unified currency code
3546
+ * @param {float} amount the amount to withdraw
3547
+ * @param {string} address the address to withdraw to
3548
+ * @param {string} tag
3549
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3550
+ * @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
3551
+ */
3552
+ async withdraw(code, amount, address, tag = undefined, params = {}) {
3553
+ [tag, params] = this.handleWithdrawTagAndParams(tag, params);
3554
+ this.checkAddress(address);
3555
+ await this.loadMarkets();
3556
+ const currency = this.currency(code);
3557
+ const request = {
3558
+ 'asset': currency['id'],
3559
+ 'receiver': address,
3560
+ 'nonce': this.milliseconds() * 1000,
3561
+ };
3562
+ let chainId = this.safeInteger(params, 'chainId');
3563
+ // TODO: check how ARBI signature would work
3564
+ const networks = this.safeDict(this.options, 'networks', {});
3565
+ let network = this.safeStringUpper(params, 'network');
3566
+ network = this.safeString(networks, network, network);
3567
+ if ((chainId === undefined) && (network !== undefined)) {
3568
+ const chainIds = this.safeDict(this.options, 'networksToChainId', {});
3569
+ chainId = this.safeInteger(chainIds, network);
3570
+ }
3571
+ if (chainId === undefined) {
3572
+ throw new errors.ArgumentsRequired(this.id + ' withdraw require chainId or network parameter');
3573
+ }
3574
+ request['chainId'] = chainId;
3575
+ const fee = this.safeString(params, 'fee');
3576
+ if (fee === undefined) {
3577
+ throw new errors.ArgumentsRequired(this.id + ' withdraw require fee parameter');
3578
+ }
3579
+ request['fee'] = fee;
3580
+ params = this.omit(params, ['chainId', 'network', 'fee']);
3581
+ request['amount'] = this.currencyToPrecision(code, amount, network);
3582
+ request['userSignature'] = this.signWithdrawPayload(request, network);
3583
+ const response = await this.sapiPrivatePostV1AsterUserWithdraw(this.extend(request, params));
3584
+ return {
3585
+ 'info': response,
3586
+ 'id': this.safeString(response, 'withdrawId'),
3587
+ 'txid': this.safeString(response, 'hash'),
3588
+ 'timestamp': undefined,
3589
+ 'datetime': undefined,
3590
+ 'network': network,
3591
+ 'address': address,
3592
+ 'addressTo': address,
3593
+ 'addressFrom': undefined,
3594
+ 'tag': tag,
3595
+ 'tagTo': tag,
3596
+ 'tagFrom': undefined,
3597
+ 'type': 'withdrawal',
3598
+ 'amount': amount,
3599
+ 'currency': code,
3600
+ 'status': undefined,
3601
+ 'updated': undefined,
3602
+ 'internal': undefined,
3603
+ 'comment': undefined,
3604
+ 'fee': undefined,
3605
+ };
3606
+ }
3607
+ /**
3608
+ * @method
3609
+ * @name aster#transfer
3610
+ * @description transfer currency internally between wallets on the same account
3611
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#transfer-asset-to-other-address-trade
3612
+ * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#transfer-between-futures-and-spot-user_data
3613
+ * @param {string} code unified currency code
3614
+ * @param {float} amount amount to transfer
3615
+ * @param {string} fromAccount account to transfer from
3616
+ * @param {string} toAccount account to transfer to
3617
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
3618
+ * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
3619
+ */
3620
+ async transfer(code, amount, fromAccount, toAccount, params = {}) {
3621
+ await this.loadMarkets();
3622
+ const currency = this.currency(code);
3623
+ const request = {
3624
+ 'asset': currency['id'],
3625
+ 'amount': this.currencyToPrecision(code, amount),
3626
+ };
3627
+ let type = undefined;
3628
+ let fromId = undefined;
3629
+ if (fromAccount !== undefined) {
3630
+ fromId = this.convertTypeToAccount(fromAccount).toUpperCase();
3631
+ }
3632
+ let toId = undefined;
3633
+ if (toAccount !== undefined) {
3634
+ toId = this.convertTypeToAccount(toAccount).toUpperCase();
3635
+ }
3636
+ if (fromId === 'SPOT' && toId === 'FUTURE') {
3637
+ type = 'SPOT_FUTURE';
3638
+ }
3639
+ else if (fromId === 'FUTURE' && toId === 'SPOT') {
3640
+ type = 'FUTURE_SPOT';
3641
+ }
3642
+ let response = undefined;
3643
+ if (type !== undefined) {
3644
+ const defaultClientTranId = this.numberToString(this.milliseconds());
3645
+ const clientTranId = this.safeString(params, 'clientTranId', defaultClientTranId);
3646
+ request['kindType'] = type;
3647
+ request['clientTranId'] = clientTranId;
3648
+ response = await this.fapiPrivatePostV1AssetWalletTransfer(this.extend(request, params));
3649
+ }
3650
+ else {
3651
+ // transfer asset to other address
3652
+ request['toAddress'] = toAccount;
3653
+ response = await this.sapiPrivatePostV1AssetSendToAddress(this.extend(request, params));
3654
+ }
3655
+ //
3656
+ // {
3657
+ // "tranId":13526853623,
3658
+ // "status": "SUCCESS"
3659
+ // }
3660
+ //
3661
+ return {
3662
+ 'info': response,
3663
+ 'id': this.safeString(response, 'tranId'),
3664
+ 'txid': undefined,
3665
+ 'timestamp': undefined,
3666
+ 'datetime': undefined,
3667
+ 'network': undefined,
3668
+ 'address': undefined,
3669
+ 'addressTo': fromAccount,
3670
+ 'addressFrom': toAccount,
3671
+ 'tag': undefined,
3672
+ 'tagTo': undefined,
3673
+ 'tagFrom': undefined,
3674
+ 'type': 'transfer',
3675
+ 'amount': amount,
3676
+ 'currency': code,
3677
+ 'status': undefined,
3678
+ 'updated': undefined,
3679
+ 'internal': undefined,
3680
+ 'comment': undefined,
3681
+ 'fee': undefined,
3682
+ };
3683
+ }
3684
+ hashMessage(binaryMessage) {
3685
+ // const binaryMessage = this.encode (message);
3686
+ const binaryMessageLength = this.binaryLength(binaryMessage);
3687
+ const x19 = this.base16ToBinary('19');
3688
+ const newline = this.base16ToBinary('0a');
3689
+ const prefix = this.binaryConcat(x19, this.encode('Ethereum Signed Message:'), newline, this.encode(this.numberToString(binaryMessageLength)));
3690
+ return '0x' + this.hash(this.binaryConcat(prefix, binaryMessage), sha3.keccak_256, 'hex');
3691
+ }
3692
+ signHash(hash, privateKey) {
3693
+ this.checkRequiredCredentials();
3694
+ const signature = crypto.ecdsa(hash.slice(-64), privateKey.slice(-64), secp256k1.secp256k1, undefined);
3695
+ const r = signature['r'];
3696
+ const s = signature['s'];
3697
+ const v = this.intToBase16(this.sum(27, signature['v']));
3698
+ return '0x' + r.padStart(64, '0') + s.padStart(64, '0') + v;
3699
+ }
3700
+ sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
3701
+ let url = this.implodeHostname(this.urls['api'][api]) + '/' + path;
3702
+ if (api === 'fapiPublic' || api === 'sapiPublic') {
3703
+ if (Object.keys(params).length) {
3704
+ url += '?' + this.rawencode(params);
3705
+ }
3706
+ }
3707
+ else if (api === 'fapiPrivate' || api === 'sapiPrivate') {
3708
+ this.checkRequiredCredentials();
3709
+ headers = {
3710
+ 'X-MBX-APIKEY': this.apiKey,
3711
+ };
3712
+ const nonce = this.milliseconds();
3713
+ const defaultRecvWindow = this.safeInteger(this.options, 'recvWindow');
3714
+ let extendedParams = this.extend({
3715
+ 'timestamp': nonce,
3716
+ }, params);
3717
+ if (defaultRecvWindow !== undefined) {
3718
+ extendedParams['recvWindow'] = defaultRecvWindow;
3719
+ }
3720
+ const recvWindow = this.safeInteger(params, 'recvWindow');
3721
+ if (recvWindow !== undefined) {
3722
+ extendedParams['recvWindow'] = recvWindow;
3723
+ }
3724
+ let query = undefined;
3725
+ if ((method === 'DELETE') && (path === 'v1/batchOrders')) {
3726
+ const orderidlist = this.safeList(extendedParams, 'orderIdList', []);
3727
+ const origclientorderidlist = this.safeList(extendedParams, 'origClientOrderIdList', []);
3728
+ extendedParams = this.omit(extendedParams, ['orderIdList', 'origClientOrderIdList']);
3729
+ query = this.rawencode(extendedParams);
3730
+ const orderidlistLength = orderidlist.length;
3731
+ const origclientorderidlistLength = origclientorderidlist.length;
3732
+ if (orderidlistLength > 0) {
3733
+ query = query + '&' + 'orderidlist=%5B' + orderidlist.join('%2C') + '%5D';
3734
+ }
3735
+ if (origclientorderidlistLength > 0) {
3736
+ query = query + '&' + 'origclientorderidlist=%5B' + origclientorderidlist.join('%2C') + '%5D';
3737
+ }
3738
+ }
3739
+ else {
3740
+ query = this.rawencode(extendedParams);
3741
+ }
3742
+ let signature = '';
3743
+ if (path.indexOf('v3') >= 0) {
3744
+ const signerAddress = this.options['signerAddress'];
3745
+ if (signerAddress === undefined) {
3746
+ throw new errors.ArgumentsRequired(this.id + ' requires signerAddress in options when use v3 api');
3747
+ }
3748
+ // the keys order matter
3749
+ const keys = Object.keys(extendedParams);
3750
+ const sortedKeys = this.sort(keys);
3751
+ const signingPayload = {};
3752
+ for (let i = 0; i < sortedKeys.length; i++) {
3753
+ const key = sortedKeys[i];
3754
+ signingPayload[key] = extendedParams[key].toString();
3755
+ }
3756
+ const signingHash = this.hashMessage(this.hash(this.ethAbiEncode([
3757
+ 'string', 'address', 'address', 'uint256',
3758
+ ], [this.json(signingPayload), this.walletAddress, signerAddress, nonce]), sha3.keccak_256, 'binary'));
3759
+ signature = this.signHash(signingHash, this.privateKey);
3760
+ extendedParams['user'] = this.walletAddress;
3761
+ extendedParams['signer'] = signerAddress;
3762
+ extendedParams['nonce'] = nonce;
3763
+ query = this.rawencode(extendedParams);
3764
+ }
3765
+ else {
3766
+ signature = this.hmac(this.encode(query), this.encode(this.secret), sha256.sha256);
3767
+ }
3768
+ query += '&' + 'signature=' + signature;
3769
+ if (method === 'GET') {
3770
+ url += '?' + query;
3771
+ }
3772
+ else {
3773
+ body = query;
3774
+ headers['Content-Type'] = 'application/x-www-form-urlencoded';
3775
+ }
3776
+ }
3777
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
3778
+ }
3779
+ handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
3780
+ if (response === undefined) {
3781
+ return undefined; // fallback to default error handler
3782
+ }
3783
+ //
3784
+ // {
3785
+ // "code": -1121,
3786
+ // "msg": "Invalid symbol.",
3787
+ // }
3788
+ //
3789
+ const code = this.safeString(response, 'code');
3790
+ const message = this.safeString(response, 'msg');
3791
+ if (code !== undefined && code !== '200') {
3792
+ const feedback = this.id + ' ' + body;
3793
+ this.throwExactlyMatchedException(this.exceptions['exact'], message, feedback);
3794
+ this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
3795
+ this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
3796
+ throw new errors.ExchangeError(feedback); // unknown message
3797
+ }
3798
+ return undefined;
3799
+ }
3800
+ }
3801
+
3802
+ exports["default"] = aster;