ccxt 4.4.70__py2.py3-none-any.whl → 4.4.72__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. ccxt/__init__.py +1 -3
  2. ccxt/abstract/bingx.py +1 -0
  3. ccxt/abstract/bitmart.py +1 -0
  4. ccxt/abstract/poloniex.py +36 -0
  5. ccxt/ascendex.py +1 -1
  6. ccxt/async_support/__init__.py +1 -3
  7. ccxt/async_support/ascendex.py +1 -1
  8. ccxt/async_support/base/exchange.py +3 -3
  9. ccxt/async_support/binance.py +107 -102
  10. ccxt/async_support/bingx.py +65 -43
  11. ccxt/async_support/bitfinex.py +1 -1
  12. ccxt/async_support/bitfinex1.py +1 -1
  13. ccxt/async_support/bitget.py +0 -3
  14. ccxt/async_support/bitmart.py +12 -1
  15. ccxt/async_support/bitopro.py +1 -0
  16. ccxt/async_support/bitrue.py +1 -0
  17. ccxt/async_support/bl3p.py +2 -2
  18. ccxt/async_support/cex.py +2 -0
  19. ccxt/async_support/coinbase.py +3 -2
  20. ccxt/async_support/coinbaseexchange.py +4 -2
  21. ccxt/async_support/coinbaseinternational.py +3 -2
  22. ccxt/async_support/coinex.py +1 -1
  23. ccxt/async_support/deribit.py +3 -1
  24. ccxt/async_support/derive.py +11 -7
  25. ccxt/async_support/gate.py +3 -0
  26. ccxt/async_support/gemini.py +2 -1
  27. ccxt/async_support/hashkey.py +4 -2
  28. ccxt/async_support/hitbtc.py +1 -1
  29. ccxt/async_support/hyperliquid.py +38 -0
  30. ccxt/async_support/kraken.py +78 -6
  31. ccxt/async_support/krakenfutures.py +4 -0
  32. ccxt/async_support/kucoin.py +5 -3
  33. ccxt/async_support/kuna.py +1 -1
  34. ccxt/async_support/mexc.py +9 -5
  35. ccxt/async_support/ndax.py +1 -1
  36. ccxt/async_support/okcoin.py +4 -0
  37. ccxt/async_support/okx.py +79 -76
  38. ccxt/async_support/paradex.py +65 -7
  39. ccxt/async_support/paymium.py +1 -1
  40. ccxt/async_support/poloniex.py +1265 -86
  41. ccxt/async_support/upbit.py +1 -1
  42. ccxt/async_support/whitebit.py +102 -4
  43. ccxt/async_support/woo.py +3 -1
  44. ccxt/async_support/woofipro.py +1 -1
  45. ccxt/async_support/yobit.py +2 -1
  46. ccxt/base/errors.py +6 -0
  47. ccxt/base/exchange.py +31 -4
  48. ccxt/base/types.py +28 -0
  49. ccxt/binance.py +107 -102
  50. ccxt/bingx.py +65 -43
  51. ccxt/bitfinex.py +1 -1
  52. ccxt/bitfinex1.py +1 -1
  53. ccxt/bitget.py +0 -3
  54. ccxt/bitmart.py +12 -1
  55. ccxt/bitopro.py +1 -0
  56. ccxt/bitrue.py +1 -0
  57. ccxt/bl3p.py +2 -2
  58. ccxt/cex.py +2 -0
  59. ccxt/coinbase.py +3 -2
  60. ccxt/coinbaseexchange.py +4 -2
  61. ccxt/coinbaseinternational.py +3 -2
  62. ccxt/coinex.py +1 -1
  63. ccxt/deribit.py +3 -1
  64. ccxt/derive.py +11 -7
  65. ccxt/gate.py +3 -0
  66. ccxt/gemini.py +2 -1
  67. ccxt/hashkey.py +4 -2
  68. ccxt/hitbtc.py +1 -1
  69. ccxt/hyperliquid.py +38 -0
  70. ccxt/kraken.py +78 -6
  71. ccxt/krakenfutures.py +4 -0
  72. ccxt/kucoin.py +5 -3
  73. ccxt/kuna.py +1 -1
  74. ccxt/mexc.py +9 -5
  75. ccxt/ndax.py +1 -1
  76. ccxt/okcoin.py +4 -0
  77. ccxt/okx.py +79 -76
  78. ccxt/paradex.py +65 -7
  79. ccxt/paymium.py +1 -1
  80. ccxt/poloniex.py +1264 -86
  81. ccxt/pro/__init__.py +1 -3
  82. ccxt/pro/binance.py +102 -102
  83. ccxt/pro/bingx.py +63 -52
  84. ccxt/pro/bitmart.py +15 -7
  85. ccxt/pro/derive.py +2 -2
  86. ccxt/pro/krakenfutures.py +1 -1
  87. ccxt/test/tests_async.py +1 -0
  88. ccxt/test/tests_sync.py +1 -0
  89. ccxt/upbit.py +1 -1
  90. ccxt/whitebit.py +102 -4
  91. ccxt/woo.py +3 -1
  92. ccxt/woofipro.py +1 -1
  93. ccxt/yobit.py +2 -1
  94. {ccxt-4.4.70.dist-info → ccxt-4.4.72.dist-info}/METADATA +6 -9
  95. {ccxt-4.4.70.dist-info → ccxt-4.4.72.dist-info}/RECORD +98 -99
  96. ccxt/abstract/poloniexfutures.py +0 -48
  97. {ccxt-4.4.70.dist-info → ccxt-4.4.72.dist-info}/LICENSE.txt +0 -0
  98. {ccxt-4.4.70.dist-info → ccxt-4.4.72.dist-info}/WHEEL +0 -0
  99. {ccxt-4.4.70.dist-info → ccxt-4.4.72.dist-info}/top_level.txt +0 -0
@@ -5,8 +5,9 @@
5
5
 
6
6
  from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.poloniex import ImplicitAPI
8
+ import asyncio
8
9
  import hashlib
9
- from ccxt.base.types import Any, Balances, Currencies, Currency, DepositAddress, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction, TransferEntry
10
+ from ccxt.base.types import Any, Balances, Bool, Currencies, Currency, DepositAddress, Int, Leverage, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction, TransferEntry
10
11
  from typing import List
11
12
  from ccxt.base.errors import ExchangeError
12
13
  from ccxt.base.errors import AuthenticationError
@@ -41,21 +42,25 @@ class poloniex(Exchange, ImplicitAPI):
41
42
  'CORS': None,
42
43
  'spot': True,
43
44
  'margin': None, # has but not fully implemented
44
- 'swap': False,
45
- 'future': False,
45
+ 'swap': True,
46
+ 'future': True,
46
47
  'option': False,
48
+ 'addMargin': True,
47
49
  'cancelAllOrders': True,
48
50
  'cancelOrder': True,
51
+ 'cancelOrders': None, # not yet implemented, because RL is worse than cancelOrder
49
52
  'createDepositAddress': True,
50
53
  'createMarketBuyOrderWithCost': True,
51
54
  'createMarketOrderWithCost': False,
52
55
  'createMarketSellOrderWithCost': False,
53
56
  'createOrder': True,
57
+ 'createOrders': None, # not yet implemented, because RL is worse than createOrder
54
58
  'createStopOrder': True,
55
59
  'createTriggerOrder': True,
56
60
  'editOrder': True,
57
61
  'fetchBalance': True,
58
62
  'fetchClosedOrder': False,
63
+ 'fetchClosedOrders': True,
59
64
  'fetchCurrencies': True,
60
65
  'fetchDepositAddress': True,
61
66
  'fetchDepositAddresses': False,
@@ -69,20 +74,24 @@ class poloniex(Exchange, ImplicitAPI):
69
74
  'fetchFundingIntervals': False,
70
75
  'fetchFundingRate': False,
71
76
  'fetchFundingRateHistory': False,
72
- 'fetchFundingRates': False,
77
+ 'fetchFundingRates': None, # has but not implemented
78
+ 'fetchLedger': None, # has but not implemented
79
+ 'fetchLeverage': True,
80
+ 'fetchLiquidations': None, # has but not implemented
73
81
  'fetchMarginMode': False,
74
82
  'fetchMarkets': True,
75
83
  'fetchMyTrades': True,
76
84
  'fetchOHLCV': True,
77
85
  'fetchOpenInterestHistory': False,
78
86
  'fetchOpenOrder': False,
79
- 'fetchOpenOrders': True, # True endpoint for open orders
87
+ 'fetchOpenOrders': True,
80
88
  'fetchOrder': True,
81
89
  'fetchOrderBook': True,
82
90
  'fetchOrderBooks': False,
83
- 'fetchOrderTrades': True, # True endpoint for trades of a single open or closed order
91
+ 'fetchOrderTrades': True,
84
92
  'fetchPosition': False,
85
- 'fetchPositionMode': False,
93
+ 'fetchPositionMode': True,
94
+ 'fetchPositions': True,
86
95
  'fetchTicker': True,
87
96
  'fetchTickers': True,
88
97
  'fetchTime': True,
@@ -93,33 +102,37 @@ class poloniex(Exchange, ImplicitAPI):
93
102
  'fetchTransfer': False,
94
103
  'fetchTransfers': False,
95
104
  'fetchWithdrawals': True,
105
+ 'reduceMargin': True,
96
106
  'sandbox': True,
107
+ 'setLeverage': True,
108
+ 'setPositionMode': True,
97
109
  'transfer': True,
98
110
  'withdraw': True,
99
111
  },
100
112
  'timeframes': {
101
113
  '1m': 'MINUTE_1',
102
114
  '5m': 'MINUTE_5',
103
- '10m': 'MINUTE_10',
115
+ '10m': 'MINUTE_10', # not in swap
104
116
  '15m': 'MINUTE_15',
105
117
  '30m': 'MINUTE_30',
106
118
  '1h': 'HOUR_1',
107
119
  '2h': 'HOUR_2',
108
120
  '4h': 'HOUR_4',
109
- '6h': 'HOUR_6',
121
+ '6h': 'HOUR_6', # not in swap
110
122
  '12h': 'HOUR_12',
111
123
  '1d': 'DAY_1',
112
124
  '3d': 'DAY_3',
113
125
  '1w': 'WEEK_1',
114
- '1M': 'MONTH_1',
126
+ '1M': 'MONTH_1', # not in swap
115
127
  },
116
128
  'urls': {
117
129
  'logo': 'https://user-images.githubusercontent.com/1294454/27766817-e9456312-5ee6-11e7-9b3c-b628ca5626a5.jpg',
118
130
  'api': {
119
- 'rest': 'https://api.poloniex.com',
131
+ 'spot': 'https://api.poloniex.com',
132
+ 'swap': 'https://api.poloniex.com',
120
133
  },
121
134
  'test': {
122
- 'rest': 'https://sand-spot-api-gateway.poloniex.com',
135
+ 'spot': 'https://sand-spot-api-gateway.poloniex.com',
123
136
  },
124
137
  'www': 'https://www.poloniex.com',
125
138
  'doc': 'https://api-docs.poloniex.com/spot/',
@@ -206,6 +219,55 @@ class poloniex(Exchange, ImplicitAPI):
206
219
  'smartorders/{id}': 20,
207
220
  },
