ccxt 4.5.51 → 4.5.52

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.
package/js/src/aster.js CHANGED
@@ -3,7 +3,6 @@ import Exchange from './abstract/aster.js';
3
3
  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';
4
4
  import { TRUNCATE, TICK_SIZE } from './base/functions/number.js';
5
5
  import Precise from './base/Precise.js';
6
- import { sha256 } from './static_dependencies/noble-hashes/sha256.js';
7
6
  import { ecdsa } from './base/functions/crypto.js';
8
7
  import { keccak_256 as keccak } from './static_dependencies/noble-hashes/sha3.js';
9
8
  import { secp256k1 } from './static_dependencies/noble-curves/secp256k1.js';
@@ -183,169 +182,217 @@ export default class aster extends Exchange {
183
182
  'setMargin': false,
184
183
  'setMarginMode': true,
185
184
  'setPositionMode': true,
186
- 'signIn': false,
185
+ 'signIn': true,
187
186
  'transfer': true,
188
187
  'withdraw': true,
189
188
  },
190
189
  'api': {
191
190
  'fapiPublic': {
192
- 'get': [
193
- 'v1/ping',
194
- 'v3/ping',
195
- 'v1/time',
196
- 'v3/time',
197
- 'v1/exchangeInfo',
198
- 'v3/exchangeInfo',
199
- 'v1/depth',
200
- 'v3/depth',
201
- 'v1/trades',
202
- 'v3/trades',
203
- 'v1/historicalTrades',
204
- 'v3/historicalTrades',
205
- 'v1/aggTrades',
206
- 'v3/aggTrades',
207
- 'v1/klines',
208
- 'v3/klines',
209
- 'v1/indexPriceKlines',
210
- 'v3/indexPriceKlines',
211
- 'v1/markPriceKlines',
212
- 'v3/markPriceKlines',
213
- 'v1/premiumIndex',
214
- 'v3/premiumIndex',
215
- 'v1/fundingRate',
216
- 'v3/fundingRate',
217
- 'v1/fundingInfo',
218
- 'v3/fundingInfo',
219
- 'v1/ticker/24hr',
220
- 'v3/ticker/24hr',
221
- 'v1/ticker/price',
222
- 'v3/ticker/price',
223
- 'v1/ticker/bookTicker',
224
- 'v3/ticker/bookTicker',
225
- 'v3/indexreferences',
226
- 'v1/adlQuantile',
227
- 'v1/forceOrders',
228
- ],
191
+ 'get': {
192
+ 'v1/ping': 1,
193
+ 'v3/ping': 1,
194
+ 'v1/time': 1,
195
+ 'v3/time': 1,
196
+ 'v1/exchangeInfo': 1,
197
+ 'v3/exchangeInfo': 1,
198
+ 'v1/depth': 1,
199
+ 'v3/depth': 2,
200
+ 'v1/trades': 1,
201
+ 'v3/trades': 1,
202
+ 'v1/historicalTrades': 1,
203
+ 'v3/historicalTrades': 20,
204
+ 'v1/aggTrades': 1,
205
+ 'v3/aggTrades': 20,
206
+ 'v1/klines': 1,
207
+ 'v3/klines': 1,
208
+ 'v1/indexPriceKlines': 1,
209
+ 'v3/indexPriceKlines': 1,
210
+ 'v1/markPriceKlines': 1,
211
+ 'v3/markPriceKlines': 1,
212
+ 'v1/premiumIndex': 1,
213
+ 'v3/premiumIndex': 1,
214
+ 'v1/fundingRate': 1,
215
+ 'v3/fundingRate': 1,
216
+ 'v1/fundingInfo': 1,
217
+ 'v3/fundingInfo': 1,
218
+ 'v1/ticker/24hr': 1,
219
+ 'v3/ticker/24hr': 1,
220
+ 'v1/ticker/price': 1,
221
+ 'v3/ticker/price': 1,
222
+ 'v1/ticker/bookTicker': 1,
223
+ 'v3/ticker/bookTicker': 1,
224
+ // different endpoints
225
+ 'v1/adlQuantile': 1,
226
+ 'v1/forceOrders': 1,
227
+ 'v3/indexreferences': 1,
228
+ },
229
229
  },
230
230
  'fapiPrivate': {
231
- 'get': [
232
- 'v1/positionSide/dual',
233
- 'v3/positionSide/dual',
234
- 'v1/multiAssetsMargin',
235
- 'v3/multiAssetsMargin',
236
- 'v1/order',
237
- 'v3/order',
238
- 'v1/openOrder',
239
- 'v3/openOrder',
240
- 'v1/openOrders',
241
- 'v3/openOrders',
242
- 'v1/allOrders',
243
- 'v3/allOrders',
244
- 'v2/balance',
245
- 'v3/balance',
246
- 'v3/account',
247
- 'v3/accountWithJoinMargin',
248
- 'v4/account',
249
- 'v1/positionMargin/history',
250
- 'v3/positionMargin/history',
251
- 'v2/positionRisk',
252
- 'v3/positionRisk',
253
- 'v1/userTrades',
254
- 'v3/userTrades',
255
- 'v1/income',
256
- 'v3/income',
257
- 'v1/leverageBracket',
258
- 'v3/leverageBracket',
259
- 'v3/adlQuantile',
260
- 'v3/forceOrders',
261
- 'v1/commissionRate',
262
- 'v3/commissionRate',
263
- 'v3/mmp',
264
- ],
265
- 'post': [
266
- 'v3/noop',
267
- 'v1/positionSide/dual',
268
- 'v3/positionSide/dual',
269
- 'v1/multiAssetsMargin',
270
- 'v3/multiAssetsMargin',
271
- 'v1/order',
272
- 'v3/order',
273
- 'v1/order/test',
274
- 'v3/order/test',
275
- 'v1/batchOrders',
276
- 'v3/batchOrders',
277
- 'v1/asset/wallet/transfer',
278
- 'v3/asset/wallet/transfer',
279
- 'v1/countdownCancelAll',
280
- 'v3/countdownCancelAll',
281
- 'v1/leverage',
282
- 'v3/leverage',
283
- 'v1/marginType',
284
- 'v3/marginType',
285
- 'v1/positionMargin',
286
- 'v3/positionMargin',
287
- 'v3/mmp',
288
- 'v3/mmpReset',
289
- 'v1/listenKey',
290
- 'v3/listenKey',
291
- ],
292
- 'put': [
293
- 'v1/listenKey',
294
- 'v3/listenKey',
295
- ],
296
- 'delete': [
297
- 'v1/order',
298
- 'v3/order',
299
- 'v1/allOpenOrders',
300
- 'v3/allOpenOrders',
301
- 'v1/batchOrders',
302
- 'v3/batchOrders',
303
- 'v3/mmp',
304
- 'v1/listenKey',
305
- 'v3/listenKey',
306
- ],
231
+ 'get': {
232
+ 'v1/positionSide/dual': 1,
233
+ 'v3/positionSide/dual': 30,
234
+ 'v1/multiAssetsMargin': 1,
235
+ 'v3/multiAssetsMargin': 1,
236
+ 'v1/order': 1,
237
+ 'v3/order': 1,
238
+ 'v1/openOrder': 1,
239
+ 'v3/openOrder': 1,
240
+ 'v1/openOrders': 1,
241
+ 'v3/openOrders': 1,
242
+ 'v1/allOrders': 1,
243
+ 'v3/allOrders': 1,
244
+ 'v2/balance': 1,
245
+ 'v3/balance': 1,
246
+ 'v3/account': 1,
247
+ 'v1/positionMargin/history': 1,
248
+ 'v3/positionMargin/history': 1,
249
+ 'v2/positionRisk': 1,
250
+ 'v3/positionRisk': 1,
251
+ 'v1/userTrades': 1,
252
+ 'v3/userTrades': 5,
253
+ 'v1/income': 1,
254
+ 'v3/income': 1,
255
+ 'v1/leverageBracket': 1,
256
+ 'v3/leverageBracket': 1,
257
+ 'v1/commissionRate': 1,
258
+ 'v3/commissionRate': 1,
259
+ // others
260
+ 'v3/adlQuantile': 1,
261
+ 'v3/forceOrders': 1,
262
+ 'v3/mmp': 1,
263
+ 'v3/accountWithJoinMargin': 1,
264
+ 'v4/account': 1,
265
+ // builder
266
+ 'v3/agent': 1,
267
+ 'v3/builder': 1,
268
+ },
269
+ 'post': {
270
+ 'v1/positionSide/dual': 1,
271
+ 'v3/positionSide/dual': 1,
272
+ 'v1/multiAssetsMargin': 1,
273
+ 'v3/multiAssetsMargin': 1,
274
+ 'v1/order': 1,
275
+ 'v3/order': 1,
276
+ 'v1/order/test': 1,
277
+ 'v3/order/test': 1,
278
+ 'v1/batchOrders': 1,
279
+ 'v3/batchOrders': 1,
280
+ 'v1/asset/wallet/transfer': 1,
281
+ 'v3/asset/wallet/transfer': 1,
282
+ 'v1/countdownCancelAll': 1,
283
+ 'v3/countdownCancelAll': 1,
284
+ 'v1/leverage': 1,
285
+ 'v3/leverage': 1,
286
+ 'v1/marginType': 1,
287
+ 'v3/marginType': 1,
288
+ 'v1/positionMargin': 1,
289
+ 'v3/positionMargin': 1,
290
+ 'v1/listenKey': 1,
291
+ 'v3/listenKey': 1,
292
+ // others
293
+ 'v3/mmp': 1,
294
+ 'v3/mmpReset': 1,
295
+ 'v3/noop': 1,
296
+ // builder
297
+ 'v3/approveAgent': 1,
298
+ 'v3/updateAgent': 1,
299
+ 'v3/approveBuilder': 1,
300
+ 'v3/updateBuilder': 1,
301
+ },
302
+ 'put': {
303
+ 'v1/listenKey': 1,
304
+ 'v3/listenKey': 1,
305
+ },
306
+ 'delete': {
307
+ 'v1/order': 1,
308
+ 'v3/order': 1,
309
+ 'v1/allOpenOrders': 1,
310
+ 'v3/allOpenOrders': 1,
311
+ 'v1/batchOrders': 1,
312
+ 'v3/batchOrders': 1,
313
+ 'v3/mmp': 1,
314
+ 'v1/listenKey': 1,
315
+ 'v3/listenKey': 1,
316
+ // builder
317
+ 'v3/agent': 1,
318
+ 'v3/builder': 1,
319
+ },
307
320
  },
308
321
  'sapiPublic': {
309
- 'get': [
310
- 'v1/ping',
311
- 'v1/time',
312
- 'v1/exchangeInfo',
313
- 'v1/depth',
314
- 'v1/trades',
315
- 'v1/historicalTrades',
316
- 'v1/aggTrades',
317
- 'v1/klines',
318
- 'v1/ticker/24hr',
319
- 'v1/ticker/price',
320
- 'v1/ticker/bookTicker',
321
- 'v1/aster/withdraw/estimateFee',
322
- ],
322
+ 'get': {
323
+ // v1
324
+ 'v1/ping': 1,
325
+ 'v1/time': 1,
326
+ 'v1/exchangeInfo': 1,
327
+ 'v1/depth': 1,
328
+ 'v1/trades': 1,
329
+ 'v1/historicalTrades': 1,
330
+ 'v1/aggTrades': 1,
331
+ 'v1/klines': 1,
332
+ 'v1/ticker/24hr': 1,
333
+ 'v1/ticker/price': 1,
334
+ 'v1/ticker/bookTicker': 1,
335
+ 'v1/aster/withdraw/estimateFee': 1,
336
+ // v3
337
+ 'v3/ping': 1,
338
+ 'v3/time': 1,
339
+ 'v3/exchangeInfo': 1,
340
+ 'v3/depth': { 'cost': 2, 'byLimit': [[50, 2], [100, 5], [500, 10], [1000, 20]] },
341
+ 'v3/trades': 1,
342
+ 'v3/historicalTrades': 20,
343
+ 'v3/aggTrades': 20,
344
+ 'v3/klines': { 'cost': 1, 'byLimit': [[99, 1], [499, 2], [1000, 5], [10000, 10]] },
345
+ 'v3/ticker/24hr': { 'cost': 1, 'noSymbol': 40 },
346
+ 'v3/ticker/price': { 'cost': 1, 'noSymbol': 2 },
347
+ 'v3/ticker/bookTicker': { 'cost': 1, 'noSymbol': 2 },
348
+ 'v3/aster/withdraw/estimateFee': 1,
349
+ },
323
350
  },
324
351
  'sapiPrivate': {
325
- 'get': [
326
- 'v1/commissionRate',
327
- 'v1/order',
328
- 'v1/openOrders',
329
- 'v1/allOrders',
330
- 'v1/transactionHistory',
331
- 'v1/account',
332
- 'v1/userTrades',
333
- ],
334
- 'post': [
335
- 'v1/order',
336
- 'v1/asset/wallet/transfer',
337
- 'v1/asset/sendToAddress',
338
- 'v1/aster/user-withdraw',
339
- 'v1/listenKey',
340
- ],
352
+ 'get': {
353
+ // v1
354
+ 'v1/commissionRate': 1,
355
+ 'v1/order': 1,
356
+ 'v1/openOrders': 1,
357
+ 'v1/allOrders': 1,
358
+ 'v1/transactionHistory': 1,
359
+ 'v1/account': 1,
360
+ 'v1/userTrades': 1,
361
+ // v3
362
+ 'v3/commissionRate': { 'cost': 1, 'noSymbol': 2 },
363
+ 'v3/order': 1,
364
+ 'v3/openOrders': 1,
365
+ 'v3/allOrders': 5,
366
+ 'v3/account': 5,
367
+ 'v3/userTrades': 5,
368
+ 'v3/openOrder': 1,
369
+ },
370
+ 'post': {
371
+ // v1
372
+ 'v1/order': 1,
373
+ 'v1/asset/wallet/transfer': 5,
374
+ 'v1/asset/sendToAddress': 1,
375
+ 'v1/listenKey': 1,
376
+ // v3
377
+ 'v3/order': 1,
378
+ 'v3/asset/wallet/transfer': 5,
379
+ 'v3/aster/user-withdraw': 1,
380
+ 'v3/listenKey': 1,
381
+ },
341
382
  'put': [
342
383
  'v1/listenKey',
384
+ 'v3/listenKey',
343
385
  ],
344
- 'delete': [
345
- 'v1/order',
346
- 'v1/allOpenOrders',
347
- 'v1/listenKey',
348
- ],
386
+ 'delete': {
387
+ // v1
388
+ 'v1/order': 1,
389
+ 'v1/allOpenOrders': 1,
390
+ 'v1/listenKey': 1,
391
+ // v3
392
+ 'v3/allOpenOrders': 1,
393
+ 'v3/order': 1,
394
+ 'v3/listenKey': 1,
395
+ },
349
396
  },
350
397
  },
