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