208
221
  },
222
+ 'swapPublic': {
223
+ 'get': {
224
+ # 300 calls / second
225
+ 'v3/market/allInstruments': 2 / 3,
226
+ 'v3/market/instruments': 2 / 3,
227
+ 'v3/market/orderBook': 2 / 3,
228
+ 'v3/market/candles': 10, # candles have differnt RL
229
+ 'v3/market/indexPriceCandlesticks': 10,
230
+ 'v3/market/premiumIndexCandlesticks': 10,
231
+ 'v3/market/markPriceCandlesticks': 10,
232
+ 'v3/market/trades': 2 / 3,
233
+ 'v3/market/liquidationOrder': 2 / 3,
234
+ 'v3/market/tickers': 2 / 3,
235
+ 'v3/market/markPrice': 2 / 3,
236
+ 'v3/market/indexPrice': 2 / 3,
237
+ 'v3/market/indexPriceComponents': 2 / 3,
238
+ 'v3/market/fundingRate': 2 / 3,
239
+ 'v3/market/openInterest': 2 / 3,
240
+ 'v3/market/insurance': 2 / 3,
241
+ 'v3/market/riskLimit': 2 / 3,
242
+ },
243
+ },
244
+ 'swapPrivate': {
245
+ 'get': {
246
+ 'v3/account/balance': 4,
247
+ 'v3/account/bills': 20,
248
+ 'v3/trade/order/opens': 20,
249
+ 'v3/trade/order/trades': 20,
250
+ 'v3/trade/order/history': 20,
251
+ 'v3/trade/position/opens': 20,
252
+ 'v3/trade/position/history': 20, # todo: method for self
253
+ 'v3/position/leverages': 20,
254
+ 'v3/position/mode': 20,
255
+ },
256
+ 'post': {
257
+ 'v3/trade/order': 4,
258
+ 'v3/trade/orders': 40,
259
+ 'v3/trade/position': 20,
260
+ 'v3/trade/positionAll': 100,
261
+ 'v3/position/leverage': 20,
262
+ 'v3/position/mode': 20,
263
+ 'v3/trade/position/margin': 20,
264
+ },
265
+ 'delete': {
266
+ 'v3/trade/order': 2,
267
+ 'v3/trade/batchOrders': 20,
268
+ 'v3/trade/allOrders': 20,
269
+ },
270
+ },
209
271
  },
210
272
  'fees': {
211
273
  'trading': {
@@ -254,6 +316,7 @@ class poloniex(Exchange, ImplicitAPI):
254
316
  'UST': 'USTC',
255
317
  },
256
318
  'options': {
319
+ 'defaultType': 'spot',
257
320
  'createMarketBuyOrderRequiresPrice': True,
258
321
  'networks': {
259
322
  'BEP20': 'BSC',
@@ -300,7 +363,7 @@ class poloniex(Exchange, ImplicitAPI):
300
363
  'timeInForce': {
301
364
  'IOC': True,
302
365
  'FOK': True,
303
- 'PO': False,
366
+ 'PO': True,
304
367
  'GTD': False,
305
368
  },
306
369
  'hedged': False,
@@ -311,7 +374,9 @@ class poloniex(Exchange, ImplicitAPI):
311
374
  'trailing': False,
312
375
  'iceberg': False,
313
376
  },
314
- 'createOrders': None,
377
+ 'createOrders': {
378
+ 'max': 20,
379
+ },
315
380
  'fetchMyTrades': {
316
381
  'marginMode': False,
317
382
  'limit': 1000,
@@ -341,13 +406,51 @@ class poloniex(Exchange, ImplicitAPI):
341
406
  'spot': {
342
407
  'extends': 'default',
343
408
  },
409
+ 'forContracts': {
410
+ 'extends': 'default',
411
+ 'createOrder': {
412
+ 'marginMode': True,
413
+ 'triggerPrice': False,
414
+ 'hedged': True,
415
+ 'stpMode': True, # todo
416
+ 'marketBuyByCost': False,
417
+ },
418
+ 'createOrders': {
419
+ 'max': 10,
420
+ },
421
+ 'fetchOpenOrders': {
422
+ 'limit': 100,
423
+ },
424
+ 'fetchClosedOrders': {
425
+ 'marginMode': False,
426
+ 'limit': 100,
427
+ 'daysBack': None,
428
+ 'daysBackCanceled': 1 / 6,
429
+ 'untilDays': None,
430
+ 'trigger': False,
431
+ 'trailing': False,
432
+ 'symbolRequired': False,
433
+ },
434
+ 'fetchMyTrades': {
435
+ 'limit': 100,
436
+ 'untilDays': 90,
437
+ },
438
+ },
344
439
  'swap': {
345
- 'linear': None,
346
- 'inverse': None,
440
+ 'linear': {
441
+ 'extends': 'forContracts',
442
+ },
443
+ 'inverse': {
444
+ 'extends': 'forContracts',
445
+ },
347
446
  },
348
447
  'future': {
349
- 'linear': None,
350
- 'inverse': None,
448
+ 'linear': {
449
+ 'extends': 'forContracts',
450
+ },
451
+ 'inverse': {
452
+ 'extends': 'forContracts',
453
+ },
351
454
  },
352
455
  },
353
456
  'precisionMode': TICK_SIZE,
@@ -467,6 +570,8 @@ class poloniex(Exchange, ImplicitAPI):
467
570
  })
468
571
 
469
572
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
573
+ #
574
+ # spot:
470
575
  #
471
576
  # [
472
577
  # [
@@ -487,6 +592,31 @@ class poloniex(Exchange, ImplicitAPI):
487
592
  # ]
488
593
  # ]
489
594
  #
595
+ # contract:
596
+ #
597
+ # [
598
+ # "84207.02",
599
+ # "84320.85",
600
+ # "84207.02",
601
+ # "84253.83",
602
+ # "3707.5395",
603
+ # "44",
604
+ # "14",
605
+ # "1740770040000",
606
+ # "1740770099999",
607
+ # ],
608
+ #
609
+ ohlcvLength = len(ohlcv)
610
+ isContract = ohlcvLength == 9
611
+ if isContract:
612
+ return [
613
+ self.safe_integer(ohlcv, 7),
614
+ self.safe_number(ohlcv, 2),
615
+ self.safe_number(ohlcv, 1),
616
+ self.safe_number(ohlcv, 0),
617
+ self.safe_number(ohlcv, 3),
618
+ self.safe_number(ohlcv, 5),
619
+ ]
490
620
  return [
491
621
  self.safe_integer(ohlcv, 12),
492
622
  self.safe_number(ohlcv, 2),
@@ -501,6 +631,7 @@ class poloniex(Exchange, ImplicitAPI):
501
631
  fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
502
632
 
503
633
  https://api-docs.poloniex.com/spot/api/public/market-data#candles
634
+ https://api-docs.poloniex.com/v3/futures/api/market/get-kline-data
504
635
 
505
636
  :param str symbol: unified symbol of the market to fetch OHLCV data for
506
637
  :param str timeframe: the length of time each candle represents
@@ -521,12 +652,37 @@ class poloniex(Exchange, ImplicitAPI):
521
652
  'symbol': market['id'],
522
653
  'interval': self.safe_string(self.timeframes, timeframe, timeframe),
523
654
  }
655
+ keyStart = 'startTime' if market['spot'] else 'sTime'
656
+ keyEnd = 'endTime' if market['spot'] else 'eTime'
524
657
  if since is not None:
525
- request['startTime'] = since
658
+ request[keyStart] = since
526
659
  if limit is not None:
527
660
  # limit should in between 100 and 500
528
661
  request['limit'] = limit
529
- request, params = self.handle_until_option('endTime', request, params)
662
+ request, params = self.handle_until_option(keyEnd, request, params)
663
+ if market['contract']:
664
+ if self.in_array(timeframe, ['10m', '1M']):
665
+ raise NotSupported(self.id + ' ' + timeframe + ' ' + market['type'] + ' fetchOHLCV is not supported')
666
+ responseRaw = await self.swapPublicGetV3MarketCandles(self.extend(request, params))
667
+ #
668
+ # {
669
+ # code: "200",
670
+ # msg: "Success",
671
+ # data: [
672
+ # [
673
+ # "84207.02",
674
+ # "84320.85",
675
+ # "84207.02",
676
+ # "84253.83",
677
+ # "3707.5395",
678
+ # "44",
679
+ # "14",
680
+ # "1740770040000",
681
+ # "1740770099999",
682
+ # ],
683
+ #
684
+ data = self.safe_list(responseRaw, 'data')
685
+ return self.parse_ohlcvs(data, market, timeframe, since, limit)
530
686
  response = await self.publicGetMarketsSymbolCandles(self.extend(request, params))
531
687
  #
532
688
  # [
@@ -562,10 +718,16 @@ class poloniex(Exchange, ImplicitAPI):
562
718
  retrieves data on all markets for poloniex
563
719
 
564
720
  https://api-docs.poloniex.com/spot/api/public/reference-data#symbol-information
721
+ https://api-docs.poloniex.com/v3/futures/api/market/get-all-product-info
565
722
 
566
723
  :param dict [params]: extra parameters specific to the exchange API endpoint
567
724
  :returns dict[]: an array of objects representing market data