351
398
  'timeframes': {
@@ -367,8 +414,9 @@ export default class aster extends Exchange {
367
414
  },
368
415
  'precisionMode': TICK_SIZE,
369
416
  'requiredCredentials': {
370
- 'apiKey': true,
371
- 'secret': true,
417
+ 'apiKey': false,
418
+ 'secret': false,
419
+ 'privateKey': true,
372
420
  },
373
421
  'fees': {
374
422
  'trading': {
@@ -383,28 +431,35 @@ export default class aster extends Exchange {
383
431
  'recvWindow': 10 * 1000,
384
432
  'defaultTimeInForce': 'GTC',
385
433
  'zeroAddress': '0x0000000000000000000000000000000000000000',
434
+ 'v3ChainId': 1666,
386
435
  'quoteOrderQty': true,
387
436
  'accountsByType': {
388
437
  'spot': 'SPOT',
438
+ 'swap': 'FUTURE',
389
439
  'future': 'FUTURE',
390
440
  'linear': 'FUTURE',
391
- 'swap': 'FUTURE',
392
441
  },
393
442
  'networks': {
394
443
  'ERC20': 'ETH',
395
444
  'BEP20': 'BSC',
396
- 'ARB': 'Arbitrum',
445
+ 'ARBONE': 'Arbitrum',
397
446
  },
398
447
  'networksToChainId': {
399
448
  'ETH': 1,
400
449
  'BSC': 56,
401
450
  'Arbitrum': 42161,
402
451
  },
452
+ 'fetchOpenOrders': {
453
+ 'warnIfNoSymbol': true, // set to false to suppress warning when calling fetchOpenOrders without symbol
454
+ },
455
+ 'builderFee': true,
456
+ 'builder': '0x1F5877C19e3777Cfd15F9d57253eA4aA5254Ec39',
457
+ 'builderRate': '0.001',
403
458
  },
404
459
  'exceptions': {
405
460
  'exact': {
406
461
  // 10xx - General Server or Network issues
407
- '-1000': OperationFailed,
462
+ '-1000': OperationRejected,
408
463
  '-1001': NetworkError,
409
464
  '-1002': AuthenticationError,
410
465
  '-1003': RateLimitExceeded,
@@ -412,7 +467,7 @@ export default class aster extends Exchange {
412
467
  '-1005': BadRequest,
413
468
  '-1006': BadResponse,
414
469
  '-1007': RequestTimeout,
415
- '-1010': OperationFailed,
470
+ '-1010': OperationRejected,
416
471
  '-1011': PermissionDenied,
417
472
  '-1013': BadRequest,
418
473
  '-1014': OrderNotFillable,
@@ -566,7 +621,9 @@ export default class aster extends Exchange {
566
621
  '-4183': InvalidOrder,
567
622
  '-4184': InvalidOrder,
568
623
  '-5060': OperationRejected,
569
- '-5076': OperationRejected, // {"code":-5076,"msg":"Total order value should be more than 5 USDT"}
624
+ '-5076': OperationRejected,
625
+ // occured errors:
626
+ '-4168': OperationRejected, // Unable to adjust to isolated-margin mode under the Multi-Assets mode.
570
627
  },
571
628
  'broad': {},
572
629
  },
@@ -592,15 +649,15 @@ export default class aster extends Exchange {
592
649
  * @method
593
650
  * @name aster#fetchCurrencies
594
651
  * @description fetches all available currencies on an exchange
595
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#trading-specification-information
596
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#exchange-information
652
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#trading-specification-information
653
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#exchange-information
597
654
  * @param {object} [params] extra parameters specific to the exchange API endpoint
598
655
  * @returns {object} an associative dictionary of currencies
599
656
  */
600
657
  async fetchCurrencies(params = {}) {
601
658
  const promises = [
602
- this.sapiPublicGetV1ExchangeInfo(params),
603
- this.fapiPublicGetV1ExchangeInfo(params),
659
+ this.sapiPublicGetV3ExchangeInfo(params),
660
+ this.fapiPublicGetV3ExchangeInfo(params),
604
661
  ];
605
662
  const results = await Promise.all(promises);
606
663
  const sapiResult = this.safeDict(results, 0, {});
@@ -612,8 +669,8 @@ export default class aster extends Exchange {
612
669
  // [
613
670
  // {
614
671
  // "asset": "USDT",
615
- // "marginAvailable": true,
616
- // "autoAssetExchange": "-10000"
672
+ // "marginAvailable": true, // only in PERP
673
+ // "autoAssetExchange": "-10000" // only in PERP
617
674
  // }
618
675
  // ]
619
676
  //
@@ -656,263 +713,267 @@ export default class aster extends Exchange {
656
713
  * @method
657
714
  * @name aster#fetchMarkets
658
715
  * @description retrieves data on all markets for bigone
659
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#trading-specification-information
660
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#exchange-information
716
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#trading-specification-information
717
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#exchange-information
661
718
  * @param {object} [params] extra parameters specific to the exchange API endpoint
662
719
  * @returns {object[]} an array of objects representing market data
663
720
  */
664
721
  async fetchMarkets(params = {}) {
665
722
  const promises = [
666
- this.sapiPublicGetV1ExchangeInfo(params),
667
- this.fapiPublicGetV1ExchangeInfo(params),
723
+ this.sapiPublicGetV3ExchangeInfo(params),
724
+ this.fapiPublicGetV3ExchangeInfo(params),
668
725
  ];
726
+ promises.push(this.signIn());
669
727
  const results = await Promise.all(promises);
670
728
  const sapiResult = this.safeDict(results, 0, {});
671
729
  const sapiRows = this.safeList(sapiResult, 'symbols', []);
672
730
  const fapiResult = this.safeDict(results, 1, {});
673
731
  const fapiRows = this.safeList(fapiResult, 'symbols', []);
674
- const rows = this.arrayConcat(sapiRows, fapiRows);
732
+ //
733
+ // example:
675
734
  //
676
735
  // [
677
- // {
678
- // "symbol": "BTCUSDT",
679
- // "pair": "BTCUSDT",
680
- // "contractType": "PERPETUAL",
681
- // "deliveryDate": 4133404800000,
682
- // "onboardDate": 1627628400000,
683
- // "status": "TRADING",
684
- // "maintMarginPercent": "2.5000",
685
- // "requiredMarginPercent": "5.0000",
686
- // "baseAsset": "BTC",
687
- // "quoteAsset": "USDT",
688
- // "marginAsset": "USDT",
689
- // "pricePrecision": 1,
690
- // "quantityPrecision": 3,
691
- // "baseAssetPrecision": 8,
692
- // "quotePrecision": 8,
693
- // "underlyingType": "COIN",
694
- // "underlyingSubType": [],
695
- // "settlePlan": 0,
696
- // "triggerProtect": "0.0200",
697
- // "liquidationFee": "0.025000",
698
- // "marketTakeBound": "0.02",
699
- // "filters": [
700
- // {
701
- // "minPrice": "1",
702
- // "maxPrice": "1000000",
703
- // "filterType": "PRICE_FILTER",
704
- // "tickSize": "0.1"
705
- // },
706
- // {
707
- // "stepSize": "0.001",
708
- // "filterType": "LOT_SIZE",
709
- // "maxQty": "100",
710
- // "minQty": "0.001"
711
- // },
712
- // {
713
- // "stepSize": "0.001",
714
- // "filterType": "MARKET_LOT_SIZE",
715
- // "maxQty": "10",
716
- // "minQty": "0.001"
717
- // },
718
- // {
719
- // "limit": 200,
720
- // "filterType": "MAX_NUM_ORDERS"
721
- // },
722
- // {
723
- // "limit": 10,
724
- // "filterType": "MAX_NUM_ALGO_ORDERS"
725
- // },
726
- // {
727
- // "notional": "5",
728
- // "filterType": "MIN_NOTIONAL"
729
- // },
730
- // {
731
- // "multiplierDown": "0.9800",
732
- // "multiplierUp": "1.0200",
733
- // "multiplierDecimal": "4",
734
- // "filterType": "PERCENT_PRICE"
735
- // }
736
- // ],
737
- // "orderTypes": [
738
- // "LIMIT",
739
- // "MARKET",
740
- // "STOP",
741
- // "STOP_MARKET",
742
- // "TAKE_PROFIT",
743
- // "TAKE_PROFIT_MARKET",
744
- // "TRAILING_STOP_MARKET"
745
- // ],
746
- // "timeInForce": [
747
- // "GTC",
748
- // "IOC",
749
- // "FOK",
750
- // "GTX",
751
- // "RPI"
752
- // ]
753
- // }
736
+ // {
737
+ // symbol: "TESTUSDT",
738
+ // status: "TRADING",
739
+ // baseAsset: "TEST",
740
+ // quoteAsset: "USDT",
741
+ // pricePrecision: "2",
742
+ // quantityPrecision: "5",
743
+ // baseAssetPrecision: "8",
744
+ // quotePrecision: "8",
745
+ // listingTime: "1756289680210", // only in SPOT
746
+ // baseAssetAddress: null, // only in SPOT
747
+ // ocoAllowed: false, // only in SPOT
748
+ // pair: "ASTERUSDT", // only in PERP
749
+ // contractType: "PERPETUAL", // only in PERP
750
+ // deliveryDate: "4133404800000", // only in PERP
751
+ // onboardDate: "1758178800000", // only in PERP
752
+ // maintMarginPercent: "12.5000", // only in PERP
753
+ // requiredMarginPercent: "25.0000", // only in PERP
754
+ // marginAsset: "USDT", // only in PERP
755
+ // underlyingType: "COIN", // only in PERP
756
+ // underlyingSubType: [ "Top", ], // only in PERP
757
+ // symbolType: "0", // only in PERP
758
+ // tradingMode: "0", // only in PERP
759
+ // name: "", // only in PERP
760
+ // channel: "{}", // only in PERP
761
+ // sequenceNo: "100", // only in PERP
762
+ // twapMinNotional: "1000", // only in PERP
763
+ // imn: "4000.00", // only in PERP
764
+ // tags: [], // only in PERP
765
+ // settlePlan: "0", // only in PERP
766
+ // triggerProtect: "0.1500", // only in PERP
767
+ // liquidationFee: "0.025000", // only in PERP
768
+ // marketTakeBound: "0.05", // only in PERP
769
+ // createTime: "1758215451058", // only in PERP
770
+ // filters: [
771
+ // {
772
+ // minPrice: "0.01",
773
+ // maxPrice: "1000000",
774
+ // filterType: "PRICE_FILTER",
775
+ // tickSize: "0.01",
776
+ // },
777
+ // {
778
+ // stepSize: "0.00001",
779
+ // filterType: "LOT_SIZE",
780
+ // maxQty: "9000",
781
+ // minQty: "0.00001",
782
+ // },
783
+ // {
784
+ // stepSize: "0.00001",
785
+ // filterType: "MARKET_LOT_SIZE",
786
+ // maxQty: "9000",
787
+ // minQty: "0.00001",
788
+ // },
789
+ // {
790
+ // limit: "200",
791
+ // filterType: "MAX_NUM_ORDERS",
792
+ // },
793
+ // {
794
+ // minNotional: "5",
795
+ // filterType: "MIN_NOTIONAL",
796
+ // },
797
+ // {
798
+ // minNotional: "5",
799
+ // avgPriceMins: "5",
800
+ // applyMinToMarket: true,
801
+ // filterType: "NOTIONAL", // only in SPOT
802
+ // applyMaxToMarket: true,
803
+ // },
804
+ // {
805
+ // multiplierDown: "0.2",
806
+ // multiplierUp: "5",
807
+ // multiplierDecimal: "1",
808
+ // filterType: "PERCENT_PRICE",
809
+ // },
810
+ // {
811
+ // bidMultiplierUp: "5",
812
+ // askMultiplierUp: "5",
813
+ // bidMultiplierDown: "0.2",
814
+ // avgPriceMins: "5",
815
+ // multiplierDecimal: "1",
816
+ // filterType: "PERCENT_PRICE_BY_SIDE", // only in SPOT
817
+ // askMultiplierDown: "0.2",
818
+ // },
819
+ // ],
820
+ // orderTypes: [ "LIMIT", "MARKET", "STOP", "STOP_MARKET", "TAKE_PROFIT", "TAKE_PROFIT_MARKET", "TRAILING_STOP_MARKET", ],
821
+ // timeInForce: [ "GTC", "IOC", "FOK", "GTX", "HIDDEN", ],
822
+ // }
754
823
  // ]
755
824
  //
756
- const fees = this.fees;
757
- const result = [];
758
- for (let i = 0; i < rows.length; i++) {
759
- let swap = false;
760
- const market = rows[i];
761
- const id = this.safeString(market, 'symbol');
762
- const baseId = this.safeString(market, 'baseAsset');
763
- const quoteId = this.safeString(market, 'quoteAsset');
764
- const base = this.safeCurrencyCode(baseId);
765
- const quote = this.safeCurrencyCode(quoteId);
766
- const contractType = this.safeString(market, 'contractType');
767
- const contract = contractType !== undefined;
768
- let spot = true;
769
- if (contractType === 'PERPETUAL') {
770
- swap = true;
771
- spot = false;
772
- }
773
- let contractSize = undefined;
774
- let linear = undefined;
775
- let inverse = undefined;
776
- let symbol = base + '/' + quote;
777
- let settle = undefined;
778
- let settleId = undefined;
779
- if (contract) {
780
- settleId = this.safeString(market, 'marginAsset');
781
- settle = this.safeCurrencyCode(settleId);
782
- if (swap) {
783
- symbol = symbol + ':' + settle;
784
- }
785
- linear = settle === quote;
786
- inverse = settle === base;
787
- contractSize = this.safeNumber2(market, 'contractSize', 'unit', this.parseNumber('1'));
788
- }
789
- let unifiedType = undefined;
790
- if (spot) {
791
- unifiedType = 'spot';
792
- }
793
- else if (swap) {
794
- unifiedType = 'swap';
795
- }
796
- const status = this.safeString(market, 'status');
797
- const active = status === 'TRADING';
798
- const filters = this.safeList(market, 'filters', []);
799
- const filtersByType = this.indexBy(filters, 'filterType');
800
- const entry = this.safeMarketStructure({
801
- 'id': id,
802
- 'symbol': symbol,
803
- 'base': base,
804
- 'quote': quote,
805
- 'settle': settle,
806
- 'baseId': baseId,
807
- 'quoteId': quoteId,
808
- 'settleId': settleId,
809
- 'type': unifiedType,
810
- 'spot': spot,
811
- 'margin': false,
812
- 'swap': swap,
813
- 'future': false,
814
- 'option': false,
815
- 'active': active,
816
- 'contract': contract,
817
- 'linear': linear,
818
- 'inverse': inverse,
819
- 'taker': fees['trading']['taker'],
820
- 'maker': fees['trading']['maker'],
821
- 'contractSize': contractSize,
822
- 'expiry': undefined,
823
- 'expiryDatetime': undefined,
824
- 'strike': undefined,
825
- 'optionType': undefined,
826
- 'precision': {
827
- 'amount': this.parseNumber(this.parsePrecision(this.safeString(market, 'quantityPrecision'))),
828
- 'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision'))),
829
- 'base': this.parseNumber(this.parsePrecision(this.safeString(market, 'baseAssetPrecision'))),
830
- 'quote': this.parseNumber(this.parsePrecision(this.safeString(market, 'quotePrecision'))),
825
+ //
826
+ const rows = this.arrayConcat(sapiRows, fapiRows);
827
+ return this.parseMarkets(rows);
828
+ }
829
+ parseMarket(market) {
830
+ const id = this.safeString(market, 'symbol');
831
+ const baseId = this.safeString(market, 'baseAsset');
832
+ const quoteId = this.safeString(market, 'quoteAsset');
833
+ const base = this.safeCurrencyCode(baseId);
834
+ const quote = this.safeCurrencyCode(quoteId);
835
+ const active = this.safeString(market, 'status') === 'TRADING';
836
+ let spot = undefined;
837
+ let symbol = undefined;
838
+ let settle = undefined;
839
+ let settleId = undefined;
840
+ let swap = undefined;
841
+ let linear = undefined;
842
+ let inverse = undefined;
843
+ let contractSize = undefined;
844
+ const contractType = this.safeString(market, 'contractType');
845
+ const isContract = contractType !== undefined;
846
+ if (isContract) {
847
+ // currently, there is only perpetuals, not futures
848
+ spot = false;
849
+ swap = true;
850
+ settleId = this.safeString(market, 'marginAsset');
851
+ settle = this.safeCurrencyCode(settleId);
852
+ symbol = base + '/' + quote + ':' + settle;
853
+ linear = settle === quote;
854
+ inverse = settle === base;
855
+ contractSize = this.safeNumber2(market, 'contractSize', 'unit', this.parseNumber('1'));
856
+ }
857
+ else {
858
+ spot = true;
859
+ swap = false;
860
+ symbol = base + '/' + quote;
861
+ }
862
+ // filters
863
+ const filters = this.safeList(market, 'filters', []);
864
+ const filtersByType = this.indexBy(filters, 'filterType');
865
+ const filterNotional = this.safeDict2(filtersByType, 'MIN_NOTIONAL', 'NOTIONAL');
866
+ const filterPrice = this.safeDict(filtersByType, 'PRICE_FILTER');
867
+ const filterLotSize = this.safeDict(filtersByType, 'LOT_SIZE');
868
+ const filterMarketLotSize = this.safeDict(filtersByType, 'MARKET_LOT_SIZE', {});
869
+ let pricePrecision = this.safeNumber(filterPrice, 'tickSize');
870
+ if (pricePrecision === undefined) {
871
+ pricePrecision = this.parseNumber(this.parsePrecision(this.safeString(market, 'pricePrecision')));
872
+ }
873
+ const amountPrecision = (filterLotSize !== undefined) ? this.safeNumber(filterLotSize, 'stepSize') : this.parseNumber(this.parsePrecision(this.safeString(market, 'quantityPrecision')));
874
+ return this.safeMarketStructure({
875
+ 'id': id,
876
+ 'symbol': symbol,
877
+ 'base': base,
878
+ 'quote': quote,
879
+ 'settle': settle,
880
+ 'baseId': baseId,
881
+ 'quoteId': quoteId,
882
+ 'settleId': settleId,
883
+ 'type': isContract ? 'swap' : 'spot',
884
+ 'spot': spot,
885
+ 'margin': false,
886
+ 'swap': swap,
887
+ 'future': false,
888
+ 'option': false,
889
+ 'active': active,
890
+ 'contract': isContract,
891
+ 'linear': linear,
892
+ 'inverse': inverse,
893
+ 'taker': this.fees['trading']['taker'],
894
+ 'maker': this.fees['trading']['maker'],
895
+ 'contractSize': contractSize,
896
+ 'expiry': undefined,
897
+ 'expiryDatetime': undefined,
898
+ 'strike': undefined,
899
+ 'optionType': undefined,
900
+ 'precision': {
901
+ 'amount': amountPrecision,
902
+ 'price': pricePrecision,
903
+ 'base': this.parseNumber(this.parsePrecision(this.safeString(market, 'baseAssetPrecision'))),
904
+ 'quote': this.parseNumber(this.parsePrecision(this.safeString(market, 'quotePrecision'))),
905
+ },
906
+ 'limits': {
907
+ 'leverage': {
908
+ 'min': undefined,
909
+ 'max': undefined,
831
910
  },
832
- 'limits': {
833
- 'leverage': {
834
- 'min': undefined,
835
- 'max': undefined,
836
- },
837
- 'amount': {
838
- 'min': undefined,
839
- 'max': undefined,
840
- },
841
- 'price': {
842
- 'min': undefined,
843
- 'max': undefined,
844
- },
845
- 'cost': {
846
- 'min': undefined,
847
- 'max': undefined,
848
- },
911
+ 'amount': {
912
+ 'min': this.safeNumber(filterLotSize, 'minQty'),
913
+ 'max': this.safeNumber(filterLotSize, 'maxQty'),
849
914
  },
850
- 'created': this.safeInteger(market, 'onboardDate'),
851
- 'info': market,
852
- });
853
- if ('PRICE_FILTER' in filtersByType) {
854
- const filter = this.safeDict(filtersByType, 'PRICE_FILTER', {});
855
- entry['limits']['price'] = {
856
- 'min': this.safeNumber(filter, 'minPrice'),
857
- 'max': this.safeNumber(filter, 'maxPrice'),
858
- };
859
- entry['precision']['price'] = this.safeNumber(filter, 'tickSize');
860
- }
861
- if ('LOT_SIZE' in filtersByType) {
862
- const filter = this.safeDict(filtersByType, 'LOT_SIZE', {});
863
- entry['precision']['amount'] = this.safeNumber(filter, 'stepSize');
864
- entry['limits']['amount'] = {
865
- 'min': this.safeNumber(filter, 'minQty'),
866
- 'max': this.safeNumber(filter, 'maxQty'),
867
- };
868
- }
869
- if ('MARKET_LOT_SIZE' in filtersByType) {
870
- const filter = this.safeDict(filtersByType, 'MARKET_LOT_SIZE', {});
871
- entry['limits']['market'] = {
872
- 'min': this.safeNumber(filter, 'minQty'),
873
- 'max': this.safeNumber(filter, 'maxQty'),
874
- };
875
- }
876
- if (('MIN_NOTIONAL' in filtersByType) || ('NOTIONAL' in filtersByType)) {
877
- const filter = this.safeDict2(filtersByType, 'MIN_NOTIONAL', 'NOTIONAL', {});
878
- entry['limits']['cost']['min'] = this.safeNumber(filter, 'notional');
879
- }
880
- result.push(entry);
881
- }
882
- return result;
915
+ 'price': {
916
+ 'min': this.safeNumber(filterPrice, 'minPrice'),
917
+ 'max': this.safeNumber(filterPrice, 'maxPrice'),
918
+ },
919
+ 'cost': {
920
+ 'min': this.safeNumber2(filterNotional, 'notional', 'minNotional'),
921
+ 'max': undefined,
922
+ },
923
+ 'market': {
924
+ 'min': this.safeNumber(filterMarketLotSize, 'minQty'),
925
+ 'max': this.safeNumber(filterMarketLotSize, 'maxQty'),
926
+ },
927
+ },
928
+ 'created': this.safeInteger2(market, 'listingTime', 'createTime'),
929
+ 'info': market,
930
+ });
883
931
  }
884
932
  /**
885
933
  * @method
886
934
  * @name aster#fetchTime
887
935
  * @description fetches the current integer timestamp in milliseconds from the exchange server
888
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#check-server-time
936
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#get-server-time
937
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#check-server-time
889
938
  * @param {object} [params] extra parameters specific to the exchange API endpoint
890
939
  * @returns {int} the current integer timestamp in milliseconds from the exchange server
891
940
  */
892
941
  async fetchTime(params = {}) {
893
- const response = await this.fapiPublicGetV1Time(params);
942
+ let marketType = undefined;
943
+ [marketType, params] = this.handleMarketTypeAndParams('fetchTime', undefined, params);
944
+ let response = undefined;
945
+ if (marketType === 'swap') {
946
+ response = await this.fapiPublicGetV3Time(params);
947
+ }
948
+ else {
949
+ response = await this.sapiPublicGetV3Time(params);
950
+ }
894
951
  //
895
- // {
896
- // "serverTime": 1499827319559
897
- // }
952
+ // both SPOT & PERP has same format
953
+ //
954
+ // {
955
+ // "serverTime": 1499827319559
956
+ // }
898
957
  //
899
958
  return this.safeInteger(response, 'serverTime');
900
959
  }
901
960
  parseOHLCV(ohlcv, market = undefined) {
961
+ //
962
+ // spot:
902
963
  //
903
964
  // [
904
- // 1631158560000,
905
- // "208.1850",
906
- // "208.1850",
907
- // "208.1850",
908
- // "208.1850",
909
- // "11.84",
910
- // 1631158619999,
911
- // "2464.910400",
912
- // 1,
913
- // "11.84",
914
- // "2464.910400",
915
- // "0"
965
+ // 1499040000000, // Open time
966
+ // "0.01634790", // Open
967
+ // "0.80000000", // High
968
+ // "0.01575800", // Low
969
+ // "0.01577100", // Close
970
+ // "148976.11427815", // Volume
971
+ // 1499644799999, // Close time
972
+ // "2434.19055334", // Quote asset volume
973
+ // 308, // Number of trades
974
+ // "1756.87402397", // Taker buy base asset volume
975
+ // "28.46694368", // Taker buy quote asset volume
976
+ // "0" // ??
916
977
  // ]
917
978
  //
918
979
  return [
@@ -928,8 +989,10 @@ export default class aster extends Exchange {
928
989
  * @method
929
990
  * @name aster#fetchOHLCV
930
991
  * @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
931
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#k-line-data
932
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#klinecandlestick-data
992
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#k-line-data
993
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#klinecandlestick-data
994
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#index-price-klinecandlestick-data
995
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#mark-price-klinecandlestick-data
933
996
  * @param {string} symbol unified symbol of the market to fetch OHLCV data for
934
997
  * @param {string} timeframe the length of time each candle represents
935
998
  * @param {int} [since] timestamp in ms of the earliest candle to fetch
@@ -940,9 +1003,6 @@ export default class aster extends Exchange {
940
1003
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
941
1004
  */
942
1005
  async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
943
- if (symbol === undefined) {
944
- throw new ArgumentsRequired(this.id + ' fetchOHLCV() requires a symbol argument');
945
- }
946
1006
  await this.loadMarkets();
947
1007
  const market = this.market(symbol);
948
1008
  let request = {};
@@ -950,10 +1010,7 @@ export default class aster extends Exchange {
950
1010
  request['startTime'] = since;
951
1011
  }
952
1012
  if (limit !== undefined) {
953
- if (limit > 1500) {
954
- limit = 1500; // Default 500; max 1500.
955
- }
956
- request['limit'] = limit;
1013
+ request['limit'] = Math.min(limit, 1500);
957
1014
  }
958
1015
  [request, params] = this.handleUntilOption('endTime', request, params);
959
1016
  request['interval'] = this.safeString(this.timeframes, timeframe, timeframe);
@@ -964,97 +1021,116 @@ export default class aster extends Exchange {
964
1021
  let response = undefined;
965
1022
  if (isMark) {
966
1023
  request['symbol'] = market['id'];
967
- response = await this.fapiPublicGetV1MarkPriceKlines(this.extend(request, params));
1024
+ response = await this.fapiPublicGetV3MarkPriceKlines(this.extend(request, params));
968
1025
  }
969
1026
  else if (isIndex) {
970
1027
  request['pair'] = market['id'];
971
- response = await this.fapiPublicGetV1IndexPriceKlines(this.extend(request, params));
1028
+ response = await this.fapiPublicGetV3IndexPriceKlines(this.extend(request, params));
972
1029
  }
973
1030
  else {
974
1031
  request['symbol'] = market['id'];
975
1032
  if (market['linear']) {
976
- response = await this.fapiPublicGetV1Klines(this.extend(request, params));
1033
+ response = await this.fapiPublicGetV3Klines(this.extend(request, params));
977
1034
  }
978
1035
  else {
979
- response = await this.sapiPublicGetV1Klines(this.extend(request, params));
1036
+ response = await this.sapiPublicGetV3Klines(this.extend(request, params));
980
1037
  }
1038
+ //
1039
+ // both SPOT & PERP has same format
1040
+ //
1041
+ // [
1042
+ // [
1043
+ // 1499040000000, // Open time
1044
+ // "0.01634790", // Open
1045
+ // "0.80000000", // High
1046
+ // "0.01575800", // Low
1047
+ // "0.01577100", // Close
1048
+ // "148976.11427815", // Volume
1049
+ // 1499644799999, // Close time
1050
+ // "2434.19055334", // Quote asset volume
1051
+ // 308, // Number of trades
1052
+ // "1756.87402397", // Taker buy base asset volume
1053
+ // "28.46694368", // Taker buy quote asset volume,
1054
+ // "0"
1055
+ // ]
1056
+ // ]
1057
+ //
981
1058
  }
982
- //
983
- // [
984
- // [
985
- // 1631158560000,
986
- // "208.1850",
987
- // "208.1850",
988
- // "208.1850",
989
- // "208.1850",
990
- // "11.84",
991
- // 1631158619999,
992
- // "2464.910400",
993
- // 1,
994
- // "11.84",
995
- // "2464.910400",
996
- // "0"
997
- // ]
998
- // ]
999
- //
1000
1059
  return this.parseOHLCVs(response, market, timeframe, since, limit);
1001
1060
  }
1002
1061
  parseTrade(trade, market = undefined) {
1003
1062
  //
1004
1063
  // fetchTrades
1005
1064
  //
1065
+ // recent trades:
1066
+ //
1006
1067
  // {
1007
1068
  // "id": 3913206,
1008
1069
  // "price": "644.100",
1009
1070
  // "qty": "0.08",
1010
- // "quoteQty": "51.528",
1071
+ // "quoteQty": "51.528", // present in PERP
1072
+ // "baseQty": "4.95049505", // present in SPOT
1011
1073
  // "time": 1749784506633,
1012
1074
  // "isBuyerMaker": true
1013
1075
  // }
1014
1076
  //
1077
+ // aggrTrades
1078
+ //
1015
1079
  // {
1016
- // "id": 657,
1017
- // "price": "1.01000000",
1018
- // "qty": "5.00000000",
1019
- // "baseQty": "4.95049505",
1020
- // "time": 1755156533943,
1021
- // "isBuyerMaker": false
1080
+ // "a": 26129, // Aggregate tradeId
1081
+ // "p": "0.01633102", // Price
1082
+ // "q": "4.70443515", // Quantity
1083
+ // "f": 27781, // First tradeId
1084
+ // "l": 27781, // Last tradeId
1085
+ // "T": 1498793709153, // Timestamp
1086
+ // "m": true, // Was the buyer the maker?
1022
1087
  // }
1023
1088
  //
1024
- // fetchMyTrades
1089
+ // fetchMyTrades (SPOT & PERP have similar format)
1025
1090
  //
1026
- // {
1027
- // "buyer": false,
1028
- // "commission": "-0.07819010",
1029
- // "commissionAsset": "USDT",
1030
- // "id": 698759,
1031
- // "maker": false,
1032
- // "orderId": 25851813,
1033
- // "price": "7819.01",
1034
- // "qty": "0.002",
1035
- // "quoteQty": "15.63802",
1036
- // "realizedPnl": "-0.91539999",
1037
- // "side": "SELL",
1038
- // "positionSide": "SHORT",
1039
- // "symbol": "BTCUSDT",
1040
- // "time": 1569514978020
1041
- // }
1091
+ // {
1092
+ // "symbol": "ETHUSDT",
1093
+ // "id": 2583152,
1094
+ // "orderId": 418588675,
1095
+ // "side": "SELL",
1096
+ // "price": "2330.04",
1097
+ // "qty": "0.0030",
1098
+ // "quoteQty": "6.99000000",
1099
+ // "commission": "0.00279605",
1100
+ // "commissionAsset": "USDT",
1101
+ // "time": 1776409179230,
1102
+ // "counterpartyId": 5143150, // only in SPOT
1103
+ // "createUpdateId": null, // only in SPOT
1104
+ // "maker": false, // only in SPOT
1105
+ // "buyer": false, // only in SPOT
1106
+ // "realizedPnl": "0.00029999", // only in PERP
1107
+ // "marginAsset": "USDT", // only in PERP
1108
+ // "positionSide": "BOTH", // only in PERP
1109
+ // }
1042
1110
  //
1043
- const id = this.safeString(trade, 'id');
1044
- const symbol = market['symbol'];
1045
- const currencyId = this.safeString(trade, 'commissionAsset');
1111
+ const id = this.safeString2(trade, 'id', 'a');
1112
+ const marketId = this.safeString(trade, 'symbol');
1113
+ const marketType = ('positionSide' in trade) ? 'swap' : 'spot';
1114
+ market = this.safeMarket(marketId, market, undefined, marketType);
1115
+ const currencyId = this.safeString2(trade, 'commissionAsset', 'marginAsset');
1046
1116
  const currencyCode = this.safeCurrencyCode(currencyId);
1047
- const amountString = this.safeString(trade, 'qty');
1048
- const priceString = this.safeString(trade, 'price');
1117
+ const amountString = this.safeString2(trade, 'qty', 'q');
1118
+ const priceString = this.safeString2(trade, 'price', 'p');
1049
1119
  const costString = this.safeString2(trade, 'quoteQty', 'baseQty');
1050
- const timestamp = this.safeInteger(trade, 'time');
1120
+ const timestamp = this.safeInteger2(trade, 'time', 'T');
1051
1121
  let side = this.safeStringLower(trade, 'side');
1052
1122
  const isMaker = this.safeBool(trade, 'maker');
1053
1123
  let takerOrMaker = undefined;
1054
1124
  if (isMaker !== undefined) {
1055
1125
  takerOrMaker = isMaker ? 'maker' : 'taker';
1126
+ if (side === undefined) {
1127
+ const isBuyer = this.safeBool(trade, 'buyer');
1128
+ if (isBuyer !== undefined) {
1129
+ side = isBuyer ? 'buy' : 'sell';
1130
+ }
1131
+ }
1056
1132
  }
1057
- const isBuyerMaker = this.safeBool(trade, 'isBuyerMaker');
1133
+ const isBuyerMaker = this.safeBool2(trade, 'isBuyerMaker', 'm');
1058
1134
  if (isBuyerMaker !== undefined) {
1059
1135
  side = isBuyerMaker ? 'sell' : 'buy';
1060
1136
  }
@@ -1063,7 +1139,7 @@ export default class aster extends Exchange {
1063
1139
  'info': trade,
1064
1140
  'timestamp': timestamp,
1065
1141
  'datetime': this.iso8601(timestamp),
1066
- 'symbol': symbol,
1142
+ 'symbol': market['symbol'],
1067
1143
  'order': this.safeString(trade, 'orderId'),
1068
1144
  'type': undefined,
1069
1145
  'side': side,
@@ -1081,8 +1157,10 @@ export default class aster extends Exchange {
1081
1157
  * @method
1082
1158
  * @name aster#fetchTrades
1083
1159
  * @description get the list of most recent trades for a particular symbol
1084
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#recent-trades-list
1085
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#recent-trades-list
1160
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#recent-trades-list
1161
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#recent-trades-aggregated
1162
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#recent-trades-list
1163
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#compressedaggregate-trades-list
1086
1164
  * @param {string} symbol unified symbol of the market to fetch trades for
1087
1165
  * @param {int} [since] timestamp in ms of the earliest trade to fetch
1088
1166
  * @param {int} [limit] the maximum amount of trades to fetch
@@ -1090,48 +1168,68 @@ export default class aster extends Exchange {
1090
1168
  * @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
1091
1169
  */
1092
1170
  async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
1093
- if (symbol === undefined) {
1094
- throw new ArgumentsRequired(this.id + ' fetchTrades() requires a symbol argument');
1095
- }
1096
1171
  await this.loadMarkets();
1097
1172
  const market = this.market(symbol);
1098
- const request = {
1173
+ let request = {
1099
1174
  'symbol': market['id'],
1100
1175
  };
1101
1176
  if (limit !== undefined) {
1102
- if (limit > 1000) {
1103
- limit = 1000; // Default 500; max 1000.
1104
- }
1105
- request['limit'] = limit;
1177
+ request['limit'] = Math.min(limit, 1000);
1106
1178
  }
1107
1179
  let response = undefined;
1108
- if (market['swap']) {
1109
- response = await this.fapiPublicGetV1Trades(this.extend(request, params));
1180
+ const sinceDefined = since !== undefined;
1181
+ const untilDefined = ('until' in params);
1182
+ if (sinceDefined) {
1183
+ request['startTime'] = since;
1184
+ }
1185
+ if (untilDefined) {
1186
+ request = this.handleUntilOption('endTime', request, params);
1187
+ }
1188
+ // use historical endpoint for targeted requests
1189
+ if ('startTime' in request) {
1190
+ if (market['swap']) {
1191
+ response = await this.fapiPublicGetV3AggTrades(this.extend(request, params));
1192
+ }
1193
+ else {
1194
+ response = await this.sapiPublicGetV3AggTrades(this.extend(request, params));
1195
+ }
1110
1196
  //
1111
- // [
1112
- // {
1113
- // "id": 3913206,
1114
- // "price": "644.100",
1115
- // "qty": "0.08",
1116
- // "quoteQty": "51.528",
1117
- // "time": 1749784506633,
1118
- // "isBuyerMaker": true
1119
- // }
1120
- // ]
1197
+ // both FAPI and SAPI have same response format
1198
+ //
1199
+ // [
1200
+ // {
1201
+ // "a": 26129, // Aggregate tradeId
1202
+ // "p": "0.01633102", // Price
1203
+ // "q": "4.70443515", // Quantity
1204
+ // "f": 27781, // First tradeId
1205
+ // "l": 27781, // Last tradeId
1206
+ // "T": 1498793709153, // Timestamp
1207
+ // "m": true, // Was the buyer the maker?
1208
+ // }
1209
+ // ]
1121
1210
  //
1122
1211
  }
1123
1212
  else {
1124
- response = await this.sapiPublicGetV1Trades(this.extend(request, params));
1125
- // [
1126
- // {
1127
- // "id": 657,
1128
- // "price": "1.01000000",
1129
- // "qty": "5.00000000",
1130
- // "baseQty": "4.95049505",
1131
- // "time": 1755156533943,
1132
- // "isBuyerMaker": false
1133
- // }
1134
- // ]
1213
+ if (market['swap']) {
1214
+ response = await this.fapiPublicGetV3Trades(this.extend(request, params));
1215
+ }
1216
+ else {
1217
+ response = await this.sapiPublicGetV3Trades(this.extend(request, params));
1218
+ }
1219
+ //
1220
+ // SAPI & FAPI have only one field difference
1221
+ //
1222
+ // [
1223
+ // {
1224
+ // "id": "73620768",
1225
+ // "price": "2324.07",
1226
+ // "qty": "0.430",
1227
+ // "quoteQty": "999.35", // only in PERP
1228
+ // "baseQty": "4.95049505", // only in SPOT
1229
+ // "time": "1776407252900",
1230
+ // "isBuyerMaker": false
1231
+ // }, ...
1232
+ //
1135
1233
  }
1136
1234
  return this.parseTrades(response, market, since, limit);
1137
1235
  }
@@ -1139,8 +1237,8 @@ export default class aster extends Exchange {
1139
1237
  * @method
1140
1238
  * @name aster#fetchMyTrades
1141
1239
  * @description fetch all trades made by the user
1142
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#account-trade-history-user_data
1143
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#account-trade-list-user_data
1240
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#account-trade-history-user_data
1241
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#account-trade-list-user_data
1144
1242
  * @param {string} [symbol] unified market symbol
1145
1243
  * @param {int} [since] the earliest time in ms to fetch trades for
1146
1244
  * @param {int} [limit] the maximum number of trades structures to retrieve
@@ -1149,50 +1247,51 @@ export default class aster extends Exchange {
1149
1247
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
1150
1248
  */
1151
1249
  async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1152
- if (symbol === undefined) {
1153
- throw new ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol argument');
1250
+ await this.loadMarketsAndSignIn();
1251
+ let request = {};
1252
+ let market = undefined;
1253
+ if (symbol !== undefined) {
1254
+ market = this.market(symbol);
1255
+ request['symbol'] = market['id'];
1154
1256
  }
1155
- await this.loadMarkets();
1156
- const market = this.market(symbol);
1157
- let request = {
1158
- 'symbol': market['id'],
1159
- };
1257
+ let marketType = undefined;
1258
+ [marketType, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
1160
1259
  if (since !== undefined) {
1161
1260
  request['startTime'] = since;
1162
1261
  }
1163
1262
  if (limit !== undefined) {
1164
- if (limit > 1000) {
1165
- limit = 1000; // Default 500; max 1000.
1166
- }
1167
- request['limit'] = limit;
1263
+ request['limit'] = Math.min(limit, 1000);
1168
1264
  }
1169
1265
  [request, params] = this.handleUntilOption('endTime', request, params);
1170
1266
  let response = undefined;
1171
- if (market['swap']) {
1172
- response = await this.fapiPrivateGetV1UserTrades(this.extend(request, params));
1267
+ if (marketType === 'swap') {
1268
+ response = await this.fapiPrivateGetV3UserTrades(this.extend(request, params));
1173
1269
  }
1174
1270
  else {
1175
- response = await this.sapiPrivateGetV1UserTrades(this.extend(request, params));
1271
+ response = await this.sapiPrivateGetV3UserTrades(this.extend(request, params));
1176
1272
  }
1177
1273
  //
1178
- // [
1179
- // {
1180
- // "buyer": false,
1181
- // "commission": "-0.07819010",
1182
- // "commissionAsset": "USDT",
1183
- // "id": 698759,
1184
- // "maker": false,
1185
- // "orderId": 25851813,
1186
- // "price": "7819.01",
1187
- // "qty": "0.002",
1188
- // "quoteQty": "15.63802",
1189
- // "realizedPnl": "-0.91539999",
1190
- // "side": "SELL",
1191
- // "positionSide": "SHORT",
1192
- // "symbol": "BTCUSDT",
1193
- // "time": 1569514978020
1194
- // }
1195
- // ]
1274
+ // SPOT & PERP have similar format
1275
+ //
1276
+ // {
1277
+ // "symbol": "ETHUSDT",
1278
+ // "id": 2583152,
1279
+ // "orderId": 418588675,
1280
+ // "side": "SELL",
1281
+ // "price": "2330.04",
1282
+ // "qty": "0.0030",
1283
+ // "quoteQty": "6.99000000",
1284
+ // "commission": "0.00279605",
1285
+ // "commissionAsset": "USDT",
1286
+ // "time": 1776409179230,
1287
+ // "counterpartyId": 5143150, // only in PERP
1288
+ // "createUpdateId": null, // only in PERP
1289
+ // "maker": false, // only in PERP
1290
+ // "buyer": false, // only in PERP
1291
+ // "realizedPnl": "0.00029999", // only in SPOT
1292
+ // "marginAsset": "USDT", // only in SPOT
1293
+ // "positionSide": "BOTH", // only in SPOT
1294
+ // }
1196
1295
  //
1197
1296
  return this.parseTrades(response, market, since, limit, params);
1198
1297
  }
@@ -1200,37 +1299,32 @@ export default class aster extends Exchange {
1200
1299
  * @method
1201
1300
  * @name aster#fetchOrderBook
1202
1301
  * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
1203
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#depth-information
1204
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#order-book
1302
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#depth-information
1303
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#order-book
1205
1304
  * @param {string} symbol unified symbol of the market to fetch the order book for
1206
1305
  * @param {int} [limit] the maximum amount of order book entries to return
1207
1306
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1208
1307
  * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
1209
1308
  */
1210
1309
  async fetchOrderBook(symbol, limit = undefined, params = {}) {
1211
- if (symbol === undefined) {
1212
- throw new ArgumentsRequired(this.id + ' fetchOrderBook() requires a symbol argument');
1213
- }
1214
1310
  await this.loadMarkets();
1215
1311
  const market = this.market(symbol);
1216
1312
  const request = {
1217
1313
  'symbol': market['id'],
1218
1314
  };
1315
+ let response = undefined;
1219
1316
  if (limit !== undefined) {
1220
- // limit: [5, 10, 20, 50, 100, 500, 1000]. Default: 500
1221
- if (limit > 1000) {
1222
- limit = 1000; // Default 500; max 1000.
1223
- }
1224
- request['limit'] = limit;
1317
+ request['limit'] = this.findNearestCeiling([5, 10, 20, 50, 100, 500, 1000], limit);
1225
1318
  }
1226
- let response = undefined;
1227
1319
  if (market['swap']) {
1228
- response = await this.fapiPublicGetV1Depth(this.extend(request, params));
1320
+ response = await this.fapiPublicGetV3Depth(this.extend(request, params));
1229
1321
  }
1230
1322
  else {
1231
- response = await this.sapiPublicGetV1Depth(this.extend(request, params));
1323
+ response = await this.sapiPublicGetV3Depth(this.extend(request, params));
1232
1324
  }
1233
1325
  //
1326
+ // both SPOT & PERP has same format
1327
+ //
1234
1328
  // {
1235
1329
  // "lastUpdateId": 1027024,
1236
1330
  // "E": 1589436922972, // Message output time
@@ -1252,118 +1346,50 @@ export default class aster extends Exchange {
1252
1346
  const timestamp = this.safeInteger(response, 'T');
1253
1347
  return this.parseOrderBook(response, symbol, timestamp, 'bids', 'asks');
1254
1348
  }
1255
- /**
1256
- * @method
1257
- * @name aster#fetchFundingRateHistory
1258
- * @description fetches historical funding rate prices
1259
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-funding-rate-history
1260
- * @param {string} symbol unified symbol of the market to fetch the funding rate history for
1261
- * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
1262
- * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
1263
- * @param {object} [params] extra parameters specific to the exchange API endpoint
1264
- * @param {int} [params.until] timestamp in ms of the latest funding rate
1265
- * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
1266
- */
1267
- async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1268
- await this.loadMarkets();
1269
- let request = {};
1270
- if (symbol !== undefined) {
1271
- const market = this.market(symbol);
1272
- request['symbol'] = market['id'];
1273
- }
1274
- if (since !== undefined) {
1275
- request['startTime'] = since;
1276
- }
1277
- if (limit !== undefined) {
1278
- if (limit > 1000) {
1279
- limit = 1000; // Default 100; max 1000
1280
- }
1281
- request['limit'] = limit;
1282
- }
1283
- [request, params] = this.handleUntilOption('endTime', request, params);
1284
- const response = await this.fapiPublicGetV1FundingRate(this.extend(request, params));
1349
+ parseTicker(ticker, market = undefined) {
1285
1350
  //
1286
- // [
1287
- // {
1288
- // "symbol": "BTCUSDT",
1289
- // "fundingTime": 1747209600000,
1290
- // "fundingRate": "0.00010000"
1291
- // }
1292
- // ]
1351
+ // fetchTicker & fetchTickers: both SPOT & PERP has similar format
1293
1352
  //
1294
- const rates = [];
1295
- for (let i = 0; i < response.length; i++) {
1296
- const entry = response[i];
1297
- const timestamp = this.safeInteger(entry, 'fundingTime');
1298
- rates.push({
1299
- 'info': entry,
1300
- 'symbol': this.safeSymbol(this.safeString(entry, 'symbol'), undefined, undefined, 'swap'),
1301
- 'fundingRate': this.safeNumber(entry, 'fundingRate'),
1302
- 'timestamp': timestamp,
1303
- 'datetime': this.iso8601(timestamp),
1304
- });
1305
- }
1306
- const sorted = this.sortBy(rates, 'timestamp');
1307
- return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
1308
- }
1309
- parseTicker(ticker, market = undefined) {
1353
+ // {
1354
+ // "symbol": "ETHUSDT",
1355
+ // "priceChange": "6.54",
1356
+ // "priceChangePercent": "0.279",
1357
+ // "weightedAvgPrice": "2330.70",
1358
+ // "lastPrice": "2350.00",
1359
+ // "lastQty": "4.437",
1360
+ // "openPrice": "2343.46",
1361
+ // "highPrice": "2363.20",
1362
+ // "lowPrice": "2283.86",
1363
+ // "volume": "267154.248",
1364
+ // "quoteVolume": "622657018.70",
1365
+ // "openTime": "1776329400000",
1366
+ // "closeTime": "1776415832593",
1367
+ // "firstId": "73520536",
1368
+ // "lastId": "73630176",
1369
+ // "count": "109640",
1370
+ // "baseAsset": "BTC", // only in SPOT
1371
+ // "quoteAsset": "USDT", // only in SPOT
1372
+ // "bidPrice": "71125.98", // only in SPOT
1373
+ // "bidQty": "0.00737", // only in SPOT
1374
+ // "askPrice": "71152.10", // only in SPOT
1375
+ // "askQty": "0.32399" // only in SPOT
1376
+ // }
1310
1377
  //
1311
- // spot
1312
- // {
1313
- // "symbol": "BTCUSDT",
1314
- // "priceChange": "-2274.38",
1315
- // "priceChangePercent": "-2.049",
1316
- // "weightedAvgPrice": "109524.37084136",
1317
- // "lastPrice": "108738.78",
1318
- // "lastQty": "0.00034",
1319
- // "openPrice": "111013.16",
1320
- // "highPrice": "111975.81",
1321
- // "lowPrice": "107459.25",
1322
- // "volume": "28.67876",
1323
- // "quoteVolume": "3141023.14551030",
1324
- // "openTime": "1760578800000",
1325
- // "closeTime": "1760665024749",
1326
- // "firstId": "37447",
1327
- // "lastId": "39698",
1328
- // "count": "2252",
1329
- // "baseAsset": "BTC",
1330
- // "quoteAsset": "USDT",
1331
- // "bidPrice": "108705.11",
1332
- // "bidQty": "0.03351",
1333
- // "askPrice": "108725.99",
1334
- // "askQty": "0.08724"
1335
- // }
1336
- // swap
1337
- // {
1338
- // "symbol": "BTCUSDT",
1339
- // "priceChange": "1845.7",
1340
- // "priceChangePercent": "1.755",
1341
- // "weightedAvgPrice": "105515.5",
1342
- // "lastPrice": "107037.7",
1343
- // "lastQty": "0.004",
1344
- // "openPrice": "105192.0",
1345
- // "highPrice": "107223.5",
1346
- // "lowPrice": "104431.6",
1347
- // "volume": "8753.286",
1348
- // "quoteVolume": "923607368.61",
1349
- // "openTime": 1749976620000,
1350
- // "closeTime": 1750063053754,
1351
- // "firstId": 24195078,
1352
- // "lastId": 24375783,
1353
- // "count": 180706
1354
- // }
1378
+ //
1379
+ // fetchBidsAsks: SPOT & PERP have only one field difference
1380
+ //
1381
+ // [
1382
+ // {
1383
+ // "symbol": "BMTUSDT",
1384
+ // "bidPrice": "0.004000",
1385
+ // "bidQty": "1250.0",
1386
+ // "askPrice": "0.000000",
1387
+ // "askQty": "0.0",
1388
+ // "time": "1776411276072",
1389
+ // "lastUpdateId": "453174307613" // only in PERP
1390
+ // }, ...
1355
1391
  //
1356
1392
  const timestamp = this.safeInteger(ticker, 'closeTime');
1357
- let marketType = undefined;
1358
- if ('bidQty' in ticker) {
1359
- marketType = 'spot';
1360
- }
1361
- else {
1362
- marketType = 'contract';
1363
- }
1364
- const marketId = this.safeString(ticker, 'symbol');
1365
- market = this.safeMarket(marketId, market, undefined, marketType);
1366
- const symbol = market['symbol'];
1367
1393
  const last = this.safeString(ticker, 'lastPrice');
1368
1394
  const open = this.safeString(ticker, 'openPrice');
1369
1395
  let percentage = this.safeString(ticker, 'priceChangePercent');
@@ -1372,8 +1398,18 @@ export default class aster extends Exchange {
1372
1398
  const baseVolume = this.safeString(ticker, 'volume');
1373
1399
  const high = this.safeString(ticker, 'highPrice');
1374
1400
  const low = this.safeString(ticker, 'lowPrice');
1401
+ const isTickerResponse = ('priceChange' in ticker);
1402
+ let marketType = undefined;
1403
+ if (isTickerResponse) {
1404
+ marketType = ('baseAsset' in ticker) ? 'spot' : 'swap';
1405
+ }
1406
+ else {
1407
+ marketType = ('lastUpdateId' in ticker) ? 'swap' : 'spot';
1408
+ }
1409
+ const marketId = this.safeString(ticker, 'symbol');
1410
+ market = this.safeMarket(marketId, market, undefined, marketType);
1375
1411
  return this.safeTicker({
1376
- 'symbol': symbol,
1412
+ 'symbol': market['symbol'],
1377
1413
  'timestamp': timestamp,
1378
1414
  'datetime': this.iso8601(timestamp),
1379
1415
  'high': high,
@@ -1401,16 +1437,13 @@ export default class aster extends Exchange {
1401
1437
  * @method
1402
1438
  * @name aster#fetchTicker
1403
1439
  * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1404
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#24h-price-change
1405
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#24hr-ticker-price-change-statistics
1440
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#24h-price-change
1441
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#24hr-ticker-price-change-statistics
1406
1442
  * @param {string} symbol unified symbol of the market to fetch the ticker for
1407
1443
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1408
1444
  * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
1409
1445
  */
1410
1446
  async fetchTicker(symbol, params = {}) {
1411
- if (symbol === undefined) {
1412
- throw new ArgumentsRequired(this.id + ' fetchTicker() requires a symbol argument');
1413
- }
1414
1447
  await this.loadMarkets();
1415
1448
  const market = this.market(symbol);
1416
1449
  const request = {
@@ -1418,63 +1451,47 @@ export default class aster extends Exchange {
1418
1451
  };
1419
1452
  let response = undefined;
1420
1453
  if (market['swap']) {
1421
- response = await this.fapiPublicGetV1Ticker24hr(this.extend(request, params));
1422
- //
1423
- // {
1424
- // "symbol": "BTCUSDT",
1425
- // "priceChange": "1845.7",
1426
- // "priceChangePercent": "1.755",
1427
- // "weightedAvgPrice": "105515.5",
1428
- // "lastPrice": "107037.7",
1429
- // "lastQty": "0.004",
1430
- // "openPrice": "105192.0",
1431
- // "highPrice": "107223.5",
1432
- // "lowPrice": "104431.6",
1433
- // "volume": "8753.286",
1434
- // "quoteVolume": "923607368.61",
1435
- // "openTime": 1749976620000,
1436
- // "closeTime": 1750063053754,
1437
- // "firstId": 24195078,
1438
- // "lastId": 24375783,
1439
- // "count": 180706
1440
- // }
1441
- //
1454
+ response = await this.fapiPublicGetV3Ticker24hr(this.extend(request, params));
1442
1455
  }
1443
1456
  else {
1444
- response = await this.sapiPublicGetV1Ticker24hr(this.extend(request, params));
1445
- // {
1446
- // "symbol": "BTCUSDT",
1447
- // "priceChange": "-2274.38",
1448
- // "priceChangePercent": "-2.049",
1449
- // "weightedAvgPrice": "109524.37084136",
1450
- // "lastPrice": "108738.78",
1451
- // "lastQty": "0.00034",
1452
- // "openPrice": "111013.16",
1453
- // "highPrice": "111975.81",
1454
- // "lowPrice": "107459.25",
1455
- // "volume": "28.67876",
1456
- // "quoteVolume": "3141023.14551030",
1457
- // "openTime": "1760578800000",
1458
- // "closeTime": "1760665024749",
1459
- // "firstId": "37447",
1460
- // "lastId": "39698",
1461
- // "count": "2252",
1462
- // "baseAsset": "BTC",
1463
- // "quoteAsset": "USDT",
1464
- // "bidPrice": "108705.11",
1465
- // "bidQty": "0.03351",
1466
- // "askPrice": "108725.99",
1467
- // "askQty": "0.08724"
1468
- // }
1457
+ response = await this.sapiPublicGetV3Ticker24hr(this.extend(request, params));
1469
1458
  }
1459
+ //
1460
+ // both SPOT & PERP has same format
1461
+ //
1462
+ // {
1463
+ // "symbol": "ETHUSDT",
1464
+ // "priceChange": "6.54",
1465
+ // "priceChangePercent": "0.279",
1466
+ // "weightedAvgPrice": "2330.70",
1467
+ // "lastPrice": "2350.00",
1468
+ // "lastQty": "4.437",
1469
+ // "openPrice": "2343.46",
1470
+ // "highPrice": "2363.20",
1471
+ // "lowPrice": "2283.86",
1472
+ // "volume": "267154.248",
1473
+ // "quoteVolume": "622657018.70",
1474
+ // "openTime": "1776329400000",
1475
+ // "closeTime": "1776415832593",
1476
+ // "firstId": "73520536",
1477
+ // "lastId": "73630176",
1478
+ // "count": "109640",
1479
+ // "baseAsset": "BTC", // only in SPOT
1480
+ // "quoteAsset": "USDT", // only in SPOT
1481
+ // "bidPrice": "71125.98", // only in SPOT
1482
+ // "bidQty": "0.00737", // only in SPOT
1483
+ // "askPrice": "71152.10", // only in SPOT
1484
+ // "askQty": "0.32399" // only in SPOT
1485
+ // }
1486
+ //
1470
1487
  return this.parseTicker(response, market);
1471
1488
  }
1472
1489
  /**
1473
1490
  * @method
1474
1491
  * @name aster#fetchTickers
1475
1492
  * @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1476
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#24h-price-change
1477
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#24hr-ticker-price-change-statistics
1493
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#24h-price-change
1494
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#24hr-ticker-price-change-statistics
1478
1495
  * @param {string[]} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1479
1496
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1480
1497
  * @param {string} [params.subType] "linear" or "inverse"
@@ -1485,19 +1502,14 @@ export default class aster extends Exchange {
1485
1502
  await this.loadMarkets();
1486
1503
  symbols = this.marketSymbols(symbols, undefined, true, true, true);
1487
1504
  const market = this.getMarketFromSymbols(symbols);
1488
- let type = undefined;
1489
- [type, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
1490
- let subType = undefined;
1491
- [subType, params] = this.handleSubTypeAndParams('fetchTickers', market, params);
1505
+ let marketType = undefined;
1506
+ [marketType, params] = this.handleMarketTypeAndParams('fetchTickers', market, params);
1492
1507
  let response = undefined;
1493
- if (this.isLinear(type, subType)) {
1494
- response = await this.fapiPublicGetV1Ticker24hr(params);
1495
- }
1496
- else if (type === 'spot') {
1497
- response = await this.sapiPublicGetV1Ticker24hr(params);
1508
+ if (marketType === 'swap') {
1509
+ response = await this.fapiPublicGetV3Ticker24hr(params);
1498
1510
  }
1499
- else {
1500
- throw new NotSupported(this.id + ' fetchTickers() does not support ' + type + ' markets yet');
1511
+ else if (marketType === 'spot') {
1512
+ response = await this.sapiPublicGetV3Ticker24hr(params);
1501
1513
  }
1502
1514
  //
1503
1515
  // [
@@ -1517,13 +1529,127 @@ export default class aster extends Exchange {
1517
1529
  // "closeTime": 1750063053754,
1518
1530
  // "firstId": 24195078,
1519
1531
  // "lastId": 24375783,
1520
- // "count": 180706
1532
+ // "count": 180706,
1533
+ // "baseAsset": "BTC", // only in SPOT
1534
+ // "quoteAsset": "USDT", // only in SPOT
1535
+ // "bidPrice": "71125.98", // only in SPOT
1536
+ // "bidQty": "0.00737", // only in SPOT
1537
+ // "askPrice": "71152.10", // only in SPOT
1538
+ // "askQty": "0.32399" // only in SPOT
1521
1539
  // }
1522
1540
  // ]
1523
1541
  //
1524
1542
  return this.parseTickers(response, symbols);
1525
1543
  }
1544
+ /**
1545
+ * @method
1546
+ * @name aster#fetchLastPrices
1547
+ * @description fetches the last price for multiple markets
1548
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#latest-price
1549
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#symbol-price-ticker
1550
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the last prices
1551
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1552
+ * @param {string} [params.subType] "linear" or "inverse"
1553
+ * @returns {object} a dictionary of lastprices structures
1554
+ */
1555
+ async fetchLastPrices(symbols = undefined, params = {}) {
1556
+ await this.loadMarkets();
1557
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
1558
+ const market = this.getMarketFromSymbols(symbols);
1559
+ let marketType = undefined;
1560
+ [marketType, params] = this.handleMarketTypeAndParams('fetchLastPrices', market, params);
1561
+ let response = undefined;
1562
+ if (marketType === 'swap') {
1563
+ response = await this.fapiPublicGetV3TickerPrice(params);
1564
+ }
1565
+ else if (marketType === 'spot') {
1566
+ response = await this.sapiPublicGetV3TickerPrice(params);
1567
+ }
1568
+ //
1569
+ // both SPOT & SWAP has same format
1570
+ //
1571
+ // [
1572
+ // {
1573
+ // "symbol": "LTCBTC",
1574
+ // "price": "4.00000200"
1575
+ // "time": "1649666690902"
1576
+ // },
1577
+ // ...
1578
+ // ]
1579
+ //
1580
+ const results = [];
1581
+ for (let i = 0; i < response.length; i++) {
1582
+ const marketId = this.safeString(response[i], 'symbol');
1583
+ const safeMarket = this.safeMarket(marketId, undefined, undefined, marketType);
1584
+ const priceData = this.extend(this.parseLastPrice(response[i], safeMarket), params);
1585
+ results.push(priceData);
1586
+ }
1587
+ symbols = this.marketSymbols(symbols);
1588
+ return this.filterByArray(results, 'symbol', symbols);
1589
+ }
1590
+ parseLastPrice(entry, market = undefined) {
1591
+ //
1592
+ // spot & swap
1593
+ //
1594
+ // {
1595
+ // "symbol": "LTCBTC",
1596
+ // "price": "4.00000200"
1597
+ // "time": "1649666690902"
1598
+ // }
1599
+ //
1600
+ const timestamp = this.safeInteger(entry, 'time');
1601
+ return {
1602
+ 'symbol': market['symbol'],
1603
+ 'timestamp': timestamp,
1604
+ 'datetime': this.iso8601(timestamp),
1605
+ 'price': this.safeNumberOmitZero(entry, 'price'),
1606
+ 'side': undefined,
1607
+ 'info': entry,
1608
+ };
1609
+ }
1610
+ /**
1611
+ * @method
1612
+ * @name aster#fetchBidsAsks
1613
+ * @description fetches the bid and ask price and volume for multiple markets
1614
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#current-best-order
1615
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#symbol-order-book-ticker
1616
+ * @param {string[]|undefined} symbols unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
1617
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1618
+ * @param {string} [params.subType] "linear" or "inverse"
1619
+ * @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/?id=ticker-structure}
1620
+ */
1621
+ async fetchBidsAsks(symbols = undefined, params = {}) {
1622
+ await this.loadMarkets();
1623
+ symbols = this.marketSymbols(symbols, undefined, true, true, true);
1624
+ const market = this.getMarketFromSymbols(symbols);
1625
+ let marketType = undefined;
1626
+ [marketType, params] = this.handleMarketTypeAndParams('fetchBidsAsks', market, params);
1627
+ let response = undefined;
1628
+ if (marketType === 'swap') {
1629
+ response = await this.fapiPublicGetV3TickerBookTicker(params);
1630
+ }
1631
+ else if (marketType === 'spot') {
1632
+ response = await this.sapiPublicGetV3TickerBookTicker(params);
1633
+ }
1634
+ //
1635
+ // SPOT & PERP have only one field difference
1636
+ //
1637
+ // [
1638
+ // {
1639
+ // "symbol": "BMTUSDT",
1640
+ // "bidPrice": "0.004000",
1641
+ // "bidQty": "1250.0",
1642
+ // "askPrice": "0.000000",
1643
+ // "askQty": "0.0",
1644
+ // "time": "1776411276072",
1645
+ // "lastUpdateId": "453174307613" // only in PERP
1646
+ // }, ...
1647
+ //
1648
+ return this.parseTickers(response, symbols);
1649
+ }
1526
1650
  parseFundingRate(contract, market = undefined) {
1651
+ //
1652
+ // fundingRate
1527
1653
  //
1528
1654
  // {
1529
1655
  // "symbol": "BTCUSDT",
@@ -1535,6 +1661,9 @@ export default class aster extends Exchange {
1535
1661
  // "nextFundingTime": 1750147200000,
1536
1662
  // "time": 1750146970000
1537
1663
  // }
1664
+ //
1665
+ // funding interval
1666
+ //
1538
1667
  // {
1539
1668
  // "symbol": "INJUSDT",
1540
1669
  // "interestRate": "0.00010000",
@@ -1577,7 +1706,7 @@ export default class aster extends Exchange {
1577
1706
  * @method
1578
1707
  * @name aster#fetchFundingRate
1579
1708
  * @description fetch the current funding rate
1580
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#mark-price
1709
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#symbol-price-ticker
1581
1710
  * @param {string} symbol unified market symbol
1582
1711
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1583
1712
  * @returns {object} a [funding rate structure]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
@@ -1591,7 +1720,7 @@ export default class aster extends Exchange {
1591
1720
  const request = {
1592
1721
  'symbol': market['id'],
1593
1722
  };
1594
- const response = await this.fapiPublicGetV1PremiumIndex(this.extend(request, params));
1723
+ const response = await this.fapiPublicGetV3PremiumIndex(this.extend(request, params));
1595
1724
  //
1596
1725
  // {
1597
1726
  // "symbol": "BTCUSDT",
@@ -1610,7 +1739,7 @@ export default class aster extends Exchange {
1610
1739
  * @method
1611
1740
  * @name aster#fetchFundingRates
1612
1741
  * @description fetch the current funding rate for multiple symbols
1613
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#24hr-ticker-price-change-statistics
1742
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#symbol-price-ticker
1614
1743
  * @param {string[]} [symbols] list of unified market symbols
1615
1744
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1616
1745
  * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
@@ -1618,7 +1747,7 @@ export default class aster extends Exchange {
1618
1747
  async fetchFundingRates(symbols = undefined, params = {}) {
1619
1748
  await this.loadMarkets();
1620
1749
  symbols = this.marketSymbols(symbols);
1621
- const response = await this.fapiPublicGetV1PremiumIndex(this.extend(params));
1750
+ const response = await this.fapiPublicGetV3PremiumIndex(this.extend(params));
1622
1751
  //
1623
1752
  // [
1624
1753
  // {
@@ -1639,7 +1768,7 @@ export default class aster extends Exchange {
1639
1768
  * @method
1640
1769
  * @name aster#fetchFundingIntervals
1641
1770
  * @description fetch the funding rate interval for multiple markets
1642
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-funding-rate-config
1771
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#get-funding-rate-config
1643
1772
  * @param {string[]} [symbols] list of unified market symbols
1644
1773
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1645
1774
  * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-structure}
@@ -1649,7 +1778,7 @@ export default class aster extends Exchange {
1649
1778
  if (symbols !== undefined) {
1650
1779
  symbols = this.marketSymbols(symbols);
1651
1780
  }
1652
- const response = await this.fapiPublicGetV1FundingInfo(params);
1781
+ const response = await this.fapiPublicGetV3FundingInfo(params);
1653
1782
  //
1654
1783
  // [
1655
1784
  // {
@@ -1664,64 +1793,98 @@ export default class aster extends Exchange {
1664
1793
  //
1665
1794
  return this.parseFundingRates(response, symbols);
1666
1795
  }
1667
- parseBalance(response) {
1668
- const result = { 'info': response };
1669
- for (let i = 0; i < response.length; i++) {
1670
- const balance = response[i];
1671
- const currencyId = this.safeString(balance, 'asset');
1672
- const code = this.safeCurrencyCode(currencyId);
1673
- const account = this.account();
1674
- account['free'] = this.safeString2(balance, 'free', 'maxWithdrawAmount');
1675
- account['used'] = this.safeString(balance, 'locked');
1676
- account['total'] = this.safeString(balance, 'walletBalance');
1677
- result[code] = account;
1796
+ /**
1797
+ * @method
1798
+ * @name aster#fetchFundingRateHistory
1799
+ * @description fetches historical funding rate prices
1800
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/market-data/#get-funding-rate-history
1801
+ * @param {string} symbol unified symbol of the market to fetch the funding rate history for
1802
+ * @param {int} [since] timestamp in ms of the earliest funding rate to fetch
1803
+ * @param {int} [limit] the maximum amount of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure} to fetch
1804
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1805
+ * @param {int} [params.until] timestamp in ms of the latest funding rate
1806
+ * @returns {object[]} a list of [funding rate structures]{@link https://docs.ccxt.com/#/?id=funding-rate-history-structure}
1807
+ */
1808
+ async fetchFundingRateHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
1809
+ await this.loadMarkets();
1810
+ let request = {};
1811
+ let market = undefined;
1812
+ if (symbol !== undefined) {
1813
+ market = this.market(symbol);
1814
+ request['symbol'] = market['id'];
1678
1815
  }
1679
- return this.safeBalance(result);
1816
+ if (since !== undefined) {
1817
+ request['startTime'] = since;
1818
+ }
1819
+ if (limit !== undefined) {
1820
+ request['limit'] = Math.min(limit, 1000);
1821
+ }
1822
+ [request, params] = this.handleUntilOption('endTime', request, params);
1823
+ const response = await this.fapiPublicGetV3FundingRate(this.extend(request, params));
1824
+ //
1825
+ // [
1826
+ // {
1827
+ // "symbol": "BTCUSDT",
1828
+ // "fundingTime": 1747209600000,
1829
+ // "fundingRate": "0.00010000"
1830
+ // }
1831
+ // ]
1832
+ //
1833
+ return this.parseFundingRateHistories(response, market);
1834
+ }
1835
+ parseFundingRateHistory(contract, market = undefined) {
1836
+ //
1837
+ // {
1838
+ // "symbol": "BTCUSDT",
1839
+ // "fundingRate": "0.00063521",
1840
+ // "fundingTime": "1621267200000",
1841
+ // }
1842
+ //
1843
+ const timestamp = this.safeInteger(contract, 'fundingTime');
1844
+ return {
1845
+ 'info': contract,
1846
+ 'symbol': this.safeSymbol(this.safeString(contract, 'symbol'), undefined, undefined, 'swap'),
1847
+ 'fundingRate': this.safeNumber(contract, 'fundingRate'),
1848
+ 'timestamp': timestamp,
1849
+ 'datetime': this.iso8601(timestamp),
1850
+ };
1680
1851
  }
1681
1852
  /**
1682
1853
  * @method
1683
1854
  * @name aster#fetchBalance
1684
1855
  * @description query for balance and get the amount of funds available for trading or funds locked in orders
1685
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#account-information-v4-user_data
1686
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#account-information-user_data
1856
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#account-information-user_data
1857
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#futures-account-balance-v3-user_data
1687
1858
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1688
1859
  * @param {string} [params.subType] "linear" or "inverse"
1689
1860
  * @param {string} [params.type] 'spot', 'option', use params["subType"] for swap and future markets
1690
1861
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1691
1862
  */
1692
1863
  async fetchBalance(params = {}) {
1693
- let type = undefined;
1694
- [type, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
1695
- let subType = undefined;
1696
- [subType, params] = this.handleSubTypeAndParams('fetchBalance', undefined, params);
1864
+ await this.loadMarketsAndSignIn();
1865
+ let marketType = undefined;
1866
+ [marketType, params] = this.handleMarketTypeAndParams('fetchBalance', undefined, params);
1697
1867
  let response = undefined;
1698
1868
  let data = undefined;
1699
- if (this.isLinear(type, subType)) {
1700
- response = await this.fapiPrivateGetV4Account(params);
1701
- data = this.safeList(response, 'assets', []);
1869
+ if (marketType === 'swap') {
1870
+ data = await this.fapiPrivateGetV3Balance(params);
1702
1871
  //
1703
- // [
1704
- // {
1705
- // "asset": "USDT", // asset name
1706
- // "walletBalance": "23.72469206", // wallet balance
1707
- // "unrealizedProfit": "0.00000000", // unrealized profit
1708
- // "marginBalance": "23.72469206", // margin balance
1709
- // "maintMargin": "0.00000000", // maintenance margin required
1710
- // "initialMargin": "0.00000000", // total initial margin required with current mark price
1711
- // "positionInitialMargin": "0.00000000", //initial margin required for positions with current mark price
1712
- // "openOrderInitialMargin": "0.00000000", // initial margin required for open orders with current mark price
1713
- // "crossWalletBalance": "23.72469206", // crossed wallet balance
1714
- // "crossUnPnl": "0.00000000", // unrealized profit of crossed positions
1715
- // "availableBalance": "23.72469206", // available balance
1716
- // "maxWithdrawAmount": "23.72469206", // maximum amount for transfer out
1717
- // "marginAvailable": true, // whether the asset can be used as margin in Multi-Assets mode
1718
- // "updateTime": 1625474304765 // last update time
1719
- // }
1720
- // ]
1872
+ // [
1873
+ // {
1874
+ // "accountAlias": "FzXquXsRFzXqAufW",
1875
+ // "asset": "CDL",
1876
+ // "balance": "0.00000000",
1877
+ // "crossWalletBalance": "0.00000000",
1878
+ // "crossUnPnl": "0.00000000",
1879
+ // "availableBalance": "878.90500233",
1880
+ // "maxWithdrawAmount": "0.00000000",
1881
+ // "marginAvailable": true,
1882
+ // "updateTime": "0"
1883
+ // }, ...
1721
1884
  //
1722
1885
  }
1723
- else if (type === 'spot') {
1724
- response = await this.sapiPrivateGetV1Account(params);
1886
+ else if (marketType === 'spot') {
1887
+ response = await this.sapiPrivateGetV3Account(params);
1725
1888
  data = this.safeList(response, 'balances', []);
1726
1889
  //
1727
1890
  // [
@@ -1733,16 +1896,27 @@ export default class aster extends Exchange {
1733
1896
  // ]
1734
1897
  //
1735
1898
  }
1736
- else {
1737
- throw new NotSupported(this.id + ' fetchBalance() does not support ' + type + ' markets yet');
1738
- }
1739
1899
  return this.parseBalance(data);
1740
1900
  }
1901
+ parseBalance(response) {
1902
+ const result = { 'info': response };
1903
+ for (let i = 0; i < response.length; i++) {
1904
+ const balance = response[i];
1905
+ const currencyId = this.safeString(balance, 'asset');
1906
+ const code = this.safeCurrencyCode(currencyId);
1907
+ const account = this.account();
1908
+ account['free'] = this.safeString2(balance, 'free', 'availableBalance');
1909
+ account['used'] = this.safeString(balance, 'locked');
1910
+ account['total'] = this.safeString(balance, 'balance');
1911
+ result[code] = account;
1912
+ }
1913
+ return this.safeBalance(result);
1914
+ }
1741
1915
  /**
1742
1916
  * @method
1743
1917
  * @name aster#setMarginMode
1744
1918
  * @description set margin mode to 'cross' or 'isolated'
1745
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#change-margin-type-trade
1919
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#change-margin-type-trade
1746
1920
  * @param {string} marginMode 'cross' or 'isolated'
1747
1921
  * @param {string} symbol unified market symbol
1748
1922
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -1759,20 +1933,15 @@ export default class aster extends Exchange {
1759
1933
  if ((marginMode !== 'ISOLATED') && (marginMode !== 'CROSSED')) {
1760
1934
  throw new BadRequest(this.id + ' marginMode must be either isolated or cross');
1761
1935
  }
1762
- await this.loadMarkets();
1936
+ await this.loadMarketsAndSignIn();
1763
1937
  const market = this.market(symbol);
1764
1938
  const request = {
1765
1939
  'symbol': market['id'],
1766
1940
  'marginType': marginMode,
1767
1941
  };
1768
- const response = await this.fapiPrivatePostV1MarginType(this.extend(request, params));
1942
+ const response = await this.fapiPrivatePostV3MarginType(this.extend(request, params));
1769
1943
  //
1770
- // {
1771
- // "amount": 100.0,
1772
- // "code": 200,
1773
- // "msg": "Successfully modify position margin.",
1774
- // "type": 1
1775
- // }
1944
+ // { "code": 200,"msg": "success" }
1776
1945
  //
1777
1946
  return response;
1778
1947
  }
@@ -1780,37 +1949,37 @@ export default class aster extends Exchange {
1780
1949
  * @method
1781
1950
  * @name aster#fetchPositionMode
1782
1951
  * @description fetchs the position mode, hedged or one way, hedged for aster is set identically for all linear markets or all inverse markets
1783
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-current-position-modeuser_data
1952
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#get-current-position-modeuser_data
1784
1953
  * @param {string} symbol unified symbol of the market to fetch the order book for
1785
1954
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1786
1955
  * @returns {object} an object detailing whether the market is in hedged or one-way mode
1787
1956
  */
1788
1957
  async fetchPositionMode(symbol = undefined, params = {}) {
1789
- const response = await this.fapiPrivateGetV1PositionSideDual(params);
1958
+ const response = await this.fapiPrivateGetV3PositionSideDual(params);
1790
1959
  //
1791
1960
  // {
1792
1961
  // "dualSidePosition": true // "true": Hedge Mode; "false": One-way Mode
1793
1962
  // }
1794
1963
  //
1795
- const dualSidePosition = this.safeBool(response, 'dualSidePosition');
1796
1964
  return {
1797
1965
  'info': response,
1798
- 'hedged': (dualSidePosition === true),
1966
+ 'hedged': this.safeBool(response, 'dualSidePosition'),
1799
1967
  };
1800
1968
  }
1801
1969
  /**
1802
1970
  * @method
1803
1971
  * @name aster#setPositionMode
1804
1972
  * @description set hedged to true or false for a market
1805
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#change-position-modetrade
1973
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#change-position-modetrade
1806
1974
  * @param {bool} hedged set to true to use dualSidePosition
1807
1975
  * @param {string} symbol not used by bingx setPositionMode ()
1808
1976
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1809
1977
  * @returns {object} response from the exchange
1810
1978
  */
1811
1979
  async setPositionMode(hedged, symbol = undefined, params = {}) {
1980
+ const strValue = hedged ? 'true' : 'false';
1812
1981
  const request = {
1813
- 'dualSidePosition': hedged,
1982
+ 'dualSidePosition': strValue,
1814
1983
  };
1815
1984
  //
1816
1985
  // {
@@ -1818,7 +1987,7 @@ export default class aster extends Exchange {
1818
1987
  // "msg": "success"
1819
1988
  // }
1820
1989
  //
1821
- return await this.fapiPrivatePostV1PositionSideDual(this.extend(request, params));
1990
+ return await this.fapiPrivatePostV3PositionSideDual(this.extend(request, params));
1822
1991
  }
1823
1992
  parseTradingFee(fee, market = undefined) {
1824
1993
  const marketId = this.safeString(fee, 'symbol');
@@ -1837,26 +2006,28 @@ export default class aster extends Exchange {
1837
2006
  * @method
1838
2007
  * @name aster#fetchTradingFee
1839
2008
  * @description fetch the trading fees for a market
1840
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#get-symbol-fees
1841
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#user-commission-rate-user_data
2009
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/market-data/#get-symbol-fees
2010
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#user-commission-rate-user_data
1842
2011
  * @param {string} symbol unified market symbol
1843
2012
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1844
2013
  * @returns {object} a [fee structure]{@link https://docs.ccxt.com/#/?id=fee-structure}
1845
2014
  */
1846
2015
  async fetchTradingFee(symbol, params = {}) {
1847
- await this.loadMarkets();
2016
+ await this.loadMarketsAndSignIn();
1848
2017
  const market = this.market(symbol);
1849
2018
  const request = {
1850
2019
  'symbol': market['id'],
1851
2020
  };
1852
2021
  let response = undefined;
1853
2022
  if (market['swap']) {
1854
- response = await this.fapiPrivateGetV1CommissionRate(this.extend(request, params));
2023
+ response = await this.fapiPrivateGetV3CommissionRate(this.extend(request, params));
1855
2024
  }
1856
2025
  else {
1857
- response = await this.sapiPrivateGetV1CommissionRate(this.extend(request, params));
2026
+ response = await this.sapiPrivateGetV3CommissionRate(this.extend(request, params));
1858
2027
  }
1859
2028
  //
2029
+ // both SPOT & SWAP has same format
2030
+ //
1860
2031
  // {
1861
2032
  // "symbol": "BTCUSDT",
1862
2033
  // "makerCommissionRate": "0.0002",
@@ -1916,32 +2087,36 @@ export default class aster extends Exchange {
1916
2087
  // "workingType": "CONTRACT_PRICE",
1917
2088
  // "priceProtect": false
1918
2089
  // }
2090
+ //
1919
2091
  // spot
1920
- // {
1921
- // "orderId": 38,
1922
- // "symbol": "ADA25SLP25",
1923
- // "status": "FILLED",
1924
- // "clientOrderId": "afMd4GBQyHkHpGWdiy34Li",
1925
- // "price": "20",
1926
- // "avgPrice": "12.0000000000000000",
1927
- // "origQty": "10",
1928
- // "executedQty": "10",
1929
- // "cumQuote": "120",
1930
- // "timeInForce": "GTC",
1931
- // "type": "LIMIT",
1932
- // "side": "BUY",
1933
- // "stopPrice": "0",
1934
- // "origType": "LIMIT",
1935
- // "time": 1649913186270,
1936
- // "updateTime": 1649913186297
1937
- // }
2092
+ //
2093
+ // fetchOrders, fetchOpenOrders, fetchOpenOrder, fetchOrder, cancelOrder, createOrder
2094
+ //
2095
+ // {
2096
+ // "orderId": "417594542",
2097
+ // "symbol": "ETHUSDT",
2098
+ // "status": "FILLED",
2099
+ // "clientOrderId": "web_qnvMAhOJsiVbSyu0BdKG",
2100
+ // "price": "0", // value set for unfilled
2101
+ // "avgPrice": "2351.580000", // value zero for unfilled
2102
+ // "origQty": "0.0054",
2103
+ // "executedQty": "0.0054", // value zero for unfilled
2104
+ // "cumQuote": "12.69853200", // value zero for unfilled
2105
+ // "timeInForce": "GTC",
2106
+ // "type": "MARKET",
2107
+ // "side": "SELL",
2108
+ // "stopPrice": "0",
2109
+ // "origType": "MARKET",
2110
+ // "time": "1776274219582",
2111
+ // "updateTime": "1776274219609",
2112
+ // "orderListId": "-1"
2113
+ // }
1938
2114
  //
1939
2115
  const info = order;
1940
2116
  const marketId = this.safeString(order, 'symbol');
1941
2117
  market = this.safeMarket(marketId, market);
1942
2118
  const side = this.safeStringLower(order, 'side');
1943
2119
  const timestamp = this.safeInteger(order, 'time');
1944
- const lastTradeTimestamp = this.safeInteger(order, 'updateTime');
1945
2120
  const statusId = this.safeStringUpper(order, 'status');
1946
2121
  const rawType = this.safeStringUpper(order, 'type');
1947
2122
  const stopPriceString = this.safeString(order, 'stopPrice');
@@ -1953,7 +2128,7 @@ export default class aster extends Exchange {
1953
2128
  'symbol': this.safeSymbol(marketId, market),
1954
2129
  'timestamp': timestamp,
1955
2130
  'datetime': this.iso8601(timestamp),
1956
- 'lastTradeTimestamp': lastTradeTimestamp,
2131
+ 'lastTradeTimestamp': undefined,
1957
2132
  'lastUpdateTimestamp': this.safeInteger(order, 'updateTime'),
1958
2133
  'type': this.parseOrderType(rawType),
1959
2134
  'timeInForce': this.safeString(order, 'timeInForce'),
@@ -1976,8 +2151,8 @@ export default class aster extends Exchange {
1976
2151
  * @method
1977
2152
  * @name aster#fetchOrder
1978
2153
  * @description fetches information on an order made by the user
1979
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#query-order-user_data
1980
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#query-order-user_data
2154
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#query-order-user_data
2155
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#query-order-user_data
1981
2156
  * @param {string} id the order id
1982
2157
  * @param {string} symbol unified symbol of the market the order was made in
1983
2158
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -1988,7 +2163,7 @@ export default class aster extends Exchange {
1988
2163
  if (symbol === undefined) {
1989
2164
  throw new ArgumentsRequired(this.id + ' fetchOrder() requires a symbol argument');
1990
2165
  }
1991
- await this.loadMarkets();
2166
+ await this.loadMarketsAndSignIn();
1992
2167
  const market = this.market(symbol);
1993
2168
  const request = {
1994
2169
  'symbol': market['id'],
@@ -2003,18 +2178,48 @@ export default class aster extends Exchange {
2003
2178
  }
2004
2179
  let response = undefined;
2005
2180
  if (market['swap']) {
2006
- response = await this.fapiPrivateGetV1Order(this.extend(request, params));
2181
+ response = await this.fapiPrivateGetV3Order(this.extend(request, params));
2007
2182
  }
2008
2183
  else {
2009
- response = await this.sapiPrivateGetV1Order(this.extend(request, params));
2184
+ response = await this.sapiPrivateGetV3Order(this.extend(request, params));
2010
2185
  }
2186
+ //
2187
+ // SPOT & SWAP has similar formats
2188
+ //
2189
+ // {
2190
+ // "orderId": "17338441758",
2191
+ // "symbol": "ETHUSDT",
2192
+ // "status": "FILLED",
2193
+ // "clientOrderId": "727Wt3TIUgkUCxXp20E543",
2194
+ // "price": "0",
2195
+ // "avgPrice": "2304.56000",
2196
+ // "origQty": "0.010",
2197
+ // "executedQty": "0.010",
2198
+ // "cumQuote": "23.04560",
2199
+ // "timeInForce": "GTC",
2200
+ // "type": "MARKET",
2201
+ // "side": "BUY",
2202
+ // "stopPrice": "0",
2203
+ // "origType": "MARKET",
2204
+ // "time": "1776800300736",
2205
+ // "updateTime": "1776800300700",
2206
+ // "orderListId": "-1" // only in SPOT
2207
+ // "positionSide": "BOTH", // only in SWAP
2208
+ // "reduceOnly": false, // only in SWAP
2209
+ // "closePosition": false, // only in SWAP
2210
+ // "workingType": "CONTRACT_PRICE", // only in SWAP
2211
+ // "priceProtect": false, // only in SWAP
2212
+ // "newChainData": { "hash": "0x46aed5...67bdbec8ba" } // only in SWAP
2213
+ // }
2214
+ //
2011
2215
  return this.parseOrder(response, market);
2012
2216
  }
2013
2217
  /**
2014
2218
  * @method
2015
2219
  * @name aster#fetchOpenOrder
2016
2220
  * @description fetch an open order by the id
2017
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#query-current-open-order-user_data
2221
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#query-current-open-order-user_data
2222
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#query-current-open-order-user_data
2018
2223
  * @param {string} id order id
2019
2224
  * @param {string} symbol unified market symbol
2020
2225
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2024,7 +2229,7 @@ export default class aster extends Exchange {
2024
2229
  if (symbol === undefined) {
2025
2230
  throw new ArgumentsRequired(this.id + ' fetchOpenOrder() requires a symbol argument');
2026
2231
  }
2027
- await this.loadMarkets();
2232
+ await this.loadMarketsAndSignIn();
2028
2233
  const market = this.market(symbol);
2029
2234
  const request = {
2030
2235
  'symbol': market['id'],
@@ -2037,15 +2242,50 @@ export default class aster extends Exchange {
2037
2242
  else {
2038
2243
  request['orderId'] = id;
2039
2244
  }
2040
- const response = await this.fapiPrivateGetV1OpenOrder(this.extend(request, params));
2245
+ let response = undefined;
2246
+ if (market['spot']) {
2247
+ response = await this.sapiPrivateGetV3OpenOrder(this.extend(request, params));
2248
+ }
2249
+ else {
2250
+ response = await this.fapiPrivateGetV3OpenOrder(this.extend(request, params));
2251
+ }
2252
+ //
2253
+ // SPOT & SWAP has similar formats
2254
+ //
2255
+ // {
2256
+ // "orderId": "17338441758",
2257
+ // "symbol": "ETHUSDT",
2258
+ // "status": "FILLED",
2259
+ // "clientOrderId": "727Wt3TIUgkUCxXp20E543",
2260
+ // "price": "0",
2261
+ // "avgPrice": "2304.56000",
2262
+ // "origQty": "0.010",
2263
+ // "executedQty": "0.010",
2264
+ // "cumQuote": "23.04560",
2265
+ // "timeInForce": "GTC",
2266
+ // "type": "MARKET",
2267
+ // "side": "BUY",
2268
+ // "stopPrice": "0",
2269
+ // "origType": "MARKET",
2270
+ // "time": "1776800300736",
2271
+ // "updateTime": "1776800300700",
2272
+ // "orderListId": "-1" // only in SPOT
2273
+ // "positionSide": "BOTH", // only in SWAP
2274
+ // "reduceOnly": false, // only in SWAP
2275
+ // "closePosition": false, // only in SWAP
2276
+ // "workingType": "CONTRACT_PRICE", // only in SWAP
2277
+ // "priceProtect": false, // only in SWAP
2278
+ // "newChainData": { "hash": "0x46aed5...67bdbec8ba" } // only in SWAP
2279
+ // }
2280
+ //
2041
2281
  return this.parseOrder(response, market);
2042
2282
  }
2043
2283
  /**
2044
2284
  * @method
2045
2285
  * @name aster#fetchOrders
2046
2286
  * @description fetches information on multiple orders made by the user
2047
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#query-all-orders-user_data
2048
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#all-orders-user_data
2287
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#query-all-orders-user_data
2288
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#all-orders-user_data
2049
2289
  * @param {string} symbol unified market symbol of the market orders were made in
2050
2290
  * @param {int} [since] the earliest time in ms to fetch orders for
2051
2291
  * @param {int} [limit] the maximum number of order structures to retrieve
@@ -2054,39 +2294,66 @@ export default class aster extends Exchange {
2054
2294
  * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2055
2295
  */
2056
2296
  async fetchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2057
- await this.loadMarkets();
2058
2297
  if (symbol === undefined) {
2059
2298
  throw new ArgumentsRequired(this.id + ' fetchOrders() requires a symbol argument');
2060
2299
  }
2300
+ await this.loadMarketsAndSignIn();
2061
2301
  const market = this.market(symbol);
2062
2302
  let request = {
2063
2303
  'symbol': market['id'],
2064
2304
  };
2305
+ if (limit !== undefined) {
2306
+ request['limit'] = Math.min(limit, 1000);
2307
+ }
2065
2308
  if (since !== undefined) {
2066
2309
  request['startTime'] = since;
2067
2310
  }
2068
- if (limit !== undefined) {
2069
- if (limit > 1000) {
2070
- limit = 1000; // Default 500; max 1000
2071
- }
2072
- request['limit'] = limit;
2073
- }
2074
2311
  [request, params] = this.handleUntilOption('endTime', request, params);
2075
2312
  let response = undefined;
2076
2313
  if (market['swap']) {
2077
- response = await this.fapiPrivateGetV1AllOrders(this.extend(request, params));
2314
+ response = await this.fapiPrivateGetV3AllOrders(this.extend(request, params));
2078
2315
  }
2079
2316
  else {
2080
- response = await this.sapiPrivateGetV1AllOrders(this.extend(request, params));
2317
+ response = await this.sapiPrivateGetV3AllOrders(this.extend(request, params));
2081
2318
  }
2319
+ //
2320
+ // SPOT & SWAP has similar responses
2321
+ //
2322
+ // [
2323
+ // {
2324
+ // "orderId": "417594542",
2325
+ // "symbol": "ETHUSDT",
2326
+ // "status": "FILLED",
2327
+ // "clientOrderId": "web_qnvMAhOJsiVbSyu0BdKG",
2328
+ // "price": "0", // value set for unfilled
2329
+ // "avgPrice": "2351.580000", // value zero for unfilled
2330
+ // "origQty": "0.0054",
2331
+ // "executedQty": "0.0054", // value zero for unfilled
2332
+ // "cumQuote": "12.69853200", // value zero for unfilled
2333
+ // "timeInForce": "GTC",
2334
+ // "type": "MARKET",
2335
+ // "side": "SELL",
2336
+ // "stopPrice": "0",
2337
+ // "origType": "MARKET",
2338
+ // "time": "1776274219582",
2339
+ // "updateTime": "1776274219609",
2340
+ // "orderListId": "-1", // only in SPOT
2341
+ // "reduceOnly": false, // only in PERP
2342
+ // "closePosition": false, // only in PERP
2343
+ // "positionSide": "BOTH", // only in PERP
2344
+ // "workingType": "CONTRACT_PRICE", // only in PERP
2345
+ // "priceProtect": false, // only in PERP
2346
+ // "newChainData": { "hash": "0xe17d3d5b...dbca8b01" } // only in PERP
2347
+ // }, ...
2348
+ //
2082
2349
  return this.parseOrders(response, market, since, limit);
2083
2350
  }
2084
2351
  /**
2085
2352
  * @method
2086
2353
  * @name aster#fetchOpenOrders
2087
2354
  * @description fetch all unfilled currently open orders
2088
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#current-open-orders-user_data
2089
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#current-all-open-orders-user_data
2355
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#current-open-orders-user_data
2356
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#current-all-open-orders-user_data
2090
2357
  * @param {string} symbol unified market symbol
2091
2358
  * @param {int} [since] the earliest time in ms to fetch open orders for
2092
2359
  * @param {int} [limit] the maximum number of open orders structures to retrieve
@@ -2096,55 +2363,63 @@ export default class aster extends Exchange {
2096
2363
  * @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2097
2364
  */
2098
2365
  async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2099
- await this.loadMarkets();
2366
+ await this.loadMarketsAndSignIn();
2100
2367
  const request = {};
2101
2368
  let market = undefined;
2102
- let type = undefined;
2103
- let subType = undefined;
2104
- [subType, params] = this.handleSubTypeAndParams('fetchOpenOrders', market, params);
2369
+ let marketType = undefined;
2105
2370
  if (symbol !== undefined) {
2106
2371
  market = this.market(symbol);
2107
2372
  request['symbol'] = market['id'];
2108
2373
  }
2109
- [type, params] = this.handleMarketTypeAndParams('fetchOpenOrders', market, params);
2110
- let response = undefined;
2111
- if (this.isLinear(type, subType)) {
2112
- response = await this.fapiPrivateGetV1OpenOrders(this.extend(request, params));
2113
- }
2114
- else if (type === 'spot') {
2115
- response = await this.sapiPrivateGetV1OpenOrders(this.extend(request, params));
2374
+ if (symbol === undefined) {
2375
+ if (this.options['fetchOpenOrders']['warnIfNoSymbol']) {
2376
+ throw new ExchangeError(this.id + ' fetchOpenOrders(): WARNING - this method without providing "symbol" argument uses 40 times more rate-limit quota. If you acknowledge this warning, set ' + this.id + '.options["fetchOpenOrders"]["warnIfNoSymbol"] = false to suppress this warning message.');
2377
+ }
2116
2378
  }
2117
2379
  else {
2118
- throw new NotSupported(this.id + ' fetchOpenOrders() does not support ' + type + ' markets yet');
2380
+ market = this.market(symbol);
2381
+ request['symbol'] = market['id'];
2382
+ }
2383
+ [marketType, params] = this.handleMarketTypeAndParams('fetchOpenOrders', market, params);
2384
+ let subType = undefined;
2385
+ [subType, params] = this.handleSubTypeAndParams('fetchOpenOrders', market, params);
2386
+ let response = undefined;
2387
+ if (this.isLinear(marketType, subType)) {
2388
+ response = await this.fapiPrivateGetV3OpenOrders(this.extend(request, params));
2389
+ }
2390
+ else if (marketType === 'spot') {
2391
+ response = await this.sapiPrivateGetV3OpenOrders(this.extend(request, params));
2119
2392
  }
2120
2393
  //
2121
- // [
2122
- // {
2123
- // "avgPrice": "0.00000",
2124
- // "clientOrderId": "abc",
2125
- // "cumQuote": "0",
2126
- // "executedQty": "0",
2127
- // "orderId": 1917641,
2128
- // "origQty": "0.40",
2129
- // "origType": "TRAILING_STOP_MARKET",
2130
- // "price": "0",
2131
- // "reduceOnly": false,
2132
- // "side": "BUY",
2133
- // "positionSide": "SHORT",
2134
- // "status": "NEW",
2135
- // "stopPrice": "9300",
2136
- // "closePosition": false,
2137
- // "symbol": "BTCUSDT",
2138
- // "time": 1579276756075,
2139
- // "timeInForce": "GTC",
2140
- // "type": "TRAILING_STOP_MARKET",
2141
- // "activatePrice": "9020",
2142
- // "priceRate": "0.3",
2143
- // "updateTime": 1579276756075,
2144
- // "workingType": "CONTRACT_PRICE",
2145
- // "priceProtect": false
2146
- // }
2147
- // ]
2394
+ // SPOT & SWAP has similar responses
2395
+ //
2396
+ // [
2397
+ // {
2398
+ // "orderId": "17338239315",
2399
+ // "symbol": "ETHUSDT",
2400
+ // "status": "NEW",
2401
+ // "clientOrderId": "web_AD_mbhgla7k15gptmwyr_x",
2402
+ // "price": "2216.62",
2403
+ // "avgPrice": "0",
2404
+ // "origQty": "0.012",
2405
+ // "executedQty": "0",
2406
+ // "cumQuote": "0",
2407
+ // "timeInForce": "GTC",
2408
+ // "type": "LIMIT",
2409
+ // "side": "BUY",
2410
+ // "stopPrice": "0",
2411
+ // "origType": "LIMIT",
2412
+ // "time": "1776798208476",
2413
+ // "updateTime": "1776798208450",
2414
+ // "orderListId": "-1" // only in SPOT
2415
+ // "reduceOnly": false, // only in PERP
2416
+ // "closePosition": false, // only in PERP
2417
+ // "positionSide": "BOTH", // only in PERP
2418
+ // "workingType": "CONTRACT_PRICE", // only in PERP
2419
+ // "priceProtect": false, // only in PERP
2420
+ // "newChainData": { "hash": "0xf8a496....a7fd5" } // only in PERP
2421
+ // }
2422
+ // ]
2148
2423
  //
2149
2424
  return this.parseOrders(response, market, since, limit);
2150
2425
  }
@@ -2152,8 +2427,8 @@ export default class aster extends Exchange {
2152
2427
  * @method
2153
2428
  * @name aster#createOrder
2154
2429
  * @description create a trade order
2155
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#place-order-trade
2156
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#new-order--trade
2430
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#place-order-trade
2431
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#new-order-trade
2157
2432
  * @param {string} symbol unified symbol of the market to create an order in
2158
2433
  * @param {string} type 'market' or 'limit' or 'STOP' or 'STOP_MARKET' or 'TAKE_PROFIT' or 'TAKE_PROFIT_MARKET' or 'TRAILING_STOP_MARKET'
2159
2434
  * @param {string} side 'buy' or 'sell'
@@ -2171,36 +2446,59 @@ export default class aster extends Exchange {
2171
2446
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2172
2447
  */
2173
2448
  async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
2174
- await this.loadMarkets();
2449
+ await this.loadMarketsAndSignIn();
2175
2450
  const market = this.market(symbol);
2176
- const test = this.safeBool(params, 'test', false);
2177
- params = this.omit(params, 'test');
2178
2451
  const request = this.createOrderRequest(symbol, type, side, amount, price, params);
2179
2452
  let response = undefined;
2180
2453
  if (market['swap']) {
2181
- if (test) {
2182
- response = await this.fapiPrivatePostV1OrderTest(request);
2183
- }
2184
- else {
2185
- response = await this.fapiPrivatePostV1Order(request);
2186
- }
2454
+ response = await this.fapiPrivatePostV3Order(request);
2187
2455
  }
2188
2456
  else {
2189
- response = await this.sapiPrivatePostV1Order(request);
2457
+ response = await this.sapiPrivatePostV3Order(request);
2190
2458
  }
2459
+ //
2460
+ // SPOT & SWAP has similar responses
2461
+ //
2462
+ // {
2463
+ // "orderId": "17338441758",
2464
+ // "symbol": "ETHUSDT",
2465
+ // "status": "NEW",
2466
+ // "clientOrderId": "727Wt3TIUgkUCxXp20E543",
2467
+ // "price": "0",
2468
+ // "avgPrice": "0.00000",
2469
+ // "origQty": "0.010",
2470
+ // "executedQty": "0",
2471
+ // "cumQty": "0",
2472
+ // "cumQuote": "0",
2473
+ // "timeInForce": "GTC",
2474
+ // "type": "MARKET",
2475
+ // "side": "BUY",
2476
+ // "stopPrice": "0",
2477
+ // "origType": "MARKET",
2478
+ // "time": "1776800300700",
2479
+ // "updateTime": "1776800300700",
2480
+ // "orderListId": "-1", // only in SPOT
2481
+ // "workingType": "CONTRACT_PRICE", // only in PERP
2482
+ // "positionSide": "BOTH", // only in PERP
2483
+ // "reduceOnly": false, // only in PERP
2484
+ // "closePosition": false, // only in PERP
2485
+ // "priceProtect": false, // only in PERP
2486
+ // "newChainData": { "hash": "0x46ae....c8ba" } // only in PERP
2487
+ // }
2488
+ //
2191
2489
  return this.parseOrder(response, market);
2192
2490
  }
2193
2491
  /**
2194
2492
  * @method
2195
2493
  * @name aster#createOrders
2196
2494
  * @description create a list of trade orders
2197
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#place-multiple-orders--trade
2495
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#new-order-trade
2198
2496
  * @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
2199
2497
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2200
2498
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
2201
2499
  */
2202
2500
  async createOrders(orders, params = {}) {
2203
- await this.loadMarkets();
2501
+ await this.loadMarketsAndSignIn();
2204
2502
  const ordersRequests = [];
2205
2503
  let orderSymbols = [];
2206
2504
  if (orders.length > 5) {
@@ -2209,6 +2507,8 @@ export default class aster extends Exchange {
2209
2507
  for (let i = 0; i < orders.length; i++) {
2210
2508
  const rawOrder = orders[i];
2211
2509
  const marketId = this.safeString(rawOrder, 'symbol');
2510
+ const currentMarket = this.market(marketId);
2511
+ orderSymbols.push(currentMarket['symbol']);
2212
2512
  const type = this.safeString(rawOrder, 'type');
2213
2513
  const side = this.safeString(rawOrder, 'side');
2214
2514
  const amount = this.safeValue(rawOrder, 'amount');
@@ -2225,7 +2525,37 @@ export default class aster extends Exchange {
2225
2525
  const request = {
2226
2526
  'batchOrders': ordersRequests,
2227
2527
  };
2228
- const response = await this.fapiPrivatePostV1BatchOrders(this.extend(request, params));
2528
+ const response = await this.fapiPrivatePostV3BatchOrders(this.extend(request, params));
2529
+ //
2530
+ // [
2531
+ // {
2532
+ // "orderId": 17338699853,
2533
+ // "symbol": "ETHUSDT",
2534
+ // "status": "NEW",
2535
+ // "clientOrderId": "NxMWPvOEyiF6TWh5UB8BQf0",
2536
+ // "price": "0",
2537
+ // "avgPrice": "0.00000",
2538
+ // "origQty": "0.010",
2539
+ // "executedQty": "0",
2540
+ // "cumQty": "0",
2541
+ // "cumQuote": "0",
2542
+ // "timeInForce": "GTC",
2543
+ // "type": "MARKET",
2544
+ // "reduceOnly": false,
2545
+ // "closePosition": false,
2546
+ // "side": "BUY",
2547
+ // "positionSide": "BOTH",
2548
+ // "stopPrice": "0",
2549
+ // "workingType": "CONTRACT_PRICE",
2550
+ // "priceProtect": false,
2551
+ // "origType": "MARKET",
2552
+ // "updateTime": 1776802276050,
2553
+ // "newChainData": {
2554
+ // "hash": "0x5e569d9794cf726f72c2d000d401d20315e78e4df7b58023a489864624527dfe"
2555
+ // }
2556
+ // }
2557
+ // ]
2558
+ //
2229
2559
  return this.parseOrders(response);
2230
2560
  }
2231
2561
  createOrderRequest(symbol, type, side, amount, price = undefined, params = {}) {
@@ -2400,14 +2730,18 @@ export default class aster extends Exchange {
2400
2730
  request['timeInForce'] = this.safeString(this.options, 'defaultTimeInForce'); // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
2401
2731
  }
2402
2732
  const requestParams = this.omit(params, ['newClientOrderId', 'clientOrderId', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'trailingDelta', 'stopPrice', 'stopLossPrice', 'takeProfitPrice']);
2733
+ if (this.safeBool(this.options, 'builderFee') && market['swap']) {
2734
+ request['builder'] = this.safeString(this.options, 'builder');
2735
+ request['feeRate'] = this.safeString(this.options, 'builderRate');
2736
+ }
2403
2737
  return this.extend(request, requestParams);
2404
2738
  }
2405
2739
  /**
2406
2740
  * @method
2407
2741
  * @name aster#cancelAllOrders
2408
2742
  * @description cancel all open orders in a market
2409
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#cancel-all-open-orders-trade
2410
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#cancel-all-open-orders-trade
2743
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#cancel-all-open-orders-trade
2744
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#current-all-open-orders-user_data
2411
2745
  * @param {string} symbol unified market symbol of the market to cancel orders in
2412
2746
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2413
2747
  * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
@@ -2416,19 +2750,21 @@ export default class aster extends Exchange {
2416
2750
  if (symbol === undefined) {
2417
2751
  throw new ArgumentsRequired(this.id + ' cancelAllOrders() requires a symbol argument');
2418
2752
  }
2419
- await this.loadMarkets();
2753
+ await this.loadMarketsAndSignIn();
2420
2754
  const market = this.market(symbol);
2421
2755
  const request = {
2422
2756
  'symbol': market['id'],
2423
2757
  };
2424
2758
  let response = undefined;
2425
2759
  if (market['swap']) {
2426
- response = await this.fapiPrivateDeleteV1AllOpenOrders(this.extend(request, params));
2760
+ response = await this.fapiPrivateDeleteV3AllOpenOrders(this.extend(request, params));
2427
2761
  }
2428
2762
  else {
2429
- response = await this.sapiPrivateDeleteV1AllOpenOrders(this.extend(request, params));
2763
+ response = await this.sapiPrivateDeleteV3AllOpenOrders(this.extend(request, params));
2430
2764
  }
2431
2765
  //
2766
+ // SPOT & SWAP has same response
2767
+ //
2432
2768
  // {
2433
2769
  // "code": "200",
2434
2770
  // "msg": "The operation of cancel all open order is done."
@@ -2444,8 +2780,8 @@ export default class aster extends Exchange {
2444
2780
  * @method
2445
2781
  * @name aster#cancelOrder
2446
2782
  * @description cancels an open order
2447
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#cancel-order-trade
2448
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#cancel-order-trade
2783
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#cancel-order-trade
2784
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#cancel-order-trade
2449
2785
  * @param {string} id order id
2450
2786
  * @param {string} symbol unified symbol of the market the order was made in
2451
2787
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2455,25 +2791,25 @@ export default class aster extends Exchange {
2455
2791
  if (symbol === undefined) {
2456
2792
  throw new ArgumentsRequired(this.id + ' cancelOrder() requires a symbol argument');
2457
2793
  }
2458
- await this.loadMarkets();
2794
+ await this.loadMarketsAndSignIn();
2459
2795
  const market = this.market(symbol);
2460
2796
  const request = {
2461
2797
  'symbol': market['id'],
2462
2798
  };
2463
- const clientOrderId = this.safeStringN(params, ['origClientOrderId', 'clientOrderId', 'newClientStrategyId']);
2799
+ const clientOrderId = this.safeStringN(params, ['origClientOrderId', 'clientOrderId']);
2464
2800
  if (clientOrderId !== undefined) {
2465
2801
  request['origClientOrderId'] = clientOrderId;
2466
2802
  }
2467
2803
  else {
2468
2804
  request['orderId'] = id;
2469
2805
  }
2470
- params = this.omit(params, ['origClientOrderId', 'clientOrderId', 'newClientStrategyId']);
2806
+ params = this.omit(params, ['origClientOrderId', 'clientOrderId']);
2471
2807
  let response = undefined;
2472
2808
  if (market['swap']) {
2473
- response = await this.fapiPrivateDeleteV1Order(this.extend(request, params));
2809
+ response = await this.fapiPrivateDeleteV3Order(this.extend(request, params));
2474
2810
  }
2475
2811
  else {
2476
- response = await this.sapiPrivateDeleteV1Order(this.extend(request, params));
2812
+ response = await this.sapiPrivateDeleteV3Order(this.extend(request, params));
2477
2813
  }
2478
2814
  return this.parseOrder(response, market);
2479
2815
  }
@@ -2481,7 +2817,8 @@ export default class aster extends Exchange {
2481
2817
  * @method
2482
2818
  * @name aster#cancelOrders
2483
2819
  * @description cancel multiple orders
2484
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#cancel-multiple-orders-trade
2820
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#cancel-all-open-orders-trade
2821
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#cancel-multiple-orders-trade
2485
2822
  * @param {string[]} ids order ids
2486
2823
  * @param {string} [symbol] unified market symbol
2487
2824
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2495,11 +2832,8 @@ export default class aster extends Exchange {
2495
2832
  if (symbol === undefined) {
2496
2833
  throw new ArgumentsRequired(this.id + ' cancelOrders() requires a symbol argument');
2497
2834
  }
2498
- await this.loadMarkets();
2835
+ await this.loadMarketsAndSignIn();
2499
2836
  const market = this.market(symbol);
2500
- if (market['spot']) {
2501
- throw new NotSupported(this.id + ' cancelOrders() does not support ' + market['type'] + ' orders');
2502
- }
2503
2837
  const request = {
2504
2838
  'symbol': market['id'],
2505
2839
  };
@@ -2510,46 +2844,55 @@ export default class aster extends Exchange {
2510
2844
  else {
2511
2845
  request['orderIdList'] = ids;
2512
2846
  }
2513
- const response = await this.fapiPrivateDeleteV1BatchOrders(this.extend(request, params));
2514
- //
2515
- // [
2516
- // {
2517
- // "clientOrderId": "myOrder1",
2518
- // "cumQty": "0",
2519
- // "cumQuote": "0",
2520
- // "executedQty": "0",
2521
- // "orderId": 283194212,
2522
- // "origQty": "11",
2523
- // "origType": "TRAILING_STOP_MARKET",
2524
- // "price": "0",
2525
- // "reduceOnly": false,
2526
- // "side": "BUY",
2527
- // "positionSide": "SHORT",
2528
- // "status": "CANCELED",
2529
- // "stopPrice": "9300", // please ignore when order type is TRAILING_STOP_MARKET
2530
- // "closePosition": false, // if Close-All
2531
- // "symbol": "BTCUSDT",
2532
- // "timeInForce": "GTC",
2533
- // "type": "TRAILING_STOP_MARKET",
2534
- // "activatePrice": "9020", // activation price, only return with TRAILING_STOP_MARKET order
2535
- // "priceRate": "0.3", // callback rate, only return with TRAILING_STOP_MARKET order
2536
- // "updateTime": 1571110484038,
2537
- // "workingType": "CONTRACT_PRICE",
2538
- // "priceProtect": false, // if conditional order trigger is protected
2539
- // },
2540
- // {
2541
- // "code": -2011,
2542
- // "msg": "Unknown order sent."
2543
- // }
2544
- // ]
2545
- //
2847
+ let response = undefined;
2848
+ if (market['swap']) {
2849
+ response = await this.fapiPrivateDeleteV3BatchOrders(this.extend(request, params));
2850
+ //
2851
+ // [
2852
+ // {
2853
+ // "clientOrderId": "myOrder1",
2854
+ // "cumQty": "0",
2855
+ // "cumQuote": "0",
2856
+ // "executedQty": "0",
2857
+ // "orderId": 283194212,
2858
+ // "origQty": "11",
2859
+ // "origType": "TRAILING_STOP_MARKET",
2860
+ // "price": "0",
2861
+ // "reduceOnly": false,
2862
+ // "side": "BUY",
2863
+ // "positionSide": "SHORT",
2864
+ // "status": "CANCELED",
2865
+ // "stopPrice": "9300", // please ignore when order type is TRAILING_STOP_MARKET
2866
+ // "closePosition": false, // if Close-All
2867
+ // "symbol": "BTCUSDT",
2868
+ // "timeInForce": "GTC",
2869
+ // "type": "TRAILING_STOP_MARKET",
2870
+ // "activatePrice": "9020", // activation price, only return with TRAILING_STOP_MARKET order
2871
+ // "priceRate": "0.3", // callback rate, only return with TRAILING_STOP_MARKET order
2872
+ // "updateTime": 1571110484038,
2873
+ // "workingType": "CONTRACT_PRICE",
2874
+ // "priceProtect": false, // if conditional order trigger is protected
2875
+ // },
2876
+ // {
2877
+ // "code": -2011,
2878
+ // "msg": "Unknown order sent."
2879
+ // }
2880
+ // ]
2881
+ //
2882
+ }
2883
+ else {
2884
+ response = await this.sapiPrivateDeleteV3AllOpenOrders(this.extend(request, params));
2885
+ //
2886
+ // {"code": 200,"msg": "The operation of cancel all open order is done."}
2887
+ //
2888
+ }
2546
2889
  return this.parseOrders(response, market);
2547
2890
  }
2548
2891
  /**
2549
2892
  * @method
2550
2893
  * @name aster#setLeverage
2551
2894
  * @description set the level of leverage for a market
2552
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#change-initial-leverage-trade
2895
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#change-initial-leverage-trade
2553
2896
  * @param {float} leverage the rate of leverage
2554
2897
  * @param {string} symbol unified market symbol
2555
2898
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2562,13 +2905,13 @@ export default class aster extends Exchange {
2562
2905
  if ((leverage < 1) || (leverage > 125)) {
2563
2906
  throw new BadRequest(this.id + ' leverage should be between 1 and 125');
2564
2907
  }
2565
- await this.loadMarkets();
2908
+ await this.loadMarketsAndSignIn();
2566
2909
  const market = this.market(symbol);
2567
2910
  const request = {
2568
2911
  'symbol': market['id'],
2569
2912
  'leverage': leverage,
2570
2913
  };
2571
- const response = await this.fapiPrivatePostV1Leverage(this.extend(request, params));
2914
+ const response = await this.fapiPrivatePostV3Leverage(this.extend(request, params));
2572
2915
  //
2573
2916
  // {
2574
2917
  // "leverage": 21,
@@ -2582,14 +2925,14 @@ export default class aster extends Exchange {
2582
2925
  * @method
2583
2926
  * @name aster#fetchLeverages
2584
2927
  * @description fetch the set leverage for all markets
2585
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
2928
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#position-information-v3-user_data
2586
2929
  * @param {string[]} [symbols] a list of unified market symbols
2587
2930
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2588
2931
  * @returns {object} a list of [leverage structures]{@link https://docs.ccxt.com/#/?id=leverage-structure}
2589
2932
  */
2590
2933
  async fetchLeverages(symbols = undefined, params = {}) {
2591
- await this.loadMarkets();
2592
- const response = await this.fapiPrivateGetV2PositionRisk(params);
2934
+ await this.loadMarketsAndSignIn();
2935
+ const response = await this.fapiPrivateGetV3PositionRisk(params);
2593
2936
  //
2594
2937
  // [
2595
2938
  // {
@@ -2661,14 +3004,14 @@ export default class aster extends Exchange {
2661
3004
  * @method
2662
3005
  * @name aster#fetchMarginModes
2663
3006
  * @description fetches margin mode of the user
2664
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
3007
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#position-information-v3-user_data
2665
3008
  * @param {string[]} symbols unified market symbols
2666
3009
  * @param {object} [params] extra parameters specific to the exchange API endpoint
2667
3010
  * @returns {object} a list of [margin mode structures]{@link https://docs.ccxt.com/#/?id=margin-mode-structure}
2668
3011
  */
2669
3012
  async fetchMarginModes(symbols = undefined, params = {}) {
2670
- await this.loadMarkets();
2671
- const response = await this.fapiPrivateGetV2PositionRisk(params);
3013
+ await this.loadMarketsAndSignIn();
3014
+ const response = await this.fapiPrivateGetV3PositionRisk(params);
2672
3015
  //
2673
3016
  //
2674
3017
  // [
@@ -2726,7 +3069,7 @@ export default class aster extends Exchange {
2726
3069
  * @method
2727
3070
  * @name aster#fetchMarginAdjustmentHistory
2728
3071
  * @description fetches the history of margin added or reduced from contract isolated positions
2729
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-position-margin-change-history-trade
3072
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#get-position-margin-change-history-trade
2730
3073
  * @param {string} symbol unified market symbol
2731
3074
  * @param {string} [type] "add" or "reduce"
2732
3075
  * @param {int} [since] timestamp in ms of the earliest change to fetch
@@ -2736,10 +3079,10 @@ export default class aster extends Exchange {
2736
3079
  * @returns {object[]} a list of [margin structures]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
2737
3080
  */
2738
3081
  async fetchMarginAdjustmentHistory(symbol = undefined, type = undefined, since = undefined, limit = undefined, params = {}) {
2739
- await this.loadMarkets();
2740
3082
  if (symbol === undefined) {
2741
3083
  throw new ArgumentsRequired(this.id + ' fetchMarginAdjustmentHistory () requires a symbol argument');
2742
3084
  }
3085
+ await this.loadMarketsAndSignIn();
2743
3086
  const market = this.market(symbol);
2744
3087
  const until = this.safeInteger(params, 'until');
2745
3088
  params = this.omit(params, 'until');
@@ -2749,16 +3092,16 @@ export default class aster extends Exchange {
2749
3092
  if (type !== undefined) {
2750
3093
  request['type'] = (type === 'add') ? 1 : 2;
2751
3094
  }
3095
+ if (limit !== undefined) {
3096
+ request['limit'] = Math.min(limit, 1000);
3097
+ }
2752
3098
  if (since !== undefined) {
2753
3099
  request['startTime'] = since;
2754
3100
  }
2755
- if (limit !== undefined) {
2756
- request['limit'] = limit;
2757
- }
2758
3101
  if (until !== undefined) {
2759
3102
  request['endTime'] = until;
2760
3103
  }
2761
- const response = await this.fapiPrivateGetV1PositionMarginHistory(this.extend(request, params));
3104
+ const response = await this.fapiPrivateGetV3PositionMarginHistory(this.extend(request, params));
2762
3105
  //
2763
3106
  // [
2764
3107
  // {
@@ -2813,7 +3156,7 @@ export default class aster extends Exchange {
2813
3156
  };
2814
3157
  }
2815
3158
  async modifyMarginHelper(symbol, amount, addOrReduce, params = {}) {
2816
- await this.loadMarkets();
3159
+ await this.loadMarketsAndSignIn();
2817
3160
  const market = this.market(symbol);
2818
3161
  amount = this.amountToPrecision(symbol, amount);
2819
3162
  const request = {
@@ -2822,7 +3165,7 @@ export default class aster extends Exchange {
2822
3165
  'amount': amount,
2823
3166
  };
2824
3167
  const code = market['quote'];
2825
- const response = await this.fapiPrivatePostV1PositionMargin(this.extend(request, params));
3168
+ const response = await this.fapiPrivatePostV3PositionMargin(this.extend(request, params));
2826
3169
  //
2827
3170
  // {
2828
3171
  // "amount": 100.0,
@@ -2831,15 +3174,13 @@ export default class aster extends Exchange {
2831
3174
  // "type": 1
2832
3175
  // }
2833
3176
  //
2834
- return this.extend(this.parseMarginModification(response, market), {
2835
- 'code': code,
2836
- });
3177
+ return this.extend(this.parseMarginModification(response, market), { 'code': code });
2837
3178
  }
2838
3179
  /**
2839
3180
  * @method
2840
3181
  * @name aster#reduceMargin
2841
3182
  * @description remove margin from a position
2842
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#modify-isolated-position-margin-trade
3183
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#modify-isolated-position-margin-trade
2843
3184
  * @param {string} symbol unified market symbol
2844
3185
  * @param {float} amount the amount of margin to remove
2845
3186
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2852,7 +3193,7 @@ export default class aster extends Exchange {
2852
3193
  * @method
2853
3194
  * @name aster#addMargin
2854
3195
  * @description add margin
2855
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#modify-isolated-position-margin-trade
3196
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#modify-isolated-position-margin-trade
2856
3197
  * @param {string} symbol unified market symbol
2857
3198
  * @param {float} amount amount of margin to add
2858
3199
  * @param {object} [params] extra parameters specific to the exchange API endpoint
@@ -2891,7 +3232,7 @@ export default class aster extends Exchange {
2891
3232
  * @method
2892
3233
  * @name aster#fetchFundingHistory
2893
3234
  * @description fetch the history of funding payments paid and received on this account
2894
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-income-historyuser_data
3235
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#get-income-historyuser_data
2895
3236
  * @param {string} symbol unified market symbol
2896
3237
  * @param {int} [since] the earliest time in ms to fetch funding history for
2897
3238
  * @param {int} [limit] the maximum number of funding history structures to retrieve
@@ -2902,7 +3243,7 @@ export default class aster extends Exchange {
2902
3243
  * @returns {object} a [funding history structure]{@link https://docs.ccxt.com/#/?id=funding-history-structure}
2903
3244
  */
2904
3245
  async fetchFundingHistory(symbol = undefined, since = undefined, limit = undefined, params = {}) {
2905
- await this.loadMarkets();
3246
+ await this.loadMarketsAndSignIn();
2906
3247
  let market = undefined;
2907
3248
  let request = {
2908
3249
  'incomeType': 'FUNDING_FEE', // "TRANSFER","WELCOME_BONUS", "REALIZED_PNL","FUNDING_FEE", "COMMISSION", "INSURANCE_CLEAR", and "MARKET_MERCHANT_RETURN_REWARD"
@@ -2918,7 +3259,7 @@ export default class aster extends Exchange {
2918
3259
  if (limit !== undefined) {
2919
3260
  request['limit'] = Math.min(limit, 1000); // max 1000
2920
3261
  }
2921
- const response = await this.fapiPrivateGetV1Income(this.extend(request, params));
3262
+ const response = await this.fapiPrivateGetV3Income(this.extend(request, params));
2922
3263
  return this.parseIncomes(response, market, since, limit);
2923
3264
  }
2924
3265
  parseLedgerEntry(item, currency = undefined) {
@@ -2982,7 +3323,7 @@ export default class aster extends Exchange {
2982
3323
  * @method
2983
3324
  * @name aster#fetchLedger
2984
3325
  * @description fetch the history of changes, actions done by the user or operations that altered the balance of the user
2985
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#get-income-historyuser_data
3326
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#get-income-historyuser_data
2986
3327
  * @param {string} [code] unified currency code
2987
3328
  * @param {int} [since] timestamp in ms of the earliest ledger entry
2988
3329
  * @param {int} [limit] max number of ledger entries to return
@@ -2991,7 +3332,7 @@ export default class aster extends Exchange {
2991
3332
  * @returns {object} a [ledger structure]{@link https://docs.ccxt.com/#/?id=ledger}
2992
3333
  */
2993
3334
  async fetchLedger(code = undefined, since = undefined, limit = undefined, params = {}) {
2994
- await this.loadMarkets();
3335
+ await this.loadMarketsAndSignIn();
2995
3336
  let currency = undefined;
2996
3337
  if (code !== undefined) {
2997
3338
  currency = this.currency(code);
@@ -3008,7 +3349,7 @@ export default class aster extends Exchange {
3008
3349
  params = this.omit(params, 'until');
3009
3350
  request['endTime'] = until;
3010
3351
  }
3011
- const response = await this.fapiPrivateGetV1Income(this.extend(request, params));
3352
+ const response = await this.fapiPrivateGetV3Income(this.extend(request, params));
3012
3353
  //
3013
3354
  // [
3014
3355
  // {
@@ -3204,7 +3545,7 @@ export default class aster extends Exchange {
3204
3545
  * @method
3205
3546
  * @name aster#fetchPositionsRisk
3206
3547
  * @description fetch positions risk
3207
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
3548
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#position-information-v3-user_data
3208
3549
  * @param {string[]|undefined} symbols list of unified market symbols
3209
3550
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3210
3551
  * @returns {object} data on the positions risk
@@ -3215,10 +3556,10 @@ export default class aster extends Exchange {
3215
3556
  throw new ArgumentsRequired(this.id + ' fetchPositionsRisk() requires an array argument for symbols');
3216
3557
  }
3217
3558
  }
3218
- await this.loadMarkets();
3559
+ await this.loadMarketsAndSignIn();
3219
3560
  await this.loadLeverageBrackets(false, params);
3220
3561
  const request = {};
3221
- const response = await this.fapiPrivateGetV2PositionRisk(this.extend(request, params));
3562
+ const response = await this.fapiPrivateGetV3PositionRisk(this.extend(request, params));
3222
3563
  //
3223
3564
  // [
3224
3565
  // {
@@ -3253,7 +3594,7 @@ export default class aster extends Exchange {
3253
3594
  * @method
3254
3595
  * @name aster#fetchPositions
3255
3596
  * @description fetch all open positions
3256
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
3597
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#position-information-v3-user_data
3257
3598
  * @param {string[]} [symbols] list of unified market symbols
3258
3599
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3259
3600
  * @param {string} [params.method] method name to call, "positionRisk", "account" or "option", default is "positionRisk"
@@ -3490,7 +3831,7 @@ export default class aster extends Exchange {
3490
3831
  * @name aster#fetchAccountPositions
3491
3832
  * @ignore
3492
3833
  * @description fetch account positions
3493
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#position-information-v2-user_data
3834
+ https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#position-information-v3-user_data
3494
3835
  * @param {string[]} [symbols] list of unified market symbols
3495
3836
  * @param {object} [params] extra parameters specific to the exchange API endpoint
3496
3837
  * @returns {object} data on account positions
@@ -3501,7 +3842,7 @@ export default class aster extends Exchange {
3501
3842
  throw new ArgumentsRequired(this.id + ' fetchPositions() requires an array argument for symbols');
3502
3843
  }
3503
3844
  }
3504
- await this.loadMarkets();
3845
+ await this.loadMarketsAndSignIn();
3505
3846
  await this.loadLeverageBrackets(false, params);
3506
3847
  const response = await this.fapiPrivateGetV4Account(params);
3507
3848
  let filterClosed = undefined;
@@ -3511,12 +3852,35 @@ export default class aster extends Exchange {
3511
3852
  return this.filterByArrayPositions(result, 'symbol', symbols, false);
3512
3853
  }
3513
3854
  async loadLeverageBrackets(reload = false, params = {}) {
3514
- await this.loadMarkets();
3855
+ await this.loadMarketsAndSignIn();
3515
3856
  // by default cache the leverage bracket
3516
3857
  // it contains useful stuff like the maintenance margin and initial margin for positions
3517
3858
  const leverageBrackets = this.safeDict(this.options, 'leverageBrackets');
3518
3859
  if ((leverageBrackets === undefined) || (reload)) {
3519
- const response = await this.fapiPrivateGetV1LeverageBracket(params);
3860
+ const response = await this.fapiPrivateGetV3LeverageBracket(params);
3861
+ //
3862
+ // [
3863
+ // {
3864
+ // "symbol": "TRUTHUSDT",
3865
+ // "brackets": [
3866
+ // {
3867
+ // "bracket": "1",
3868
+ // "initialLeverage": "50",
3869
+ // "notionalCap": "5000",
3870
+ // "notionalFloor": "0",
3871
+ // "maintMarginRatio": "0.01",
3872
+ // "cum": "0.0"
3873
+ // },
3874
+ // {
3875
+ // "bracket": "2",
3876
+ // "initialLeverage": "20",
3877
+ // "notionalCap": "10000",
3878
+ // "notionalFloor": "5000",
3879
+ // "maintMarginRatio": "0.025",
3880
+ // "cum": "75.0"
3881
+ // },
3882
+ // ...
3883
+ //
3520
3884
  this.options['leverageBrackets'] = this.createSafeDictionary();
3521
3885
  for (let i = 0; i < response.length; i++) {
3522
3886
  const entry = response[i];
@@ -3542,12 +3906,11 @@ export default class aster extends Exchange {
3542
3906
  return this.signHash(this.keccakMessage(message), privateKey.slice(-64));
3543
3907
  }
3544
3908
  signWithdrawPayload(withdrawPayload, network) {
3545
- const zeroAddress = this.safeString(this.options, 'zeroAddress');
3546
3909
  const chainId = this.safeInteger(withdrawPayload, 'chainId');
3547
3910
  const domain = {
3548
3911
  'chainId': chainId,
3549
3912
  'name': 'Aster',
3550
- 'verifyingContract': zeroAddress,
3913
+ 'verifyingContract': this.safeString(this.options, 'zeroAddress'),
3551
3914
  'version': '1',
3552
3915
  };
3553
3916
  const messageTypes = {
@@ -3562,17 +3925,17 @@ export default class aster extends Exchange {
3562
3925
  { 'name': 'aster chain', 'type': 'string' },
3563
3926
  ],
3564
3927
  };
3565
- const withdraw = {
3928
+ const request = {
3566
3929
  'type': 'Withdraw',
3567
3930
  'destination': this.safeString(withdrawPayload, 'receiver'),
3568
3931
  'destination Chain': network,
3569
3932
  'token': this.safeString(withdrawPayload, 'asset'),
3570
3933
  'amount': this.safeString(withdrawPayload, 'amount'),
3571
3934
  'fee': this.safeString(withdrawPayload, 'fee'),
3572
- 'nonce': this.safeInteger(withdrawPayload, 'nonce'),
3935
+ 'nonce': this.safeInteger(withdrawPayload, 'userNonce'),
3573
3936
  'aster chain': 'Mainnet',
3574
3937
  };
3575
- const msg = this.ethEncodeStructuredData(domain, messageTypes, withdraw);
3938
+ const msg = this.ethEncodeStructuredData(domain, messageTypes, request);
3576
3939
  const signature = this.signMessage(msg, this.privateKey);
3577
3940
  return signature;
3578
3941
  }
@@ -3580,7 +3943,9 @@ export default class aster extends Exchange {
3580
3943
  * @method
3581
3944
  * @name aster#withdraw
3582
3945
  * @description make a withdrawal
3583
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#withdraw-user_data
3946
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#withdraw-user_data
3947
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/deposit%26withdrawal/#withdraw-by-fapiv3-evm-futures
3948
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/deposit%26withdrawal/#withdraw-by-fapiv3-evm-spot
3584
3949
  * @param {string} code unified currency code
3585
3950
  * @param {float} amount the amount to withdraw
3586
3951
  * @param {string} address the address to withdraw to
@@ -3591,12 +3956,13 @@ export default class aster extends Exchange {
3591
3956
  async withdraw(code, amount, address, tag = undefined, params = {}) {
3592
3957
  [tag, params] = this.handleWithdrawTagAndParams(tag, params);
3593
3958
  this.checkAddress(address);
3594
- await this.loadMarkets();
3959
+ await this.loadMarketsAndSignIn();
3595
3960
  const currency = this.currency(code);
3961
+ const nonce = this.milliseconds() * 1000;
3596
3962
  const request = {
3597
3963
  'asset': currency['id'],
3598
3964
  'receiver': address,
3599
- 'nonce': this.milliseconds() * 1000,
3965
+ 'userNonce': nonce.toString(),
3600
3966
  };
3601
3967
  let chainId = this.safeInteger(params, 'chainId');
3602
3968
  // TODO: check how ARBI signature would work
@@ -3619,23 +3985,32 @@ export default class aster extends Exchange {
3619
3985
  params = this.omit(params, ['chainId', 'network', 'fee']);
3620
3986
  request['amount'] = this.currencyToPrecision(code, amount, network);
3621
3987
  request['userSignature'] = this.signWithdrawPayload(request, network);
3622
- const response = await this.sapiPrivatePostV1AsterUserWithdraw(this.extend(request, params));
3988
+ const response = await this.sapiPrivatePostV3AsterUserWithdraw(this.extend(request, params));
3989
+ //
3990
+ // {
3991
+ // "withdrawId": "1097219372504338432",
3992
+ // "hash": "0x9e6baa3eb75d92a1164eef51a0cc97b9591930518ba3e8e5ab40ce524ba4e463"
3993
+ // }
3994
+ //
3995
+ return this.parseTransaction(response, currency);
3996
+ }
3997
+ parseTransaction(transaction, currency = undefined) {
3623
3998
  return {
3624
- 'info': response,
3625
- 'id': this.safeString(response, 'withdrawId'),
3626
- 'txid': this.safeString(response, 'hash'),
3999
+ 'info': transaction,
4000
+ 'id': this.safeString(transaction, 'withdrawId'),
4001
+ 'txid': this.safeString(transaction, 'hash'),
3627
4002
  'timestamp': undefined,
3628
4003
  'datetime': undefined,
3629
- 'network': network,
3630
- 'address': address,
3631
- 'addressTo': address,
4004
+ 'network': undefined,
4005
+ 'address': undefined,
4006
+ 'addressTo': undefined,
3632
4007
  'addressFrom': undefined,
3633
- 'tag': tag,
3634
- 'tagTo': tag,
4008
+ 'tag': undefined,
4009
+ 'tagTo': undefined,
3635
4010
  'tagFrom': undefined,
3636
4011
  'type': 'withdrawal',
3637
- 'amount': amount,
3638
- 'currency': code,
4012
+ 'amount': undefined,
4013
+ 'currency': undefined,
3639
4014
  'status': undefined,
3640
4015
  'updated': undefined,
3641
4016
  'internal': undefined,
@@ -3647,8 +4022,8 @@ export default class aster extends Exchange {
3647
4022
  * @method
3648
4023
  * @name aster#transfer
3649
4024
  * @description transfer currency internally between wallets on the same account
3650
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-spot-api.md#transfer-asset-to-other-address-trade
3651
- * @see https://github.com/asterdex/api-docs/blob/master/aster-finance-futures-api.md#transfer-between-futures-and-spot-user_data
4025
+ * @see https://asterdex.github.io/aster-api-website/spot-v3/account%26trades/#perp-spot-transfer-trade
4026
+ * @see https://asterdex.github.io/aster-api-website/futures-v3/account%26trades/#transfer-between-futures-and-spot-transfer
3652
4027
  * @param {string} code unified currency code
3653
4028
  * @param {float} amount amount to transfer
3654
4029
  * @param {string} fromAccount account to transfer from
@@ -3657,7 +4032,7 @@ export default class aster extends Exchange {
3657
4032
  * @returns {object} a [transfer structure]{@link https://docs.ccxt.com/#/?id=transfer-structure}
3658
4033
  */
3659
4034
  async transfer(code, amount, fromAccount, toAccount, params = {}) {
3660
- await this.loadMarkets();
4035
+ await this.loadMarketsAndSignIn();
3661
4036
  const currency = this.currency(code);
3662
4037
  const request = {
3663
4038
  'asset': currency['id'],
@@ -3678,47 +4053,36 @@ export default class aster extends Exchange {
3678
4053
  else if (fromId === 'FUTURE' && toId === 'SPOT') {
3679
4054
  type = 'FUTURE_SPOT';
3680
4055
  }
3681
- let response = undefined;
3682
- if (type !== undefined) {
3683
- const defaultClientTranId = this.numberToString(this.milliseconds());
3684
- const clientTranId = this.safeString(params, 'clientTranId', defaultClientTranId);
3685
- request['kindType'] = type;
3686
- request['clientTranId'] = clientTranId;
3687
- response = await this.fapiPrivatePostV1AssetWalletTransfer(this.extend(request, params));
3688
- }
3689
- else {
3690
- // transfer asset to other address
3691
- request['toAddress'] = toAccount;
3692
- response = await this.sapiPrivatePostV1AssetSendToAddress(this.extend(request, params));
4056
+ if (type === undefined) {
4057
+ throw new ArgumentsRequired(this.id + ' transfer() requires fromAccount and toAccount parameters to be either SPOT or FUTURE');
3693
4058
  }
3694
- //
3695
- // {
3696
- // "tranId":13526853623,
3697
- // "status": "SUCCESS"
3698
- // }
3699
- //
4059
+ let response = undefined;
4060
+ const defaultClientTranId = this.numberToString(this.milliseconds());
4061
+ const clientTranId = this.safeString(params, 'clientTranId', defaultClientTranId);
4062
+ request['kindType'] = type;
4063
+ request['clientTranId'] = clientTranId;
4064
+ response = await this.sapiPrivatePostV3AssetWalletTransfer(this.extend(request, params));
4065
+ return this.parseTransfer(response, currency);
4066
+ }
4067
+ parseTransfer(transfer, currency = undefined) {
4068
+ const currencyId = this.safeString(transfer, 'code');
3700
4069
  return {
3701
- 'info': response,
3702
- 'id': this.safeString(response, 'tranId'),
3703
- 'txid': undefined,
4070
+ 'info': transfer,
4071
+ 'id': this.safeString(transfer, 'tranId'),
3704
4072
  'timestamp': undefined,
3705
4073
  'datetime': undefined,
3706
- 'network': undefined,
3707
- 'address': undefined,
3708
- 'addressTo': fromAccount,
3709
- 'addressFrom': toAccount,
3710
- 'tag': undefined,
3711
- 'tagTo': undefined,
3712
- 'tagFrom': undefined,
3713
- 'type': 'transfer',
3714
- 'amount': amount,
3715
- 'currency': code,
3716
- 'status': undefined,
3717
- 'updated': undefined,
3718
- 'internal': undefined,
3719
- 'comment': undefined,
3720
- 'fee': undefined,
4074
+ 'currency': this.safeCurrencyCode(currencyId, currency),
4075
+ 'amount': undefined,
4076
+ 'fromAccount': undefined,
4077
+ 'toAccount': undefined,
4078
+ 'status': this.parseTransferStatus(this.safeString(transfer, 'status')),
4079
+ };
4080
+ }
4081
+ parseTransferStatus(status) {
4082
+ const statuses = {
4083
+ 'SUCCESS': 'ok',
3721
4084
  };
4085
+ return this.safeString(statuses, status, status);
3722
4086
  }
3723
4087
  hashMessage(binaryMessage) {
3724
4088
  // const binaryMessage = this.encode (message);
@@ -3745,78 +4109,174 @@ export default class aster extends Exchange {
3745
4109
  }
3746
4110
  else if (api === 'fapiPrivate' || api === 'sapiPrivate') {
3747
4111
  this.checkRequiredCredentials();
3748
- headers = {
3749
- 'X-MBX-APIKEY': this.apiKey,
4112
+ const nonce = this.milliseconds() * 1000;
4113
+ // Sign using EIP-712 typed data per the AsterSignTransaction spec
4114
+ const zeroAddress = this.safeString(this.options, 'zeroAddress', '0x0000000000000000000000000000000000000000');
4115
+ const v3ChainId = this.safeInteger(this.options, 'v3ChainId', 1666);
4116
+ const signerAddress = this.safeString(this.options, 'signerAddress');
4117
+ if (signerAddress === undefined) {
4118
+ throw new ArgumentsRequired(this.id + ' requires signerAddress in options when use v3 api');
4119
+ }
4120
+ const domain = {
4121
+ 'name': 'AsterSignTransaction',
4122
+ 'version': '1',
4123
+ 'chainId': v3ChainId,
4124
+ 'verifyingContract': zeroAddress,
3750
4125
  };
3751
- const timestamp = this.milliseconds();
3752
- // Nonce is in microseconds
3753
- const nonce = this.microseconds();
3754
- const defaultRecvWindow = this.safeInteger(this.options, 'recvWindow');
3755
- let extendedParams = this.extend({
3756
- 'timestamp': timestamp,
4126
+ let messageTypes = {
4127
+ 'Message': [
4128
+ { 'name': 'msg', 'type': 'string' },
4129
+ ],
4130
+ };
4131
+ // Build v3 params: original endpoint params + nonce (macroseconds) + user + signer
4132
+ // Note: timestamp and recvWindow are not used for v3; nonce replaces timestamp
4133
+ const finalParams = this.extend({
4134
+ 'nonce': nonce.toString(),
4135
+ 'user': this.walletAddress,
4136
+ 'signer': signerAddress,
3757
4137
  }, params);
3758
- if (defaultRecvWindow !== undefined) {
3759
- extendedParams['recvWindow'] = defaultRecvWindow;
3760
- }
3761
- const recvWindow = this.safeInteger(params, 'recvWindow');
3762
- if (recvWindow !== undefined) {
3763
- extendedParams['recvWindow'] = recvWindow;
3764
- }
3765
- let query = undefined;
3766
- if ((method === 'DELETE') && (path === 'v1/batchOrders')) {
3767
- const orderidlist = this.safeList(extendedParams, 'orderIdList', []);
3768
- const origclientorderidlist = this.safeList(extendedParams, 'origClientOrderIdList', []);
3769
- extendedParams = this.omit(extendedParams, ['orderIdList', 'origClientOrderIdList']);
3770
- query = this.rawencode(extendedParams);
3771
- const orderidlistLength = orderidlist.length;
3772
- const origclientorderidlistLength = origclientorderidlist.length;
3773
- if (orderidlistLength > 0) {
3774
- query = query + '&' + 'orderidlist=%5B' + orderidlist.join('%2C') + '%5D';
3775
- }
3776
- if (origclientorderidlistLength > 0) {
3777
- query = query + '&' + 'origclientorderidlist=%5B' + origclientorderidlist.join('%2C') + '%5D';
3778
- }
3779
- }
3780
- else {
3781
- query = this.rawencode(extendedParams);
3782
- }
3783
- let signature = '';
3784
- if (path.indexOf('v3') >= 0) {
3785
- const signerAddress = this.options['signerAddress'];
3786
- if (signerAddress === undefined) {
3787
- throw new ArgumentsRequired(this.id + ' requires signerAddress in options when use v3 api');
3788
- }
3789
- // the keys order matter
3790
- const keys = Object.keys(extendedParams);
3791
- const sortedKeys = this.sort(keys);
3792
- const signingPayload = {};
3793
- for (let i = 0; i < sortedKeys.length; i++) {
3794
- const key = sortedKeys[i];
3795
- signingPayload[key] = extendedParams[key].toString();
3796
- }
3797
- const signingHash = this.hashMessage(this.hash(this.ethAbiEncode([
3798
- 'string', 'address', 'address', 'uint256',
3799
- ], [this.json(signingPayload), this.walletAddress, signerAddress, nonce]), keccak, 'binary'));
3800
- signature = this.signHash(signingHash, this.privateKey);
3801
- extendedParams['user'] = this.walletAddress;
3802
- extendedParams['signer'] = signerAddress;
3803
- extendedParams['nonce'] = nonce;
3804
- query = this.rawencode(extendedParams);
4138
+ let paramString = undefined;
4139
+ let paramsToEncode = undefined;
4140
+ const isApproveBuilder = (path.indexOf('/approveBuilder') >= 0);
4141
+ if (isApproveBuilder) {
4142
+ // domain['name'] = 'Aster';
4143
+ messageTypes = {
4144
+ 'ApproveBuilder': [
4145
+ { 'name': 'Builder', 'type': 'string' },
4146
+ { 'name': 'MaxFeeRate', 'type': 'string' },
4147
+ { 'name': 'BuilderName', 'type': 'string' },
4148
+ { 'name': 'AsterChain', 'type': 'string' },
4149
+ { 'name': 'User', 'type': 'string' },
4150
+ { 'name': 'Nonce', 'type': 'uint256' },
4151
+ ],
4152
+ };
4153
+ delete finalParams['signer']; // signer is not needed for approveBuilder endpoint
4154
+ paramString = this.encodeValuesWithJson(finalParams);
4155
+ paramsToEncode = this.capitalizeKeys(finalParams);
3805
4156
  }
3806
4157
  else {
3807
- signature = this.hmac(this.encode(query), this.encode(this.secret), sha256);
4158
+ paramString = this.encodeValuesWithJson(finalParams);
4159
+ paramsToEncode = { 'msg': paramString };
3808
4160
  }
3809
- query += '&' + 'signature=' + signature;
4161
+ const encodedMessage = this.ethEncodeStructuredData(domain, messageTypes, paramsToEncode);
4162
+ const signature = this.signMessage(encodedMessage, this.privateKey);
4163
+ const queryString = paramString + '&' + 'signature=' + signature;
3810
4164
  if (method === 'GET') {
3811
- url += '?' + query;
4165
+ url += '?' + queryString;
3812
4166
  }
3813
4167
  else {
3814
- body = query;
4168
+ headers = {};
3815
4169
  headers['Content-Type'] = 'application/x-www-form-urlencoded';
4170
+ body = queryString;
3816
4171
  }
3817
4172
  }
3818
4173
  return { 'url': url, 'method': method, 'body': body, 'headers': headers };
3819
4174
  }
4175
+ encodeValuesWithJson(values) {
4176
+ let encodedString = '';
4177
+ const keys = Object.keys(values);
4178
+ for (let i = 0; i < keys.length; i++) {
4179
+ const key = keys[i];
4180
+ const value = values[key];
4181
+ const isObj = Array.isArray(value) || this.isDictionary(value);
4182
+ const valueJsonified = isObj ? this.json(value) : value.toString();
4183
+ const encoded = this.encodeURIComponent(valueJsonified);
4184
+ encodedString += key + '=' + encoded + '&';
4185
+ }
4186
+ return encodedString.slice(0, -1);
4187
+ }
4188
+ capitalizeKeys(dict) {
4189
+ const capitalized = {};
4190
+ const keys = Object.keys(dict);
4191
+ for (let i = 0; i < keys.length; i++) {
4192
+ const key = keys[i];
4193
+ const value = dict[key];
4194
+ const capitalizedKey = this.capitalize(key);
4195
+ capitalized[capitalizedKey] = value;
4196
+ }
4197
+ return capitalized;
4198
+ }
4199
+ async loadMarketsAndSignIn() {
4200
+ await Promise.all([this.loadMarkets(), this.signIn()]);
4201
+ }
4202
+ /**
4203
+ * @method
4204
+ * @name aster#signIn
4205
+ * @description sign in, must be called prior to using other authenticated methods
4206
+ * @see https://asterdex.github.io/aster-api-website/asterCode/integration-flow/
4207
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
4208
+ * @returns response from exchange
4209
+ */
4210
+ async signIn(params = {}) {
4211
+ if (this.isEmptyString(this.privateKey)) {
4212
+ if (!this.isEmptyString(this.apiKey) || !this.isEmptyString(this.secret)) {
4213
+ throw new NotSupported(this.id + 'after the latest upgrade (v4.5.52), CCXT now expects the l1 private key to be provided in the credentials.');
4214
+ }
4215
+ return false;
4216
+ }
4217
+ if (this.privateKey.length > 66) {
4218
+ throw new NotSupported(this.id + ' after the latest update (v4.5.52), CCXT now expects the l1 private key to be provided in the credentials.');
4219
+ }
4220
+ await this.initializeClient(params);
4221
+ return true;
4222
+ }
4223
+ async initializeClient(params = {}) {
4224
+ const builderFee = this.safeBool(params, 'builderFee', this.safeBool(this.options, 'builderFee', true)); // we shouldn't omit here
4225
+ if (!builderFee) {
4226
+ return false; // skip if builder fee is not enabled
4227
+ }
4228
+ const approvedBuilderFee = this.safeBool(this.options, 'approvedBuilderFee', false);
4229
+ if (approvedBuilderFee) {
4230
+ return true; // skip if builder fee is already approved
4231
+ }
4232
+ const result = await this.fapiPrivateGetV3Builder();
4233
+ //
4234
+ // [
4235
+ // {
4236
+ // "userAddress": "0x35a5B33Be664B09F78b5089eb6185f71c8a7f11f",
4237
+ // "builderAddress": "0x1F5877C19e3777Cfd15F9d57253eA4aA5254Ec39",
4238
+ // "maxFeeRate": "0.001",
4239
+ // "builderName": "ccxt"
4240
+ // }
4241
+ // ]
4242
+ //
4243
+ const approvedBuilders = result;
4244
+ const length = approvedBuilders.length;
4245
+ let found = false;
4246
+ for (let i = 0; i < length; i++) {
4247
+ const builderInfo = this.safeDict(approvedBuilders, i, {});
4248
+ const builderAccountId = this.safeString(builderInfo, 'builderAddress');
4249
+ if (builderAccountId === this.safeString(this.options, 'builder')) {
4250
+ found = true;
4251
+ break;
4252
+ }
4253
+ }
4254
+ if (!found) {
4255
+ this.options['approvedBuilderFee'] = true;
4256
+ try {
4257
+ const request = {
4258
+ 'builder': this.safeString(this.options, 'builder'),
4259
+ 'builderName': this.safeString(this.options, 'builderName', 'ccxt'),
4260
+ 'maxFeeRate': this.safeString(this.options, 'builderRate'),
4261
+ 'signatureChainId': this.safeInteger(this.options, 'v3ChainId', 1666),
4262
+ 'asterChain': 'Mainnet',
4263
+ };
4264
+ const authResponse = await this.fapiPrivatePostV3ApproveBuilder(this.extend(request, params));
4265
+ //
4266
+ // {"code": 200,"msg": "success"}
4267
+ //
4268
+ const codeRes = this.safeInteger(authResponse, 'code');
4269
+ if (codeRes !== 200) {
4270
+ throw new ExchangeError('Builder authorization failed, ' + this.json(authResponse));
4271
+ }
4272
+ }
4273
+ catch (e) {
4274
+ this.options['approvedBuilderFee'] = false;
4275
+ this.options['builderFee'] = false; // disable if err
4276
+ }
4277
+ }
4278
+ return undefined; // just c#
4279
+ }
3820
4280
  handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
3821
4281
  if (response === undefined) {
3822
4282
  return undefined; // fallback to default error handler