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