568
725
  """
726
+ promises = [self.fetch_spot_markets(params), self.fetch_swap_markets(params)]
727
+ results = await asyncio.gather(*promises)
728
+ return self.array_concat(results[0], results[1])
729
+
730
+ async def fetch_spot_markets(self, params={}) -> List[Market]:
569
731
  markets = await self.publicGetMarkets(params)
570
732
  #
571
733
  # [
@@ -592,7 +754,57 @@ class poloniex(Exchange, ImplicitAPI):
592
754
  #
593
755
  return self.parse_markets(markets)
594
756
 
757
+ async def fetch_swap_markets(self, params={}) -> List[Market]:
758
+ # do similar per https://api-docs.poloniex.com/v3/futures/api/market/get-product-info
759
+ response = await self.swapPublicGetV3MarketAllInstruments(params)
760
+ #
761
+ # {
762
+ # "code": "200",
763
+ # "msg": "Success",
764
+ # "data": [
765
+ # {
766
+ # "symbol": "BNB_USDT_PERP",
767
+ # "bAsset": ".PBNBUSDT",
768
+ # "bCcy": "BNB",
769
+ # "qCcy": "USDT",
770
+ # "visibleStartTime": "1620390600000",
771
+ # "tradableStartTime": "1620390600000",
772
+ # "sCcy": "USDT",
773
+ # "tSz": "0.001",
774
+ # "pxScale": "0.001,0.01,0.1,1,10",
775
+ # "lotSz": "1",
776
+ # "minSz": "1",
777
+ # "ctVal": "0.1",
778
+ # "status": "OPEN",
779
+ # "oDate": "1620287590000",
780
+ # "maxPx": "1000000",
781
+ # "minPx": "0.001",
782
+ # "maxQty": "1000000",
783
+ # "minQty": "1",
784
+ # "maxLever": "50",
785
+ # "lever": "10",
786
+ # "ctType": "LINEAR",
787
+ # "alias": "",
788
+ # "iM": "0.02",
789
+ # "mM": "0.0115",
790
+ # "mR": "2000",
791
+ # "buyLmt": "",
792
+ # "sellLmt": "",
793
+ # "ordPxRange": "0.05",
794
+ # "marketMaxQty": "2800",
795
+ # "limitMaxQty": "1000000"
796
+ # },
797
+ #
798
+ markets = self.safe_list(response, 'data')
799
+ return self.parse_markets(markets)
800
+
595
801
  def parse_market(self, market: dict) -> Market:
802
+ if 'ctType' in market:
803
+ return self.parse_swap_market(market)
804
+ else:
805
+ return self.parse_spot_market(market)
806
+
807
+ def parse_spot_market(self, market: dict) -> Market:
596
808
  id = self.safe_string(market, 'symbol')
597
809
  baseId = self.safe_string(market, 'baseCurrencyName')
598
810
  quoteId = self.safe_string(market, 'quoteCurrencyName')
@@ -648,6 +860,113 @@ class poloniex(Exchange, ImplicitAPI):
648
860
  'info': market,
649
861
  }
650
862
 
863
+ def parse_swap_market(self, market: dict) -> Market:
864
+ #
865
+ # {
866
+ # "symbol": "BNB_USDT_PERP",
867
+ # "bAsset": ".PBNBUSDT",
868
+ # "bCcy": "BNB",
869
+ # "qCcy": "USDT",
870
+ # "visibleStartTime": "1620390600000",
871
+ # "tradableStartTime": "1620390600000",
872
+ # "sCcy": "USDT",
873
+ # "tSz": "0.001",
874
+ # "pxScale": "0.001,0.01,0.1,1,10",
875
+ # "lotSz": "1",
876
+ # "minSz": "1",
877
+ # "ctVal": "0.1",
878
+ # "status": "OPEN",
879
+ # "oDate": "1620287590000",
880
+ # "maxPx": "1000000",
881
+ # "minPx": "0.001",
882
+ # "maxQty": "1000000",
883
+ # "minQty": "1",
884
+ # "maxLever": "50",
885
+ # "lever": "10",
886
+ # "ctType": "LINEAR",
887
+ # "alias": "",
888
+ # "iM": "0.02",
889
+ # "mM": "0.0115",
890
+ # "mR": "2000",
891
+ # "buyLmt": "",
892
+ # "sellLmt": "",
893
+ # "ordPxRange": "0.05",
894
+ # "marketMaxQty": "2800",
895
+ # "limitMaxQty": "1000000"
896
+ # },
897
+ #
898
+ id = self.safe_string(market, 'symbol')
899
+ baseId = self.safe_string(market, 'bCcy')
900
+ quoteId = self.safe_string(market, 'qCcy')
901
+ settleId = self.safe_string(market, 'sCcy')
902
+ base = self.safe_currency_code(baseId)
903
+ quote = self.safe_currency_code(quoteId)
904
+ settle = self.safe_currency_code(settleId)
905
+ status = self.safe_string(market, 'status')
906
+ active = status == 'OPEN'
907
+ linear = market['ctType'] == 'LINEAR'
908
+ symbol = base + '/' + quote
909
+ if linear:
910
+ symbol += ':' + settle
911
+ else:
912
+ # actually, exchange does not have any inverse future now
913
+ symbol += ':' + base
914
+ alias = self.safe_string(market, 'alias')
915
+ type = 'swap'
916
+ if alias is not None:
917
+ type = 'future'
918
+ return {
919
+ 'id': id,
920
+ 'symbol': symbol,
921
+ 'base': base,
922
+ 'quote': quote,
923
+ 'settle': settle,
924
+ 'baseId': baseId,
925
+ 'quoteId': quoteId,
926
+ 'settleId': settleId,
927
+ 'type': 'future' if (type == 'future') else 'swap',
928
+ 'spot': False,
929
+ 'margin': False,
930
+ 'swap': type == 'swap',
931
+ 'future': type == 'future',
932
+ 'option': False,
933
+ 'active': active,
934
+ 'contract': True,
935
+ 'linear': linear,
936
+ 'inverse': not linear,
937
+ 'contractSize': self.safe_number(market, 'ctVal'),
938
+ 'expiry': None,
939
+ 'expiryDatetime': None,
940
+ 'strike': None,
941
+ 'optionType': None,
942
+ 'taker': self.safe_number(market, 'tFee'),
943
+ 'maker': self.safe_number(market, 'mFee'),
944
+ 'precision': {
945
+ 'amount': self.safe_number(market, 'lotSz'),
946
+ 'price': self.safe_number(market, 'tSz'),
947
+ },
948
+ 'limits': {
949
+ 'amount': {
950
+ 'min': self.safe_number(market, 'minSz'),
951
+ 'max': self.safe_number(market, 'limitMaxQty'),
952
+ },
953
+ 'price': {
954
+ 'min': self.safe_number(market, 'minPx'),
955
+ 'max': self.safe_number(market, 'maxPx'),
956
+ },
957
+ 'cost': {
958
+ 'min': None,
959
+ 'max': None,
960
+ },
961
+ 'leverage': {
962
+ 'max': self.safe_number(market, 'maxLever'),
963
+ 'min': None,
964
+ },
965
+ },
966
+ 'created': self.safe_integer(market, 'oDate'),
967
+ 'info': market,
968
+ }
969
+
651
970
  async def fetch_time(self, params={}) -> Int:
652
971
  """
653
972
  fetches the current integer timestamp in milliseconds from the exchange server
@@ -661,6 +980,8 @@ class poloniex(Exchange, ImplicitAPI):
661
980
  return self.safe_integer(response, 'serverTime')
662
981
 
663
982
  def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
983
+ #
984
+ # spot:
664
985
  #
665
986
  # {
666
987
  # "symbol" : "BTC_USDT",
@@ -683,36 +1004,56 @@ class poloniex(Exchange, ImplicitAPI):
683
1004
  # "markPrice" : "26444.11"
684
1005
  # }
685
1006
  #
686
- timestamp = self.safe_integer(ticker, 'ts')
687
- marketId = self.safe_string(ticker, 'symbol')
1007
+ # swap:
1008
+ #
1009
+ # {
1010
+ # "s": "XRP_USDT_PERP",
1011
+ # "o": "2.0503",
1012
+ # "l": "2.0066",
1013
+ # "h": "2.216",
1014
+ # "c": "2.1798",
1015
+ # "qty": "21090",
1016
+ # "amt": "451339.65",
1017
+ # "tC": "3267",
1018
+ # "sT": "1740736380000",
1019
+ # "cT": "1740822777559",
1020
+ # "dN": "XRP/USDT/PERP",
1021
+ # "dC": "0.0632",
1022
+ # "bPx": "2.175",
1023
+ # "bSz": "3",
1024
+ # "aPx": "2.1831",
1025
+ # "aSz": "111",
1026
+ # "mPx": "2.1798",
1027
+ # "iPx": "2.1834"
1028
+ # },
1029
+ #
1030
+ timestamp = self.safe_integer_2(ticker, 'ts', 'cT')
1031
+ marketId = self.safe_string_2(ticker, 'symbol', 's')
688
1032
  market = self.safe_market(marketId)
689
- close = self.safe_string(ticker, 'close')
690
- relativeChange = self.safe_string(ticker, 'dailyChange')
1033
+ relativeChange = self.safe_string_2(ticker, 'dailyChange', 'dc')
691
1034
  percentage = Precise.string_mul(relativeChange, '100')
692
- bidVolume = self.safe_string(ticker, 'bidQuantity')
693
- askVolume = self.safe_string(ticker, 'askQuantity')
694
1035
  return self.safe_ticker({
695
1036
  'id': marketId,
696
1037
  'symbol': market['symbol'],
697
1038
  'timestamp': timestamp,
698
1039
  'datetime': self.iso8601(timestamp),
699
- 'high': self.safe_string(ticker, 'high'),
700
- 'low': self.safe_string(ticker, 'low'),
701
- 'bid': self.safe_string(ticker, 'bid'),
702
- 'bidVolume': bidVolume,
703
- 'ask': self.safe_string(ticker, 'ask'),
704
- 'askVolume': askVolume,
1040
+ 'high': self.safe_string_2(ticker, 'high', 'h'),
1041
+ 'low': self.safe_string_2(ticker, 'low', 'l'),
1042
+ 'bid': self.safe_string_2(ticker, 'bid', 'bPx'),
1043
+ 'bidVolume': self.safe_string_2(ticker, 'bidQuantity', 'bSz'),
1044
+ 'ask': self.safe_string_2(ticker, 'ask', 'aPx'),
1045
+ 'askVolume': self.safe_string_2(ticker, 'askQuantity', 'aSz'),
705
1046
  'vwap': None,
706
- 'open': self.safe_string(ticker, 'open'),
707
- 'close': close,
708
- 'last': close,
1047
+ 'open': self.safe_string_2(ticker, 'open', 'o'),
1048
+ 'close': self.safe_string_2(ticker, 'close', 'c'),
709
1049
  'previousClose': None,
710
1050
  'change': None,
711
1051
  'percentage': percentage,
712
1052
  'average': None,
713
- 'baseVolume': self.safe_string(ticker, 'quantity'),
714
- 'quoteVolume': self.safe_string(ticker, 'amount'),
715
- 'markPrice': self.safe_string(ticker, 'markPrice'),
1053
+ 'baseVolume': self.safe_string_2(ticker, 'quantity', 'qty'),
1054
+ 'quoteVolume': self.safe_string_2(ticker, 'amount', 'amt'),
1055
+ 'markPrice': self.safe_string_2(ticker, 'markPrice', 'mPx'),
1056
+ 'indexPrice': self.safe_string(ticker, 'iPx'),
716
1057
  'info': ticker,
717
1058
  }, market)
718
1059
 
@@ -721,13 +1062,54 @@ class poloniex(Exchange, ImplicitAPI):
721
1062
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
722
1063
 
723
1064
  https://api-docs.poloniex.com/spot/api/public/market-data#ticker
1065
+ https://api-docs.poloniex.com/v3/futures/api/market/get-market-info
724
1066
 
725
1067
  :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
726
1068
  :param dict [params]: extra parameters specific to the exchange API endpoint
727
1069
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
728
1070
  """
729
1071
  await self.load_markets()
730
- symbols = self.market_symbols(symbols)
1072
+ market = None
1073
+ request: dict = {}
1074
+ if symbols is not None:
1075
+ symbols = self.market_symbols(symbols, None, True, True, False)
1076
+ symbolsLength = len(symbols)
1077
+ if symbolsLength > 0:
1078
+ market = self.market(symbols[0])
1079
+ if symbolsLength == 1:
1080
+ request['symbol'] = market['id']
1081
+ marketType = None
1082
+ marketType, params = self.handle_market_type_and_params('fetchTickers', market, params)
1083
+ if marketType == 'swap':
1084
+ responseRaw = await self.swapPublicGetV3MarketTickers(self.extend(request, params))
1085
+ #
1086
+ # {
1087
+ # "code": "200",
1088
+ # "msg": "Success",
1089
+ # "data": [
1090
+ # {
1091
+ # "s": "XRP_USDT_PERP",
1092
+ # "o": "2.0503",
1093
+ # "l": "2.0066",
1094
+ # "h": "2.216",
1095
+ # "c": "2.1798",
1096
+ # "qty": "21090",
1097
+ # "amt": "451339.65",
1098
+ # "tC": "3267",
1099
+ # "sT": "1740736380000",
1100
+ # "cT": "1740822777559",
1101
+ # "dN": "XRP/USDT/PERP",
1102
+ # "dC": "0.0632",
1103
+ # "bPx": "2.175",
1104
+ # "bSz": "3",
1105
+ # "aPx": "2.1831",
1106
+ # "aSz": "111",
1107
+ # "mPx": "2.1798",
1108
+ # "iPx": "2.1834"
1109
+ # },
1110
+ #
1111
+ data = self.safe_list(responseRaw, 'data')
1112
+ return self.parse_tickers(data, symbols)
731
1113
  response = await self.publicGetMarketsTicker24h(params)
732
1114
  #
733
1115
  # [
@@ -892,6 +1274,7 @@ class poloniex(Exchange, ImplicitAPI):
892
1274
  fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
893
1275
 
894
1276
  https://api-docs.poloniex.com/spot/api/public/market-data#ticker
1277
+ https://api-docs.poloniex.com/v3/futures/api/market/get-market-info
895
1278
 
896
1279
  :param str symbol: unified symbol of the market to fetch the ticker for
897
1280
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -902,6 +1285,9 @@ class poloniex(Exchange, ImplicitAPI):
902
1285
  request: dict = {
903
1286
  'symbol': market['id'],
904
1287
  }
1288
+ if market['contract']:
1289
+ tickers = await self.fetch_tickers([market['symbol']], params)
1290
+ return self.safe_dict(tickers, symbol)
905
1291
  response = await self.publicGetMarketsSymbolTicker24h(self.extend(request, params))
906
1292
  #
907
1293
  # {
@@ -931,6 +1317,8 @@ class poloniex(Exchange, ImplicitAPI):
931
1317
  #
932
1318
  # fetchTrades
933
1319
  #
1320
+ # spot:
1321
+ #
934
1322
  # {
935
1323
  # "id" : "60014521",
936
1324
  # "price" : "23162.94",
@@ -941,8 +1329,21 @@ class poloniex(Exchange, ImplicitAPI):
941
1329
  # "createTime" : 1659684602036
942
1330
  # }
943
1331
  #
1332
+ # swap:
1333
+ #
1334
+ # {
1335
+ # "id": "105807376",
1336
+ # "side": "buy",
1337
+ # "px": "84410.57",
1338
+ # "qty": "1",
1339
+ # "amt": "84.41057",
1340
+ # "cT": "1740777563557",
1341
+ # }
1342
+ #
944
1343
  # fetchMyTrades
945
1344
  #
1345
+ # spot:
1346
+ #
946
1347
  # {
947
1348
  # "id": "32164924331503616",
948
1349
  # "symbol": "LINK_USDT",
@@ -961,6 +1362,34 @@ class poloniex(Exchange, ImplicitAPI):
961
1362
  # "clientOrderId": "myOwnId-321"
962
1363
  # }
963
1364
  #
1365
+ # swap:
1366
+ #
1367
+ # {
1368
+ # "symbol": "BTC_USDT_PERP",
1369
+ # "trdId": "105813553",
1370
+ # "side": "SELL",
1371
+ # "type": "TRADE",
1372
+ # "mgnMode": "CROSS",
1373
+ # "ordType": "MARKET",
1374
+ # "clOrdId": "polo418912106147315112",
1375
+ # "role": "TAKER",
1376
+ # "px": "84704.9",
1377
+ # "qty": "1",
1378
+ # "cTime": "1740842829430",
1379
+ # "uTime": "1740842829450",
1380
+ # "feeCcy": "USDT",
1381
+ # "feeAmt": "0.04235245",
1382
+ # "deductCcy": "",
1383
+ # "deductAmt": "0",
1384
+ # "feeRate": "0.0005",
1385
+ # "id": "418912106342654592",
1386
+ # "posSide": "BOTH",
1387
+ # "ordId": "418912106147315112",
1388
+ # "qCcy": "USDT",
1389
+ # "value": "84.7049",
1390
+ # "actType": "TRADING"
1391
+ # },
1392
+ #
964
1393
  # fetchOrderTrades(taker trades)
965
1394
  #
966
1395
  # {
@@ -981,20 +1410,19 @@ class poloniex(Exchange, ImplicitAPI):
981
1410
  # "clientOrderId": ""
982
1411
  # }
983
1412
  #
984
- #
985
- id = self.safe_string_2(trade, 'id', 'tradeID')
986
- orderId = self.safe_string(trade, 'orderId')
987
- timestamp = self.safe_integer_2(trade, 'ts', 'createTime')
1413
+ id = self.safe_string_n(trade, ['id', 'tradeID', 'trdId'])
1414
+ orderId = self.safe_string_2(trade, 'orderId', 'ordId')
1415
+ timestamp = self.safe_integer_n(trade, ['ts', 'createTime', 'cT', 'cTime'])
988
1416
  marketId = self.safe_string(trade, 'symbol')
989
1417
  market = self.safe_market(marketId, market, '_')
990
1418
  symbol = market['symbol']
991
1419
  side = self.safe_string_lower_2(trade, 'side', 'takerSide')
992
1420
  fee = None
993
- priceString = self.safe_string(trade, 'price')
994
- amountString = self.safe_string(trade, 'quantity')
995
- costString = self.safe_string(trade, 'amount')
996
- feeCurrencyId = self.safe_string(trade, 'feeCurrency')
997
- feeCostString = self.safe_string(trade, 'feeAmount')
1421
+ priceString = self.safe_string_2(trade, 'price', 'px')
1422
+ amountString = self.safe_string_2(trade, 'quantity', 'qty')
1423
+ costString = self.safe_string_2(trade, 'amount', 'amt')
1424
+ feeCurrencyId = self.safe_string_2(trade, 'feeCurrency', 'feeCcy')
1425
+ feeCostString = self.safe_string_2(trade, 'feeAmount', 'feeAmt')
998
1426
  if feeCostString is not None:
999
1427
  feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1000
1428
  fee = {
@@ -1008,9 +1436,9 @@ class poloniex(Exchange, ImplicitAPI):
1008
1436
  'datetime': self.iso8601(timestamp),
1009
1437
  'symbol': symbol,
1010
1438
  'order': orderId,
1011
- 'type': self.safe_string_lower(trade, 'type'),
1439
+ 'type': self.safe_string_lower_2(trade, 'ordType', 'type'), # ordType should take precedence
1012
1440
  'side': side,
1013
- 'takerOrMaker': self.safe_string_lower(trade, 'matchRole'),
1441
+ 'takerOrMaker': self.safe_string_lower_2(trade, 'matchRole', 'role'),
1014
1442
  'price': priceString,
1015
1443
  'amount': amountString,
1016
1444
  'cost': costString,
@@ -1022,6 +1450,7 @@ class poloniex(Exchange, ImplicitAPI):
1022
1450
  get the list of most recent trades for a particular symbol
1023
1451
 
1024
1452
  https://api-docs.poloniex.com/spot/api/public/market-data#trades
1453
+ https://api-docs.poloniex.com/v3/futures/api/market/get-execution-info
1025
1454
 
1026
1455
  :param str symbol: unified symbol of the market to fetch trades for
1027
1456
  :param int [since]: timestamp in ms of the earliest trade to fetch
@@ -1035,7 +1464,25 @@ class poloniex(Exchange, ImplicitAPI):
1035
1464
  'symbol': market['id'],
1036
1465
  }
1037
1466
  if limit is not None:
1038
- request['limit'] = limit
1467
+ request['limit'] = limit # max 1000, for spot & swap
1468
+ if market['contract']:
1469
+ response = await self.swapPublicGetV3MarketTrades(self.extend(request, params))
1470
+ #
1471
+ # {
1472
+ # code: "200",
1473
+ # msg: "Success",
1474
+ # data: [
1475
+ # {
1476
+ # id: "105807320", # descending order
1477
+ # side: "sell",
1478
+ # px: "84383.93",
1479
+ # qty: "1",
1480
+ # amt: "84.38393",
1481
+ # cT: "1740777074704",
1482
+ # },
1483
+ #
1484
+ tradesList = self.safe_list(response, 'data')
1485
+ return self.parse_trades(tradesList, market, since, limit)
1039
1486
  trades = await self.publicGetMarketsSymbolTrades(self.extend(request, params))
1040
1487
  #
1041
1488
  # [
@@ -1057,6 +1504,7 @@ class poloniex(Exchange, ImplicitAPI):
1057
1504
  fetch all trades made by the user
1058
1505
 
1059
1506
  https://api-docs.poloniex.com/spot/api/private/trade#trade-history
1507
+ https://api-docs.poloniex.com/v3/futures/api/trade/get-execution-details
1060
1508
 
1061
1509
  :param str symbol: unified market symbol
1062
1510
  :param int [since]: the earliest time in ms to fetch trades for
@@ -1074,15 +1522,57 @@ class poloniex(Exchange, ImplicitAPI):
1074
1522
  market: Market = None
1075
1523
  if symbol is not None:
1076
1524
  market = self.market(symbol)
1525
+ marketType = None
1526
+ marketType, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
1527
+ isContract = self.in_array(marketType, ['swap', 'future'])
1077
1528
  request: dict = {
1078
1529
  # 'from': 12345678, # A 'trade Id'. The query begins at ‘from'.
1079
1530
  # 'direction': 'PRE', # PRE, NEXT The direction before or after ‘from'.
1080
1531
  }
1532
+ startKey = 'sTime' if isContract else 'startTime'
1533
+ endKey = 'eTime' if isContract else 'endTime'
1081
1534
  if since is not None:
1082
- request['startTime'] = since
1535
+ request[startKey] = since
1083
1536
  if limit is not None:
1084
1537
  request['limit'] = limit
1085
- request, params = self.handle_until_option('endTime', request, params)
1538
+ if isContract and symbol is not None:
1539
+ request['symbol'] = market['id']
1540
+ request, params = self.handle_until_option(endKey, request, params)
1541
+ if isContract:
1542
+ raw = await self.swapPrivateGetV3TradeOrderTrades(self.extend(request, params))
1543
+ #
1544
+ # {
1545
+ # "code": "200",
1546
+ # "msg": "",
1547
+ # "data": [
1548
+ # {
1549
+ # "symbol": "BTC_USDT_PERP",
1550
+ # "trdId": "105813553",
1551
+ # "side": "SELL",
1552
+ # "type": "TRADE",
1553
+ # "mgnMode": "CROSS",
1554
+ # "ordType": "MARKET",
1555
+ # "clOrdId": "polo418912106147315112",
1556
+ # "role": "TAKER",
1557
+ # "px": "84704.9",
1558
+ # "qty": "1",
1559
+ # "cTime": "1740842829430",
1560
+ # "uTime": "1740842829450",
1561
+ # "feeCcy": "USDT",
1562
+ # "feeAmt": "0.04235245",
1563
+ # "deductCcy": "",
1564
+ # "deductAmt": "0",
1565
+ # "feeRate": "0.0005",
1566
+ # "id": "418912106342654592",
1567
+ # "posSide": "BOTH",
1568
+ # "ordId": "418912106147315112",
1569
+ # "qCcy": "USDT",
1570
+ # "value": "84.7049",
1571
+ # "actType": "TRADING"
1572
+ # },
1573
+ #
1574
+ data = self.safe_list(raw, 'data')
1575
+ return self.parse_trades(data, market, since, limit)
1086
1576
  response = await self.privateGetTrades(self.extend(request, params))
1087
1577
  #
1088
1578
  # [
@@ -1143,7 +1633,9 @@ class poloniex(Exchange, ImplicitAPI):
1143
1633
  # "updateTime" : 16xxxxxxxxx36
1144
1634
  # }
1145
1635
  #
1146
- # fetchOpenOrders
1636
+ # fetchOpenOrders(and fetchClosedOrders same for contracts)
1637
+ #
1638
+ # spot:
1147
1639
  #
1148
1640
  # {
1149
1641
  # "id": "24993088082542592",
@@ -1164,14 +1656,60 @@ class poloniex(Exchange, ImplicitAPI):
1164
1656
  # "updateTime": 1646925216548
1165
1657
  # }
1166
1658
  #
1659
+ # contract:
1660
+ #
1661
+ # {
1662
+ # "symbol": "BTC_USDT_PERP",
1663
+ # "side": "BUY",
1664
+ # "type": "LIMIT",
1665
+ # "ordId": "418890767248232148",
1666
+ # "clOrdId": "polo418890767248232148",
1667
+ # "mgnMode": "CROSS",
1668
+ # "px": "81130.13",
1669
+ # "reduceOnly": False,
1670
+ # "lever": "20",
1671
+ # "state": "NEW",
1672
+ # "source": "WEB",
1673
+ # "timeInForce": "GTC",
1674
+ # "tpTrgPx": "",
1675
+ # "tpPx": "",
1676
+ # "tpTrgPxType": "",
1677
+ # "slTrgPx": "",
1678
+ # "slPx": "",
1679
+ # "slTrgPxType": "",
1680
+ # "avgPx": "0",
1681
+ # "execQty": "0",
1682
+ # "execAmt": "0",
1683
+ # "feeCcy": "",
1684
+ # "feeAmt": "0",
1685
+ # "deductCcy": "0",
1686
+ # "deductAmt": "0",
1687
+ # "stpMode": "NONE", # todo: selfTradePrevention
1688
+ # "cTime": "1740837741523",
1689
+ # "uTime": "1740840846882",
1690
+ # "sz": "1",
1691
+ # "posSide": "BOTH",
1692
+ # "qCcy": "USDT"
1693
+ # "cancelReason": "", # self field can only be in closed orders
1694
+ # },
1695
+ #
1167
1696
  # createOrder, editOrder
1168
1697
  #
1698
+ # spot:
1699
+ #
1169
1700
  # {
1170
1701
  # "id": "29772698821328896",
1171
1702
  # "clientOrderId": "1234Abc"
1172
1703
  # }
1173
1704
  #
1174
- timestamp = self.safe_integer_2(order, 'timestamp', 'createTime')
1705
+ # contract:
1706
+ #
1707
+ # {
1708
+ # "ordId":"418876147745775616",
1709
+ # "clOrdId":"polo418876147745775616"
1710
+ # }
1711
+ #
1712
+ timestamp = self.safe_integer_n(order, ['timestamp', 'createTime', 'cTime'])
1175
1713
  if timestamp is None:
1176
1714
  timestamp = self.parse8601(self.safe_string(order, 'date'))
1177
1715
  marketId = self.safe_string(order, 'symbol')
@@ -1181,16 +1719,16 @@ class poloniex(Exchange, ImplicitAPI):
1181
1719
  if resultingTrades is not None:
1182
1720
  if not isinstance(resultingTrades, list):
1183
1721
  resultingTrades = self.safe_value(resultingTrades, self.safe_string(market, 'id', marketId))
1184
- price = self.safe_string_2(order, 'price', 'rate')
1185
- amount = self.safe_string(order, 'quantity')
1186
- filled = self.safe_string(order, 'filledQuantity')
1722
+ price = self.safe_string_n(order, ['price', 'rate', 'px'])
1723
+ amount = self.safe_string_2(order, 'quantity', 'sz')
1724
+ filled = self.safe_string_2(order, 'filledQuantity', 'execQty')
1187
1725
  status = self.parse_order_status(self.safe_string(order, 'state'))
1188
1726
  side = self.safe_string_lower(order, 'side')
1189
1727
  rawType = self.safe_string(order, 'type')
1190
1728
  type = self.parse_order_type(rawType)
1191
- id = self.safe_string_n(order, ['orderNumber', 'id', 'orderId'])
1729
+ id = self.safe_string_n(order, ['orderNumber', 'id', 'orderId', 'ordId'])
1192
1730
  fee = None
1193
- feeCurrency = self.safe_string(order, 'tokenFeeCurrency')
1731
+ feeCurrency = self.safe_string_2(order, 'tokenFeeCurrency', 'feeCcy')
1194
1732
  feeCost: Str = None
1195
1733
  feeCurrencyCode: Str = None
1196
1734
  rate = self.safe_string(order, 'fee')
@@ -1199,14 +1737,18 @@ class poloniex(Exchange, ImplicitAPI):
1199
1737
  else:
1200
1738
  # poloniex accepts a 30% discount to pay fees in TRX
1201
1739
  feeCurrencyCode = self.safe_currency_code(feeCurrency)
1202
- feeCost = self.safe_string(order, 'tokenFee')
1740
+ feeCost = self.safe_string_2(order, 'tokenFee', 'feeAmt')
1203
1741
  if feeCost is not None:
1204
1742
  fee = {
1205
1743
  'rate': rate,
1206
1744
  'cost': feeCost,
1207
1745
  'currency': feeCurrencyCode,
1208
1746
  }
1209
- clientOrderId = self.safe_string(order, 'clientOrderId')
1747
+ clientOrderId = self.safe_string_2(order, 'clientOrderId', 'clOrdId')
1748
+ marginMode = self.safe_string_lower(order, 'mgnMode')
1749
+ reduceOnly = self.safe_bool(order, 'reduceOnly')
1750
+ leverage = self.safe_integer(order, 'lever')
1751
+ hedged = self.safe_string(order, 'posSide') != 'BOTH'
1210
1752
  return self.safe_order({
1211
1753
  'info': order,
1212
1754
  'id': id,
@@ -1218,23 +1760,28 @@ class poloniex(Exchange, ImplicitAPI):
1218
1760
  'symbol': symbol,
1219
1761
  'type': type,
1220
1762
  'timeInForce': self.safe_string(order, 'timeInForce'),
1221
- 'postOnly': None,
1763
+ 'postOnly': rawType == 'LIMIT_MAKER',
1222
1764
  'side': side,
1223
1765
  'price': price,
1224
1766
  'triggerPrice': self.safe_string_2(order, 'triggerPrice', 'stopPrice'),
1225
- 'cost': None,
1226
- 'average': self.safe_string(order, 'avgPrice'),
1767
+ 'cost': self.safe_string(order, 'execAmt'),
1768
+ 'average': self.safe_string_2(order, 'avgPrice', 'avgPx'),
1227
1769
  'amount': amount,
1228
1770
  'filled': filled,
1229
1771
  'remaining': None,
1230
1772
  'trades': resultingTrades,
1231
1773
  'fee': fee,
1774
+ 'marginMode': marginMode,
1775
+ 'reduceOnly': reduceOnly,
1776
+ 'leverage': leverage,
1777
+ 'hedged': hedged,
1232
1778
  }, market)
1233
1779
 
1234
1780
  def parse_order_type(self, status):
1235
1781
  statuses: dict = {
1236
1782
  'MARKET': 'market',
1237
1783
  'LIMIT': 'limit',
1784
+ 'LIMIT_MAKER': 'limit',
1238
1785
  'STOP-LIMIT': 'limit',
1239
1786
  'STOP-MARKET': 'market',
1240
1787
  }
@@ -1258,6 +1805,7 @@ class poloniex(Exchange, ImplicitAPI):
1258
1805
 
1259
1806
  https://api-docs.poloniex.com/spot/api/private/order#open-orders
1260
1807
  https://api-docs.poloniex.com/spot/api/private/smart-order#open-orders # trigger orders
1808
+ https://api-docs.poloniex.com/v3/futures/api/trade/get-current-orders
1261
1809
 
1262
1810
  :param str symbol: unified market symbol
1263
1811
  :param int [since]: the earliest time in ms to fetch open orders for
@@ -1272,12 +1820,57 @@ class poloniex(Exchange, ImplicitAPI):
1272
1820
  if symbol is not None:
1273
1821
  market = self.market(symbol)
1274
1822
  request['symbol'] = market['id']
1823
+ marketType = None
1824
+ marketType, params = self.handle_market_type_and_params('fetchOpenOrders', market, params)
1275
1825
  if limit is not None:
1276
- request['limit'] = limit
1826
+ max = 2000 if (marketType == 'spot') else 100
1827
+ request['limit'] = max(limit, max)
1277
1828
  isTrigger = self.safe_value_2(params, 'trigger', 'stop')
1278
1829
  params = self.omit(params, ['trigger', 'stop'])
1279
1830
  response = None
1280
- if isTrigger:
1831
+ if not market['spot']:
1832
+ raw = await self.swapPrivateGetV3TradeOrderOpens(self.extend(request, params))
1833
+ #
1834
+ # {
1835
+ # "code": "200",
1836
+ # "msg": "",
1837
+ # "data": [
1838
+ # {
1839
+ # "symbol": "BTC_USDT_PERP",
1840
+ # "side": "BUY",
1841
+ # "type": "LIMIT",
1842
+ # "ordId": "418890767248232148",
1843
+ # "clOrdId": "polo418890767248232148",
1844
+ # "mgnMode": "CROSS",
1845
+ # "px": "81130.13",
1846
+ # "reduceOnly": False,
1847
+ # "lever": "20",
1848
+ # "state": "NEW",
1849
+ # "source": "WEB",
1850
+ # "timeInForce": "GTC",
1851
+ # "tpTrgPx": "",
1852
+ # "tpPx": "",
1853
+ # "tpTrgPxType": "",
1854
+ # "slTrgPx": "",
1855
+ # "slPx": "",
1856
+ # "slTrgPxType": "",
1857
+ # "avgPx": "0",
1858
+ # "execQty": "0",
1859
+ # "execAmt": "0",
1860
+ # "feeCcy": "",
1861
+ # "feeAmt": "0",
1862
+ # "deductCcy": "0",
1863
+ # "deductAmt": "0",
1864
+ # "stpMode": "NONE",
1865
+ # "cTime": "1740837741523",
1866
+ # "uTime": "1740840846882",
1867
+ # "sz": "1",
1868
+ # "posSide": "BOTH",
1869
+ # "qCcy": "USDT"
1870
+ # },
1871
+ #
1872
+ response = self.safe_list(raw, 'data')
1873
+ elif isTrigger:
1281
1874
  response = await self.privateGetSmartorders(self.extend(request, params))
1282
1875
  else:
1283
1876
  response = await self.privateGetOrders(self.extend(request, params))
@@ -1307,6 +1900,78 @@ class poloniex(Exchange, ImplicitAPI):
1307
1900
  extension: dict = {'status': 'open'}
1308
1901
  return self.parse_orders(response, market, since, limit, extension)
1309
1902
 
1903
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
1904
+ """
1905
+
1906
+ https://api-docs.poloniex.com/v3/futures/api/trade/get-order-history
1907
+
1908
+ fetches information on multiple closed orders made by the user
1909
+ :param str symbol: unified market symbol of the market orders were made in
1910
+ :param int [since]: the earliest time in ms to fetch orders for
1911
+ :param int [limit]: the maximum number of order structures to retrieve
1912
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1913
+ :param int [params.until]: timestamp in ms of the latest entry
1914
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1915
+ """
1916
+ await self.load_markets()
1917
+ market = None
1918
+ request: dict = {}
1919
+ if symbol is not None:
1920
+ market = self.market(symbol)
1921
+ request['symbol'] = market['id']
1922
+ marketType = None
1923
+ marketType, params = self.handle_market_type_and_params('fetchClosedOrders', market, params, 'swap')
1924
+ if marketType == 'spot':
1925
+ raise NotSupported(self.id + ' fetchClosedOrders() is not supported for spot markets yet')
1926
+ if limit is not None:
1927
+ request['limit'] = min(200, limit)
1928
+ if since is not None:
1929
+ request['sTime'] = since
1930
+ request, params = self.handle_until_option('eTime', request, params)
1931
+ response = await self.swapPrivateGetV3TradeOrderHistory(self.extend(request, params))
1932
+ #
1933
+ # {
1934
+ # "code": "200",
1935
+ # "msg": "",
1936
+ # "data": [
1937
+ # {
1938
+ # "symbol": "BTC_USDT_PERP",
1939
+ # "side": "SELL",
1940
+ # "type": "MARKET",
1941
+ # "ordId": "418912106147315712",
1942
+ # "clOrdId": "polo418912106147315712",
1943
+ # "mgnMode": "CROSS",
1944
+ # "px": "0",
1945
+ # "sz": "2",
1946
+ # "lever": "20",
1947
+ # "state": "FILLED",
1948
+ # "cancelReason": "",
1949
+ # "source": "WEB",
1950
+ # "reduceOnly": "true",
1951
+ # "timeInForce": "GTC",
1952
+ # "tpTrgPx": "",
1953
+ # "tpPx": "",
1954
+ # "tpTrgPxType": "",
1955
+ # "slTrgPx": "",
1956
+ # "slPx": "",
1957
+ # "slTrgPxType": "",
1958
+ # "avgPx": "84705.56",
1959
+ # "execQty": "2",
1960
+ # "execAmt": "169.41112",
1961
+ # "feeCcy": "USDT",
1962
+ # "feeAmt": "0.08470556",
1963
+ # "deductCcy": "0",
1964
+ # "deductAmt": "0",
1965
+ # "stpMode": "NONE",
1966
+ # "cTime": "1740842829116",
1967
+ # "uTime": "1740842829130",
1968
+ # "posSide": "BOTH",
1969
+ # "qCcy": "USDT"
1970
+ # },
1971
+ #
1972
+ data = self.safe_list(response, 'data', [])
1973
+ return self.parse_orders(data, market, since, limit)
1974
+
1310
1975
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1311
1976
  """
1312
1977
  create a trade order
@@ -1326,19 +1991,23 @@ class poloniex(Exchange, ImplicitAPI):
1326
1991
  """
1327
1992
  await self.load_markets()
1328
1993
  market = self.market(symbol)
1329
- if not market['spot']:
1330
- raise NotSupported(self.id + ' createOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted')
1331
1994
  request: dict = {
1332
1995
  'symbol': market['id'],
1333
- 'side': side,
1334
- # 'timeInForce': timeInForce,
1996
+ 'side': side.upper(), # uppercase, both for spot & swap
1997
+ # 'timeInForce': timeInForce, # matches unified values
1335
1998
  # 'accountType': 'SPOT',
1336
1999
  # 'amount': amount,
1337
2000
  }
1338
2001
  triggerPrice = self.safe_number_2(params, 'stopPrice', 'triggerPrice')
1339
2002
  request, params = self.order_request(symbol, type, side, amount, request, price, params)
1340
2003
  response = None
1341
- if triggerPrice is not None:
2004
+ if market['swap'] or market['future']:
2005
+ responseInitial = await self.swapPrivatePostV3TradeOrder(self.extend(request, params))
2006
+ #
2007
+ # {"code":200,"msg":"Success","data":{"ordId":"418876147745775616","clOrdId":"polo418876147745775616"}}
2008
+ #
2009
+ response = self.safe_dict(responseInitial, 'data')
2010
+ elif triggerPrice is not None:
1342
2011
  response = await self.privatePostSmartorders(self.extend(request, params))
1343
2012
  else:
1344
2013
  response = await self.privatePostOrders(self.extend(request, params))
@@ -1348,19 +2017,31 @@ class poloniex(Exchange, ImplicitAPI):
1348
2017
  # "clientOrderId" : ""
1349
2018
  # }
1350
2019
  #
1351
- response = self.extend(response, {
1352
- 'type': type,
1353
- 'side': side,
1354
- })
1355
2020
  return self.parse_order(response, market)
1356
2021
 
1357
2022
  def order_request(self, symbol, type, side, amount, request, price=None, params={}):
2023
+ triggerPrice = self.safe_number_2(params, 'stopPrice', 'triggerPrice')
2024
+ market = self.market(symbol)
2025
+ if market['contract']:
2026
+ marginMode = None
2027
+ marginMode, params = self.handle_param_string(params, 'marginMode')
2028
+ if marginMode is not None:
2029
+ self.check_required_argument('createOrder', marginMode, 'marginMode', ['cross', 'isolated'])
2030
+ request['mgnMode'] = marginMode.upper()
2031
+ hedged = None
2032
+ hedged, params = self.handle_param_string(params, 'hedged')
2033
+ if hedged:
2034
+ if marginMode is None:
2035
+ raise ArgumentsRequired(self.id + ' createOrder() requires a marginMode parameter "cross" or "isolated" for hedged orders')
2036
+ if not ('posSide' in params):
2037
+ raise ArgumentsRequired(self.id + ' createOrder() requires a posSide parameter "LONG" or "SHORT" for hedged orders')
1358
2038
  upperCaseType = type.upper()
1359
2039
  isMarket = upperCaseType == 'MARKET'
1360
2040
  isPostOnly = self.is_post_only(isMarket, upperCaseType == 'LIMIT_MAKER', params)
1361
- triggerPrice = self.safe_number_2(params, 'stopPrice', 'triggerPrice')
1362
2041
  params = self.omit(params, ['postOnly', 'triggerPrice', 'stopPrice'])
1363
2042
  if triggerPrice is not None:
2043
+ if not market['spot']:
2044
+ raise InvalidOrder(self.id + ' createOrder() does not support trigger orders for ' + market['type'] + ' markets')
1364
2045
  upperCaseType = 'STOP' if (price is None) else 'STOP_LIMIT'
1365
2046
  request['stopPrice'] = triggerPrice
1366
2047
  elif isPostOnly:
@@ -1375,7 +2056,7 @@ class poloniex(Exchange, ImplicitAPI):
1375
2056
  params = self.omit(params, 'cost')
1376
2057
  if cost is not None:
1377
2058
  quoteAmount = self.cost_to_precision(symbol, cost)
1378
- elif createMarketBuyOrderRequiresPrice:
2059
+ elif createMarketBuyOrderRequiresPrice and market['spot']:
1379
2060
  if price is None:
1380
2061
  raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend(quote quantity) in the amount argument')
1381
2062
  else:
@@ -1385,12 +2066,16 @@ class poloniex(Exchange, ImplicitAPI):
1385
2066
  quoteAmount = self.cost_to_precision(symbol, costRequest)
1386
2067
  else:
1387
2068
  quoteAmount = self.cost_to_precision(symbol, amount)
1388
- request['amount'] = quoteAmount
2069
+ amountKey = 'amount' if market['spot'] else 'sz'
2070
+ request[amountKey] = quoteAmount
1389
2071
  else:
1390
- request['quantity'] = self.amount_to_precision(symbol, amount)
2072
+ amountKey = 'quantity' if market['spot'] else 'sz'
2073
+ request[amountKey] = self.amount_to_precision(symbol, amount)
1391
2074
  else:
1392
- request['quantity'] = self.amount_to_precision(symbol, amount)
1393
- request['price'] = self.price_to_precision(symbol, price)
2075
+ amountKey = 'quantity' if market['spot'] else 'sz'
2076
+ request[amountKey] = self.amount_to_precision(symbol, amount)
2077
+ priceKey = 'price' if market['spot'] else 'px'
2078
+ request[priceKey] = self.price_to_precision(symbol, price)
1394
2079
  clientOrderId = self.safe_string(params, 'clientOrderId')
1395
2080
  if clientOrderId is not None:
1396
2081
  request['clientOrderId'] = clientOrderId
@@ -1456,7 +2141,25 @@ class poloniex(Exchange, ImplicitAPI):
1456
2141
  # @returns {object} An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1457
2142
  #
1458
2143
  await self.load_markets()
2144
+ if symbol is None:
2145
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
2146
+ market = self.market(symbol)
1459
2147
  request: dict = {}
2148
+ if not market['spot']:
2149
+ request['symbol'] = market['id']
2150
+ request['ordId'] = id
2151
+ raw = await self.swapPrivateDeleteV3TradeOrder(self.extend(request, params))
2152
+ #
2153
+ # {
2154
+ # "code": "200",
2155
+ # "msg": "Success",
2156
+ # "data": {
2157
+ # "ordId": "418886099910612040",
2158
+ # "clOrdId": "polo418886099910612040"
2159
+ # }
2160
+ # }
2161
+ #
2162
+ return self.parse_order(self.safe_dict(raw, 'data'))
1460
2163
  clientOrderId = self.safe_value(params, 'clientOrderId')
1461
2164
  if clientOrderId is not None:
1462
2165
  id = clientOrderId
@@ -1485,6 +2188,7 @@ class poloniex(Exchange, ImplicitAPI):
1485
2188
 
1486
2189
  https://api-docs.poloniex.com/spot/api/private/order#cancel-all-orders
1487
2190
  https://api-docs.poloniex.com/spot/api/private/smart-order#cancel-all-orders # trigger orders
2191
+ https://api-docs.poloniex.com/v3/futures/api/trade/cancel-all-orders - contract markets
1488
2192
 
1489
2193
  :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
1490
2194
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1502,9 +2206,29 @@ class poloniex(Exchange, ImplicitAPI):
1502
2206
  request['symbols'] = [
1503
2207
  market['id'],
1504
2208
  ]
2209
+ response = None
2210
+ marketType = None
2211
+ marketType, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
2212
+ if marketType == 'swap' or marketType == 'future':
2213
+ raw = await self.swapPrivateDeleteV3TradeAllOrders(self.extend(request, params))
2214
+ #
2215
+ # {
2216
+ # "code": "200",
2217
+ # "msg": "Success",
2218
+ # "data": [
2219
+ # {
2220
+ # "code": "200",
2221
+ # "msg": "Success",
2222
+ # "ordId": "418885787866388511",
2223
+ # "clOrdId": "polo418885787866388511"
2224
+ # }
2225
+ # ]
2226
+ # }
2227
+ #
2228
+ response = self.safe_list(raw, 'data')
2229
+ return self.parse_orders(response, market)
1505
2230
  isTrigger = self.safe_value_2(params, 'trigger', 'stop')
1506
2231
  params = self.omit(params, ['trigger', 'stop'])
1507
- response = None
1508
2232
  if isTrigger:
1509
2233
  response = await self.privateDeleteSmartorders(self.extend(request, params))
1510
2234
  else:
@@ -1546,6 +2270,14 @@ class poloniex(Exchange, ImplicitAPI):
1546
2270
  request: dict = {
1547
2271
  'id': id,
1548
2272
  }
2273
+ market = None
2274
+ if symbol is not None:
2275
+ market = self.market(symbol)
2276
+ request['symbol'] = market['id']
2277
+ marketType = None
2278
+ marketType, params = self.handle_market_type_and_params('fetchOrder', market, params)
2279
+ if marketType != 'spot':
2280
+ raise NotSupported(self.id + ' fetchOrder() is not supported for ' + marketType + ' markets yet')
1549
2281
  isTrigger = self.safe_value_2(params, 'trigger', 'stop')
1550
2282
  params = self.omit(params, ['trigger', 'stop'])
1551
2283
  response = None
@@ -1632,6 +2364,22 @@ class poloniex(Exchange, ImplicitAPI):
1632
2364
  'timestamp': None,
1633
2365
  'datetime': None,
1634
2366
  }
2367
+ # for swap
2368
+ if not isinstance(response, list):
2369
+ ts = self.safe_integer(response, 'uTime')
2370
+ result['timestamp'] = ts
2371
+ result['datetime'] = self.iso8601(ts)
2372
+ details = self.safe_list(response, 'details', [])
2373
+ for i in range(0, len(details)):
2374
+ balance = details[i]
2375
+ currencyId = self.safe_string(balance, 'ccy')
2376
+ code = self.safe_currency_code(currencyId)
2377
+ account = self.account()
2378
+ account['total'] = self.safe_string(balance, 'avail')
2379
+ account['used'] = self.safe_string(balance, 'im')
2380
+ result[code] = account
2381
+ return self.safe_balance(result)
2382
+ # for spot
1635
2383
  for i in range(0, len(response)):
1636
2384
  account = self.safe_value(response, i, {})
1637
2385
  balances = self.safe_value(account, 'balances')
@@ -1650,11 +2398,55 @@ class poloniex(Exchange, ImplicitAPI):
1650
2398
  query for balance and get the amount of funds available for trading or funds locked in orders
1651
2399
 
1652
2400
  https://api-docs.poloniex.com/spot/api/private/account#all-account-balances
2401
+ https://api-docs.poloniex.com/v3/futures/api/account/balance
1653
2402
 
1654
2403
  :param dict [params]: extra parameters specific to the exchange API endpoint
1655
2404
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1656
2405
  """
1657
2406
  await self.load_markets()
2407
+ marketType = None
2408
+ marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
2409
+ if marketType != 'spot':
2410
+ responseRaw = await self.swapPrivateGetV3AccountBalance(params)
2411
+ #
2412
+ # {
2413
+ # "code": "200",
2414
+ # "msg": "",
2415
+ # "data": {
2416
+ # "state": "NORMAL",
2417
+ # "eq": "9.98571622",
2418
+ # "isoEq": "0",
2419
+ # "im": "0",
2420
+ # "mm": "0",
2421
+ # "mmr": "0",
2422
+ # "upl": "0",
2423
+ # "availMgn": "9.98571622",
2424
+ # "cTime": "1738093601775",
2425
+ # "uTime": "1740829116236",
2426
+ # "details": [
2427
+ # {
2428
+ # "ccy": "USDT",
2429
+ # "eq": "9.98571622",
2430
+ # "isoEq": "0",
2431
+ # "avail": "9.98571622",
2432
+ # "trdHold": "0",
2433
+ # "upl": "0",
2434
+ # "isoAvail": "0",
2435
+ # "isoHold": "0",
2436
+ # "isoUpl": "0",
2437
+ # "im": "0",
2438
+ # "mm": "0",
2439
+ # "mmr": "0",
2440
+ # "imr": "0",
2441
+ # "cTime": "1740829116236",
2442
+ # "uTime": "1740829116236"
2443
+ # }
2444
+ # ]
2445
+ # }
2446
+ # }
2447
+ #
2448
+ data = self.safe_dict(responseRaw, 'data', {})
2449
+ return self.parse_balance(data)
1658
2450
  request: dict = {
1659
2451
  'accountType': 'SPOT',
1660
2452
  }
@@ -1714,6 +2506,7 @@ class poloniex(Exchange, ImplicitAPI):
1714
2506
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1715
2507
 
1716
2508
  https://api-docs.poloniex.com/spot/api/public/market-data#order-book
2509
+ https://api-docs.poloniex.com/v3/futures/api/market/get-order-book
1717
2510
 
1718
2511
  :param str symbol: unified symbol of the market to fetch the order book for
1719
2512
  :param int [limit]: the maximum amount of order book entries to return
@@ -1727,6 +2520,25 @@ class poloniex(Exchange, ImplicitAPI):
1727
2520
  }
1728
2521
  if limit is not None:
1729
2522
  request['limit'] = limit # The default value of limit is 10. Valid limit values are: 5, 10, 20, 50, 100, 150.
2523
+ if market['contract']:
2524
+ request['limit'] = self.find_nearest_ceiling([5, 10, 20, 100, 150], limit)
2525
+ if market['contract']:
2526
+ responseRaw = await self.swapPublicGetV3MarketOrderBook(self.extend(request, params))
2527
+ #
2528
+ # {
2529
+ # "code": 200,
2530
+ # "data": {
2531
+ # "asks": [["58700", "9934"], ..],
2532
+ # "bids": [["58600", "9952"], ..],
2533
+ # "s": "100",
2534
+ # "ts": 1719974138333
2535
+ # },
2536
+ # "msg": "Success"
2537
+ # }
2538
+ #
2539
+ data = self.safe_dict(responseRaw, 'data', {})
2540
+ ts = self.safe_integer(data, 'ts')
2541
+ return self.parse_order_book(data, symbol, ts)
1730
2542
  response = await self.publicGetMarketsSymbolOrderBook(self.extend(request, params))
1731
2543
  #
1732
2544
  # {
@@ -1761,7 +2573,7 @@ class poloniex(Exchange, ImplicitAPI):
1761
2573
  'nonce': None,
1762
2574
  }
1763
2575
 
1764
- async def create_deposit_address(self, code: str, params={}):
2576
+ async def create_deposit_address(self, code: str, params={}) -> DepositAddress:
1765
2577
  """
1766
2578
  create a currency deposit address
1767
2579
 
@@ -2300,14 +3112,381 @@ class poloniex(Exchange, ImplicitAPI):
2300
3112
  },
2301
3113
  }
2302
3114
 
3115
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
3116
+ """
3117
+ set the level of leverage for a market
3118
+
3119
+ https://api-docs.poloniex.com/v3/futures/api/positions/set-leverage
3120
+
3121
+ :param int leverage: the rate of leverage
3122
+ :param str symbol: unified market symbol
3123
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3124
+ :param str [params.marginMode]: 'cross' or 'isolated'
3125
+ :returns dict: response from the exchange
3126
+ """
3127
+ if symbol is None:
3128
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
3129
+ await self.load_markets()
3130
+ market = self.market(symbol)
3131
+ marginMode = None
3132
+ marginMode, params = self.handle_margin_mode_and_params('setLeverage', params)
3133
+ if marginMode is None:
3134
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a marginMode parameter "cross" or "isolated"')
3135
+ hedged: Bool = None
3136
+ hedged, params = self.handle_param_bool(params, 'hedged', False)
3137
+ if hedged:
3138
+ if not ('posSide' in params):
3139
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a posSide parameter for hedged mode: "LONG" or "SHORT"')
3140
+ request: dict = {
3141
+ 'lever': leverage,
3142
+ 'mgnMode': marginMode.upper(),
3143
+ 'symbol': market['id'],
3144
+ }
3145
+ response = await self.swapPrivatePostV3PositionLeverage(self.extend(request, params))
3146
+ return response
3147
+
3148
+ async def fetch_leverage(self, symbol: str, params={}) -> Leverage:
3149
+ """
3150
+ fetch the set leverage for a market
3151
+
3152
+ https://api-docs.poloniex.com/v3/futures/api/positions/get-leverages
3153
+
3154
+ :param str symbol: unified market symbol
3155
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3156
+ :returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
3157
+ """
3158
+ await self.load_markets()
3159
+ market = self.market(symbol)
3160
+ request: dict = {
3161
+ 'symbol': market['id'],
3162
+ }
3163
+ marginMode = None
3164
+ marginMode, params = self.handle_margin_mode_and_params('fetchLeverage', params)
3165
+ if marginMode is None:
3166
+ raise ArgumentsRequired(self.id + ' fetchLeverage() requires a marginMode parameter "cross" or "isolated"')
3167
+ request['mgnMode'] = marginMode.upper()
3168
+ response = await self.swapPrivateGetV3PositionLeverages(self.extend(request, params))
3169
+ #
3170
+ # for one-way mode:
3171
+ #
3172
+ # {
3173
+ # "code": "200",
3174
+ # "msg": "",
3175
+ # "data": [
3176
+ # {
3177
+ # "symbol": "BTC_USDT_PERP",
3178
+ # "lever": "10",
3179
+ # "mgnMode": "CROSS",
3180
+ # "posSide": "BOTH"
3181
+ # }
3182
+ # ]
3183
+ # }
3184
+ #
3185
+ # for hedge:
3186
+ #
3187
+ # {
3188
+ # "code": "200",
3189
+ # "msg": "",
3190
+ # "data": [
3191
+ # {
3192
+ # "symbol": "BTC_USDT_PERP",
3193
+ # "lever": "20",
3194
+ # "mgnMode": "CROSS",
3195
+ # "posSide": "SHORT"
3196
+ # },
3197
+ # {
3198
+ # "symbol": "BTC_USDT_PERP",
3199
+ # "lever": "20",
3200
+ # "mgnMode": "CROSS",
3201
+ # "posSide": "LONG"
3202
+ # }
3203
+ # ]
3204
+ # }
3205
+ #
3206
+ return self.parse_leverage(response, market)
3207
+
3208
+ def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
3209
+ shortLeverage: Int = None
3210
+ longLeverage: Int = None
3211
+ marketId: Str = None
3212
+ marginMode: Str = None
3213
+ data = self.safe_list(leverage, 'data')
3214
+ for i in range(0, len(data)):
3215
+ entry = data[i]
3216
+ marketId = self.safe_string(entry, 'symbol')
3217
+ marginMode = self.safe_string(entry, 'mgnMode')
3218
+ lever = self.safe_integer(entry, 'lever')
3219
+ posSide = self.safe_string(entry, 'posSide')
3220
+ if posSide == 'LONG':
3221
+ longLeverage = lever
3222
+ elif posSide == 'SHORT':
3223
+ shortLeverage = lever
3224
+ else:
3225
+ longLeverage = lever
3226
+ shortLeverage = lever
3227
+ return {
3228
+ 'info': leverage,
3229
+ 'symbol': self.safe_symbol(marketId, market),
3230
+ 'marginMode': marginMode,
3231
+ 'longLeverage': longLeverage,
3232
+ 'shortLeverage': shortLeverage,
3233
+ }
3234
+
3235
+ async def fetch_position_mode(self, symbol: Str = None, params={}):
3236
+ """
3237
+ fetchs the position mode, hedged or one way, hedged for binance is set identically for all linear markets or all inverse markets
3238
+
3239
+ https://api-docs.poloniex.com/v3/futures/api/positions/position-mode-switch
3240
+
3241
+ :param str symbol: unified symbol of the market to fetch the order book for
3242
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3243
+ :returns dict: an object detailing whether the market is in hedged or one-way mode
3244
+ """
3245
+ response = await self.swapPrivateGetV3PositionMode(params)
3246
+ #
3247
+ # {
3248
+ # "code": "200",
3249
+ # "msg": "Success",
3250
+ # "data": {
3251
+ # "posMode": "ONE_WAY"
3252
+ # }
3253
+ # }
3254
+ #
3255
+ data = self.safe_dict(response, 'data', {})
3256
+ posMode = self.safe_string(data, 'posMode')
3257
+ hedged = posMode == 'HEDGE'
3258
+ return {
3259
+ 'info': response,
3260
+ 'hedged': hedged,
3261
+ }
3262
+
3263
+ async def set_position_mode(self, hedged: bool, symbol: Str = None, params={}):
3264
+ """
3265
+ set hedged to True or False for a market
3266
+
3267
+ https://api-docs.poloniex.com/v3/futures/api/positions/position-mode-switch
3268
+
3269
+ :param bool hedged: set to True to use dualSidePosition
3270
+ :param str symbol: not used by binance setPositionMode()
3271
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3272
+ :returns dict: response from the exchange
3273
+ """
3274
+ mode = 'HEDGE' if hedged else 'ONE_WAY'
3275
+ request: dict = {
3276
+ 'posMode': mode,
3277
+ }
3278
+ response = await self.swapPrivatePostV3PositionMode(self.extend(request, params))
3279
+ #
3280
+ # {
3281
+ # "code": "200",
3282
+ # "msg": "Success",
3283
+ # "data": {}
3284
+ # }
3285
+ #
3286
+ return response
3287
+
3288
+ async def fetch_positions(self, symbols: Strings = None, params={}):
3289
+ """
3290
+ fetch all open positions
3291
+
3292
+ https://api-docs.poloniex.com/v3/futures/api/positions/get-current-position
3293
+
3294
+ :param str[]|None symbols: list of unified market symbols
3295
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3296
+ :param boolean [params.standard]: whether to fetch standard contract positions
3297
+ :returns dict[]: a list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
3298
+ """
3299
+ await self.load_markets()
3300
+ symbols = self.market_symbols(symbols)
3301
+ response = await self.swapPrivateGetV3TradePositionOpens(params)
3302
+ #
3303
+ # {
3304
+ # "code": "200",
3305
+ # "msg": "",
3306
+ # "data": [
3307
+ # {
3308
+ # "symbol": "BTC_USDT_PERP",
3309
+ # "posSide": "LONG",
3310
+ # "side": "BUY",
3311
+ # "mgnMode": "CROSS",
3312
+ # "openAvgPx": "94193.42",
3313
+ # "qty": "1",
3314
+ # "availQty": "1",
3315
+ # "lever": "20",
3316
+ # "adl": "0.3007",
3317
+ # "liqPx": "84918.201844064386317906",
3318
+ # "im": "4.7047795",
3319
+ # "mm": "0.56457354",
3320
+ # "upl": "-0.09783",
3321
+ # "uplRatio": "-0.0207",
3322
+ # "pnl": "0",
3323
+ # "markPx": "94095.59",
3324
+ # "mgnRatio": "0.0582",
3325
+ # "state": "NORMAL",
3326
+ # "cTime": "1740950344401",
3327
+ # "uTime": "1740950344401",
3328
+ # "mgn": "4.7047795",
3329
+ # "actType": "TRADING",
3330
+ # "maxWAmt": "0",
3331
+ # "tpTrgPx": "",
3332
+ # "slTrgPx": ""
3333
+ # }
3334
+ # ]
3335
+ # }
3336
+ #
3337
+ positions = self.safe_list(response, 'data', [])
3338
+ return self.parse_positions(positions, symbols)
3339
+
3340
+ def parse_position(self, position: dict, market: Market = None):
3341
+ #
3342
+ # {
3343
+ # "symbol": "BTC_USDT_PERP",
3344
+ # "posSide": "LONG",
3345
+ # "side": "BUY",
3346
+ # "mgnMode": "CROSS",
3347
+ # "openAvgPx": "94193.42",
3348
+ # "qty": "1",
3349
+ # "availQty": "1",
3350
+ # "lever": "20",
3351
+ # "adl": "0.3007",
3352
+ # "liqPx": "84918.201844064386317906",
3353
+ # "im": "4.7047795",
3354
+ # "mm": "0.56457354",
3355
+ # "upl": "-0.09783",
3356
+ # "uplRatio": "-0.0207",
3357
+ # "pnl": "0",
3358
+ # "markPx": "94095.59",
3359
+ # "mgnRatio": "0.0582",
3360
+ # "state": "NORMAL",
3361
+ # "cTime": "1740950344401",
3362
+ # "uTime": "1740950344401",
3363
+ # "mgn": "4.7047795",
3364
+ # "actType": "TRADING",
3365
+ # "maxWAmt": "0",
3366
+ # "tpTrgPx": "",
3367
+ # "slTrgPx": ""
3368
+ # }
3369
+ #
3370
+ marketId = self.safe_string(position, 'symbol')
3371
+ market = self.safe_market(marketId, market)
3372
+ timestamp = self.safe_integer(position, 'cTime')
3373
+ marginMode = self.safe_string_lower(position, 'mgnMode')
3374
+ leverage = self.safe_string(position, 'lever')
3375
+ initialMargin = self.safe_string(position, 'im')
3376
+ notional = Precise.string_mul(leverage, initialMargin)
3377
+ qty = self.safe_string(position, 'qty')
3378
+ avgPrice = self.safe_string(position, 'openAvgPx')
3379
+ collateral = Precise.string_mul(qty, avgPrice)
3380
+ # todo: some more fields
3381
+ return self.safe_position({
3382
+ 'info': position,
3383
+ 'id': None,
3384
+ 'symbol': market['symbol'],
3385
+ 'notional': notional,
3386
+ 'marginMode': marginMode,
3387
+ 'liquidationPrice': self.safe_number(position, 'liqPx'),
3388
+ 'entryPrice': self.safe_number(position, 'openAvgPx'),
3389
+ 'unrealizedPnl': self.safe_number(position, 'upl'),
3390
+ 'percentage': None,
3391
+ 'contracts': self.safe_number(position, 'qty'),
3392
+ 'contractSize': None,
3393
+ 'markPrice': self.safe_number(position, 'markPx'),
3394
+ 'lastPrice': None,
3395
+ 'side': self.safe_string_lower(position, 'posSide'),
3396
+ 'hedged': None,
3397
+ 'timestamp': timestamp,
3398
+ 'datetime': self.iso8601(timestamp),
3399
+ 'lastUpdateTimestamp': None,
3400
+ 'maintenanceMargin': self.safe_number(position, 'mm'),
3401
+ 'maintenanceMarginPercentage': None,
3402
+ 'collateral': collateral,
3403
+ 'initialMargin': initialMargin,
3404
+ 'initialMarginPercentage': None,
3405
+ 'leverage': int(leverage),
3406
+ 'marginRatio': self.safe_number(position, 'mgnRatio'),
3407
+ 'stopLossPrice': self.safe_number(position, 'slTrgPx'),
3408
+ 'takeProfitPrice': self.safe_number(position, 'tpTrgPx'),
3409
+ })
3410
+
3411
+ async def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
3412
+ await self.load_markets()
3413
+ market = self.market(symbol)
3414
+ amount = self.amount_to_precision(symbol, amount)
3415
+ request: dict = {
3416
+ 'symbol': market['id'],
3417
+ 'amt': Precise.string_abs(amount),
3418
+ 'type': type.upper(), # 'ADD' or 'REDUCE'
3419
+ }
3420
+ # todo: hedged handling, tricky
3421
+ if not ('posMode' in params):
3422
+ request['posMode'] = 'BOTH'
3423
+ response = await self.swapPrivatePostV3TradePositionMargin(self.extend(request, params))
3424
+ #
3425
+ # {
3426
+ # "code": 200,
3427
+ # "data": {
3428
+ # "amt": "50",
3429
+ # "lever": "20",
3430
+ # "symbol": "DOT_USDT_PERP",
3431
+ # "posSide": "BOTH",
3432
+ # "type": "ADD"
3433
+ # },
3434
+ # "msg": "Success"
3435
+ # }
3436
+ #
3437
+ if type == 'reduce':
3438
+ amount = Precise.string_abs(amount)
3439
+ data = self.safe_dict(response, 'data')
3440
+ return self.parse_margin_modification(data, market)
3441
+
3442
+ def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
3443
+ marketId = self.safe_string(data, 'symbol')
3444
+ market = self.safe_market(marketId, market)
3445
+ rawType = self.safe_string(data, 'type')
3446
+ type = 'add' if (rawType == 'ADD') else 'reduce'
3447
+ return {
3448
+ 'info': data,
3449
+ 'symbol': market['symbol'],
3450
+ 'type': type,
3451
+ 'marginMode': None,
3452
+ 'amount': self.safe_number(data, 'amt'),
3453
+ 'total': None,
3454
+ 'code': None,
3455
+ 'status': 'ok',
3456
+ 'timestamp': None,
3457
+ 'datetime': None,
3458
+ }
3459
+
3460
+ async def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3461
+ """
3462
+ remove margin from a position
3463
+ :param str symbol: unified market symbol
3464
+ :param float amount: the amount of margin to remove
3465
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3466
+ :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
3467
+ """
3468
+ return await self.modify_margin_helper(symbol, -amount, 'reduce', params)
3469
+
3470
+ async def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3471
+ """
3472
+ add margin
3473
+ :param str symbol: unified market symbol
3474
+ :param float amount: amount of margin to add
3475
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3476
+ :returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
3477
+ """
3478
+ return await self.modify_margin_helper(symbol, amount, 'add', params)
3479
+
2303
3480
  def nonce(self):
2304
3481
  return self.milliseconds()
2305
3482
 
2306
3483
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2307
- url = self.urls['api']['rest']
3484
+ url = self.urls['api']['spot']
3485
+ if self.in_array(api, ['swapPublic', 'swapPrivate']):
3486
+ url = self.urls['api']['swap']
2308
3487
  query = self.omit(params, self.extract_params(path))
2309
3488
  implodedPath = self.implode_params(path, params)
2310
- if api == 'public':
3489
+ if api == 'public' or api == 'swapPublic':
2311
3490
  url += '/' + implodedPath
2312
3491
  if query:
2313
3492
  url += '?' + self.urlencode(query)