bitget 0.0.78__py3-none-any.whl → 0.0.80__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.
@@ -827,6 +827,7 @@ class bitget(Exchange, ImplicitAPI):
827
827
  'get': {
828
828
  'v3/account/assets': 1,
829
829
  'v3/account/settings': 1,
830
+ 'v3/account/deposit-records': 2,
830
831
  'v3/account/financial-records': 1,
831
832
  'v3/account/repayable-coins': 2,
832
833
  'v3/account/payment-coins': 2,
@@ -845,7 +846,9 @@ class bitget(Exchange, ImplicitAPI):
845
846
  'v3/position/history-position': 1,
846
847
  'v3/trade/order-info': 1,
847
848
  'v3/trade/unfilled-orders': 1,
849
+ 'v3/trade/unfilled-strategy-orders': 1,
848
850
  'v3/trade/history-orders': 1,
851
+ 'v3/trade/history-strategy-orders': 1,
849
852
  'v3/trade/fills': 1,
850
853
  'v3/user/sub-list': 2,
851
854
  'v3/user/sub-api-list': 2,
@@ -859,8 +862,11 @@ class bitget(Exchange, ImplicitAPI):
859
862
  'v3/account/max-open-available': 4,
860
863
  'v3/ins-loan/bind-uid': 6.6667,
861
864
  'v3/trade/place-order': 2,
865
+ 'v3/trade/place-strategy-order': 2,
862
866
  'v3/trade/modify-order': 2,
867
+ 'v3/trade/modify-strategy-order': 2,
863
868
  'v3/trade/cancel-order': 2,
869
+ 'v3/trade/cancel-strategy-order': 2,
864
870
  'v3/trade/place-batch': 4,
865
871
  'v3/trade/batch-modify-order': 2,
866
872
  'v3/trade/cancel-batch': 4,
@@ -906,6 +912,7 @@ class bitget(Exchange, ImplicitAPI):
906
912
  # '0': ExchangeError, # 200 successful,when the order placement / cancellation / operation is successful
907
913
  '4001': ExchangeError, # no data received in 30s
908
914
  '4002': ExchangeError, # Buffer full. cannot write data
915
+ '40020': BadRequest, # {"code":"40020","msg":"Parameter orderId error","requestTime":1754305078588,"data":null}
909
916
  # --------------------------------------------------------
910
917
  '30001': AuthenticationError, # {"code": 30001, "message": 'request header "OK_ACCESS_KEY" cannot be blank'}
911
918
  '30002': AuthenticationError, # {"code": 30002, "message": 'request header "OK_ACCESS_SIGN" cannot be blank'}
@@ -1450,6 +1457,19 @@ class bitget(Exchange, ImplicitAPI):
1450
1457
  '1w': '1Wutc',
1451
1458
  '1M': '1Mutc',
1452
1459
  },
1460
+ 'uta': {
1461
+ '1m': '1m',
1462
+ '3m': '3m',
1463
+ '5m': '5m',
1464
+ '15m': '15m',
1465
+ '30m': '30m',
1466
+ '1h': '1H',
1467
+ '2h': '2H',
1468
+ '4h': '4H',
1469
+ '6h': '6H',
1470
+ '12h': '12H',
1471
+ '1d': '1D',
1472
+ },
1453
1473
  },
1454
1474
  'fetchMarkets': {
1455
1475
  'types': ['spot', 'swap'], # there is future markets but they use the same endpoints
@@ -1539,7 +1559,6 @@ class bitget(Exchange, ImplicitAPI):
1539
1559
  'ERC20': 'ERC20',
1540
1560
  'BEP20': 'BSC',
1541
1561
  # 'BEP20': 'BEP20', # different for BEP20
1542
- 'BSC': 'BEP20',
1543
1562
  'ATOM': 'ATOM',
1544
1563
  'ACA': 'AcalaToken',
1545
1564
  'APT': 'Aptos',
@@ -1793,10 +1812,17 @@ class bitget(Exchange, ImplicitAPI):
1793
1812
  # else:
1794
1813
  defaultProductType = 'USDT-FUTURES' if (subType == 'linear') else 'COIN-FUTURES'
1795
1814
  # }
1796
- productType = self.safe_string(params, 'productType', defaultProductType)
1815
+ productType = self.safe_string_2(params, 'productType', 'category', defaultProductType)
1797
1816
  if (productType is None) and (market is not None):
1798
1817
  settle = market['settle']
1799
- if settle == 'USDT':
1818
+ if market['spot']:
1819
+ marginMode = None
1820
+ marginMode, params = self.handle_margin_mode_and_params('handleProductTypeAndParams', params)
1821
+ if marginMode is not None:
1822
+ productType = 'MARGIN'
1823
+ else:
1824
+ productType = 'SPOT'
1825
+ elif settle == 'USDT':
1800
1826
  productType = 'USDT-FUTURES'
1801
1827
  elif settle == 'USDC':
1802
1828
  productType = 'USDC-FUTURES'
@@ -1809,8 +1835,8 @@ class bitget(Exchange, ImplicitAPI):
1809
1835
  else:
1810
1836
  productType = 'COIN-FUTURES'
1811
1837
  if productType is None:
1812
- raise ArgumentsRequired(self.id + ' requires a productType param, one of "USDT-FUTURES", "USDC-FUTURES", "COIN-FUTURES", "SUSDT-FUTURES", "SUSDC-FUTURES" or "SCOIN-FUTURES"')
1813
- params = self.omit(params, 'productType')
1838
+ raise ArgumentsRequired(self.id + ' requires a productType param, one of "USDT-FUTURES", "USDC-FUTURES", "COIN-FUTURES", "SUSDT-FUTURES", "SUSDC-FUTURES", "SCOIN-FUTURES" or for uta only "SPOT"')
1839
+ params = self.omit(params, ['productType', 'category'])
1814
1840
  return [productType, params]
1815
1841
 
1816
1842
  async def fetch_time(self, params={}) -> Int:
@@ -1843,10 +1869,10 @@ class bitget(Exchange, ImplicitAPI):
1843
1869
  https://www.bitget.com/api-doc/spot/market/Get-Symbols
1844
1870
  https://www.bitget.com/api-doc/contract/market/Get-All-Symbols-Contracts
1845
1871
  https://www.bitget.com/api-doc/margin/common/support-currencies
1846
- https://www.bitget.bike/api-doc/uta/public/Instruments
1872
+ https://www.bitget.com/api-doc/uta/public/Instruments
1847
1873
 
1848
1874
  :param dict [params]: extra parameters specific to the exchange API endpoint
1849
- :param str [params.uta]: set to True to fetch markets for the unified trading account(uta), defaults to False
1875
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
1850
1876
  :returns dict[]: an array of objects representing market data
1851
1877
  """
1852
1878
  if self.options['adjustForTimeDifference']:
@@ -2453,12 +2479,14 @@ class bitget(Exchange, ImplicitAPI):
2453
2479
  https://www.bitget.com/api-doc/contract/position/Get-Query-Position-Lever
2454
2480
  https://www.bitget.com/api-doc/margin/cross/account/Cross-Tier-Data
2455
2481
  https://www.bitget.com/api-doc/margin/isolated/account/Isolated-Tier-Data
2482
+ https://www.bitget.com/api-doc/uta/public/Get-Position-Tier-Data
2456
2483
 
2457
2484
  :param str symbol: unified market symbol
2458
2485
  :param dict [params]: extra parameters specific to the exchange API endpoint
2459
2486
  :param str [params.marginMode]: for spot margin 'cross' or 'isolated', default is 'isolated'
2460
2487
  :param str [params.code]: required for cross spot margin
2461
- :param str [params.productType]: *contract only* 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
2488
+ :param str [params.productType]: *contract and uta only* 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
2489
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
2462
2490
  :returns dict: a `leverage tiers structure <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`
2463
2491
  """
2464
2492
  await self.load_markets()
@@ -2466,10 +2494,19 @@ class bitget(Exchange, ImplicitAPI):
2466
2494
  request: dict = {}
2467
2495
  response = None
2468
2496
  marginMode = None
2497
+ productType = None
2498
+ uta = None
2469
2499
  marginMode, params = self.handle_margin_mode_and_params('fetchMarketLeverageTiers', params, 'isolated')
2470
- if (market['swap']) or (market['future']):
2471
- productType = None
2472
- productType, params = self.handle_product_type_and_params(market, params)
2500
+ productType, params = self.handle_product_type_and_params(market, params)
2501
+ uta, params = self.handle_option_and_params(params, 'fetchMarketLeverageTiers', 'uta', False)
2502
+ if uta:
2503
+ if productType == 'SPOT':
2504
+ if marginMode is not None:
2505
+ productType = 'MARGIN'
2506
+ request['symbol'] = market['id']
2507
+ request['category'] = productType
2508
+ response = await self.publicUtaGetV3MarketPositionTier(self.extend(request, params))
2509
+ elif (market['swap']) or (market['future']):
2473
2510
  request['productType'] = productType
2474
2511
  request['symbol'] = market['id']
2475
2512
  response = await self.publicMixGetV2MixMarketQueryPositionLever(self.extend(request, params))
@@ -2543,6 +2580,23 @@ class bitget(Exchange, ImplicitAPI):
2543
2580
  # ]
2544
2581
  # }
2545
2582
  #
2583
+ # uta
2584
+ #
2585
+ # {
2586
+ # "code": "00000",
2587
+ # "msg": "success",
2588
+ # "requestTime": 1752735673127,
2589
+ # "data": [
2590
+ # {
2591
+ # "tier": "1",
2592
+ # "minTierValue": "0",
2593
+ # "maxTierValue": "150000",
2594
+ # "leverage": "125",
2595
+ # "mmr": "0.004"
2596
+ # },
2597
+ # ]
2598
+ # }
2599
+ #
2546
2600
  result = self.safe_value(response, 'data', [])
2547
2601
  return self.parse_market_leverage_tiers(result, market)
2548
2602
 
@@ -2583,14 +2637,24 @@ class bitget(Exchange, ImplicitAPI):
2583
2637
  # "maintainMarginRate": "0.1"
2584
2638
  # }
2585
2639
  #
2640
+ # uta
2641
+ #
2642
+ # {
2643
+ # "tier": "1",
2644
+ # "minTierValue": "0",
2645
+ # "maxTierValue": "150000",
2646
+ # "leverage": "125",
2647
+ # "mmr": "0.004"
2648
+ # }
2649
+ #
2586
2650
  tiers = []
2587
2651
  minNotional = 0
2588
2652
  for i in range(0, len(info)):
2589
2653
  item = info[i]
2590
- minimumNotional = self.safe_number(item, 'startUnit')
2654
+ minimumNotional = self.safe_number_2(item, 'startUnit', 'minTierValue')
2591
2655
  if minimumNotional is not None:
2592
2656
  minNotional = minimumNotional
2593
- maxNotional = self.safe_number_n(item, ['endUnit', 'maxBorrowableAmount', 'baseMaxBorrowableAmount'])
2657
+ maxNotional = self.safe_number_n(item, ['endUnit', 'maxBorrowableAmount', 'baseMaxBorrowableAmount', 'maxTierValue'])
2594
2658
  marginCurrency = self.safe_string_2(item, 'coin', 'baseCoin')
2595
2659
  currencyId = marginCurrency if (marginCurrency is not None) else market['base']
2596
2660
  marketId = self.safe_string(item, 'symbol')
@@ -2600,7 +2664,7 @@ class bitget(Exchange, ImplicitAPI):
2600
2664
  'currency': self.safe_currency_code(currencyId),
2601
2665
  'minNotional': minNotional,
2602
2666
  'maxNotional': maxNotional,
2603
- 'maintenanceMarginRate': self.safe_number_2(item, 'keepMarginRate', 'maintainMarginRate'),
2667
+ 'maintenanceMarginRate': self.safe_number_n(item, ['keepMarginRate', 'maintainMarginRate', 'mmr']),
2604
2668
  'maxLeverage': self.safe_number(item, 'leverage'),
2605
2669
  'info': item,
2606
2670
  })
@@ -2942,10 +3006,12 @@ class bitget(Exchange, ImplicitAPI):
2942
3006
 
2943
3007
  https://www.bitget.com/api-doc/spot/market/Get-Orderbook
2944
3008
  https://www.bitget.com/api-doc/contract/market/Get-Merge-Depth
3009
+ https://www.bitget.com/api-doc/uta/public/OrderBook
2945
3010
 
2946
3011
  :param str symbol: unified symbol of the market to fetch the order book for
2947
3012
  :param int [limit]: the maximum amount of order book entries to return
2948
3013
  :param dict [params]: extra parameters specific to the exchange API endpoint
3014
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
2949
3015
  :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
2950
3016
  """
2951
3017
  await self.load_markets()
@@ -2955,12 +3021,17 @@ class bitget(Exchange, ImplicitAPI):
2955
3021
  }
2956
3022
  if limit is not None:
2957
3023
  request['limit'] = limit
3024
+ productType = None
3025
+ productType, params = self.handle_product_type_and_params(market, params)
2958
3026
  response = None
2959
- if market['spot']:
3027
+ uta = None
3028
+ uta, params = self.handle_option_and_params(params, 'fetchOrderBook', 'uta', False)
3029
+ if uta:
3030
+ request['category'] = productType
3031
+ response = await self.publicUtaGetV3MarketOrderbook(self.extend(request, params))
3032
+ elif market['spot']:
2960
3033
  response = await self.publicSpotGetV2SpotMarketOrderbook(self.extend(request, params))
2961
3034
  else:
2962
- productType = None
2963
- productType, params = self.handle_product_type_and_params(market, params)
2964
3035
  request['productType'] = productType
2965
3036
  response = await self.publicMixGetV2MixMarketMergeDepth(self.extend(request, params))
2966
3037
  #
@@ -2975,9 +3046,24 @@ class bitget(Exchange, ImplicitAPI):
2975
3046
  # }
2976
3047
  # }
2977
3048
  #
3049
+ # uta
3050
+ #
3051
+ # {
3052
+ # "code": "00000",
3053
+ # "msg": "success",
3054
+ # "requestTime": 1750329437753,
3055
+ # "data": {
3056
+ # "a": [[104992.60, 0.018411]],
3057
+ # "b":[[104927.40, 0.229914]],
3058
+ # "ts": "1750329437763"
3059
+ # }
3060
+ # }
3061
+ #
2978
3062
  data = self.safe_value(response, 'data', {})
3063
+ bidsKey = 'b' if uta else 'bids'
3064
+ asksKey = 'a' if uta else 'asks'
2979
3065
  timestamp = self.safe_integer(data, 'ts')
2980
- return self.parse_order_book(data, market['symbol'], timestamp)
3066
+ return self.parse_order_book(data, market['symbol'], timestamp, bidsKey, asksKey)
2981
3067
 
2982
3068
  def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
2983
3069
  #
@@ -2989,7 +3075,7 @@ class bitget(Exchange, ImplicitAPI):
2989
3075
  # "ts": "1695793390482"
2990
3076
  # }
2991
3077
  #
2992
- # spot: fetchTicker, fetchTickers
3078
+ # spot
2993
3079
  #
2994
3080
  # {
2995
3081
  # "open": "37202.46",
@@ -3010,90 +3096,115 @@ class bitget(Exchange, ImplicitAPI):
3010
3096
  # "change24h": "0.00321"
3011
3097
  # }
3012
3098
  #
3013
- # swap and future: fetchTicker
3099
+ # swap and future
3014
3100
  #
3015
3101
  # {
3016
3102
  # "symbol": "BTCUSDT",
3017
- # "lastPr": "37577.2",
3018
- # "askPr": "37577.3",
3019
- # "bidPr": "37577.2",
3020
- # "bidSz": "3.679",
3021
- # "askSz": "0.02",
3022
- # "high24h": "37765",
3023
- # "low24h": "36628.9",
3024
- # "ts": "1700533070359",
3025
- # "change24h": "0.00288",
3026
- # "baseVolume": "108606.181",
3027
- # "quoteVolume": "4051316303.9608",
3028
- # "usdtVolume": "4051316303.9608",
3029
- # "openUtc": "37451.5",
3030
- # "changeUtc24h": "0.00336",
3031
- # "indexPrice": "37574.489253",
3032
- # "fundingRate": "0.0001",
3033
- # "holdingAmount": "53464.529",
3103
+ # "lastPr": "104823.8",
3104
+ # "askPr": "104823.8",
3105
+ # "bidPr": "104823.5",
3106
+ # "bidSz": "0.703",
3107
+ # "askSz": "13.894",
3108
+ # "high24h": "105289.3",
3109
+ # "low24h": "103447.9",
3110
+ # "ts": "1750332210370",
3111
+ # "change24h": "0.00471",
3112
+ # "baseVolume": "79089.5675",
3113
+ # "quoteVolume": "8274870921.80485",
3114
+ # "usdtVolume": "8274870921.80485",
3115
+ # "openUtc": "104833",
3116
+ # "changeUtc24h": "-0.00009",
3117
+ # "indexPrice": "104881.953125",
3118
+ # "fundingRate": "-0.000014",
3119
+ # "holdingAmount": "7452.6421",
3034
3120
  # "deliveryStartTime": null,
3035
3121
  # "deliveryTime": null,
3036
3122
  # "deliveryStatus": "",
3037
- # "open24h": "37235.7"
3123
+ # "open24h": "104332.3",
3124
+ # "markPrice": "104824.2"
3125
+ # }
3126
+ #
3127
+ # spot uta
3128
+ #
3129
+ # {
3130
+ # "category": "SPOT",
3131
+ # "symbol": "BTCUSDT",
3132
+ # "ts": "1750330651972",
3133
+ # "lastPrice": "104900.2",
3134
+ # "openPrice24h": "104321.2",
3135
+ # "highPrice24h": "107956.8",
3136
+ # "lowPrice24h": "103600.1",
3137
+ # "ask1Price": "104945.8",
3138
+ # "bid1Price": "104880.6",
3139
+ # "bid1Size": "0.266534",
3140
+ # "ask1Size": "0.014001",
3141
+ # "price24hPcnt": "0.00555",
3142
+ # "volume24h": "355.941109",
3143
+ # "turnover24h": "37302936.008134"
3038
3144
  # }
3039
3145
  #
3040
- # swap and future: fetchTickers
3146
+ # swap and future uta
3041
3147
  #
3042
3148
  # {
3043
- # "open": "14.9776",
3044
- # "symbol": "LINKUSDT",
3045
- # "high24h": "15.3942",
3046
- # "low24h": "14.3457",
3047
- # "lastPr": "14.3748",
3048
- # "quoteVolume": "7008612.4299",
3049
- # "baseVolume": "469908.8523",
3050
- # "usdtVolume": "7008612.42986561",
3051
- # "ts": "1700533772309",
3052
- # "bidPr": "14.375",
3053
- # "askPr": "14.3769",
3054
- # "bidSz": "50.004",
3055
- # "askSz": "0.7647",
3056
- # "openUtc": "14.478",
3057
- # "changeUtc24h": "-0.00713",
3058
- # "change24h": "-0.04978"
3149
+ # "category": "USDT-FUTURES",
3150
+ # "symbol": "BTCUSDT",
3151
+ # "ts": "1750332730472",
3152
+ # "lastPrice": "104738",
3153
+ # "openPrice24h": "104374",
3154
+ # "highPrice24h": "105289.3",
3155
+ # "lowPrice24h": "103447.9",
3156
+ # "ask1Price": "104738",
3157
+ # "bid1Price": "104737.7",
3158
+ # "bid1Size": "2.036",
3159
+ # "ask1Size": "8.094",
3160
+ # "price24hPcnt": "0.00349",
3161
+ # "volume24h": "79101.6477",
3162
+ # "turnover24h": "8276293391.45973",
3163
+ # "indexPrice": "104785.956168",
3164
+ # "markPrice": "104738",
3165
+ # "fundingRate": "-0.000007",
3166
+ # "openInterest": "7465.5938",
3167
+ # "deliveryStartTime": "",
3168
+ # "deliveryTime": "",
3169
+ # "deliveryStatus": ""
3059
3170
  # }
3060
3171
  #
3061
3172
  marketId = self.safe_string(ticker, 'symbol')
3062
- close = self.safe_string(ticker, 'lastPr')
3173
+ close = self.safe_string_2(ticker, 'lastPr', 'lastPrice')
3063
3174
  timestamp = self.safe_integer_omit_zero(ticker, 'ts') # exchange bitget provided 0
3064
3175
  change = self.safe_string(ticker, 'change24h')
3065
- open24 = self.safe_string_2(ticker, 'open24', 'open24h')
3066
- open = self.safe_string(ticker, 'open')
3067
- symbol: str
3068
- openValue: str
3069
- if open is None:
3070
- symbol = self.safe_symbol(marketId, market, None, 'contract')
3071
- openValue = open24
3176
+ category = self.safe_string(ticker, 'category')
3177
+ markPrice = self.safe_string(ticker, 'markPrice')
3178
+ marketType: str
3179
+ if (markPrice is not None) and (category != 'SPOT'):
3180
+ marketType = 'contract'
3072
3181
  else:
3073
- symbol = self.safe_symbol(marketId, market, None, 'spot')
3074
- openValue = open
3182
+ marketType = 'spot'
3183
+ percentage = self.safe_string(ticker, 'price24hPcnt')
3184
+ if percentage is None:
3185
+ percentage = Precise.string_mul(change, '100')
3075
3186
  return self.safe_ticker({
3076
- 'symbol': symbol,
3187
+ 'symbol': self.safe_symbol(marketId, market, None, marketType),
3077
3188
  'timestamp': timestamp,
3078
3189
  'datetime': self.iso8601(timestamp),
3079
- 'high': self.safe_string(ticker, 'high24h'),
3080
- 'low': self.safe_string(ticker, 'low24h'),
3081
- 'bid': self.safe_string(ticker, 'bidPr'),
3082
- 'bidVolume': self.safe_string(ticker, 'bidSz'),
3083
- 'ask': self.safe_string(ticker, 'askPr'),
3084
- 'askVolume': self.safe_string(ticker, 'askSz'),
3190
+ 'high': self.safe_string_2(ticker, 'high24h', 'highPrice24h'),
3191
+ 'low': self.safe_string_2(ticker, 'low24h', 'lowPrice24h'),
3192
+ 'bid': self.safe_string_2(ticker, 'bidPr', 'bid1Price'),
3193
+ 'bidVolume': self.safe_string_2(ticker, 'bidSz', 'bid1Size'),
3194
+ 'ask': self.safe_string_2(ticker, 'askPr', 'ask1Price'),
3195
+ 'askVolume': self.safe_string_2(ticker, 'askSz', 'ask1Size'),
3085
3196
  'vwap': None,
3086
- 'open': openValue,
3197
+ 'open': self.safe_string_n(ticker, ['open', 'open24h', 'openPrice24h']),
3087
3198
  'close': close,
3088
3199
  'last': close,
3089
3200
  'previousClose': None,
3090
3201
  'change': change,
3091
- 'percentage': Precise.string_mul(change, '100'),
3202
+ 'percentage': percentage,
3092
3203
  'average': None,
3093
- 'baseVolume': self.safe_string(ticker, 'baseVolume'),
3094
- 'quoteVolume': self.safe_string(ticker, 'quoteVolume'),
3204
+ 'baseVolume': self.safe_string_2(ticker, 'baseVolume', 'volume24h'),
3205
+ 'quoteVolume': self.safe_string_2(ticker, 'quoteVolume', 'turnover24h'),
3095
3206
  'indexPrice': self.safe_string(ticker, 'indexPrice'),
3096
- 'markPrice': self.safe_string(ticker, 'markPrice'),
3207
+ 'markPrice': markPrice,
3097
3208
  'info': ticker,
3098
3209
  }, market)
3099
3210
 
@@ -3103,9 +3214,11 @@ class bitget(Exchange, ImplicitAPI):
3103
3214
 
3104
3215
  https://www.bitget.com/api-doc/spot/market/Get-Tickers
3105
3216
  https://www.bitget.com/api-doc/contract/market/Get-Ticker
3217
+ https://www.bitget.com/api-doc/uta/public/Tickers
3106
3218
 
3107
3219
  :param str symbol: unified symbol of the market to fetch the ticker for
3108
3220
  :param dict [params]: extra parameters specific to the exchange API endpoint
3221
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
3109
3222
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
3110
3223
  """
3111
3224
  await self.load_markets()
@@ -3113,12 +3226,17 @@ class bitget(Exchange, ImplicitAPI):
3113
3226
  request: dict = {
3114
3227
  'symbol': market['id'],
3115
3228
  }
3229
+ productType = None
3230
+ productType, params = self.handle_product_type_and_params(market, params)
3116
3231
  response = None
3117
- if market['spot']:
3232
+ uta = None
3233
+ uta, params = self.handle_option_and_params(params, 'fetchTicker', 'uta', False)
3234
+ if uta:
3235
+ request['category'] = productType
3236
+ response = await self.publicUtaGetV3MarketTickers(self.extend(request, params))
3237
+ elif market['spot']:
3118
3238
  response = await self.publicSpotGetV2SpotMarketTickers(self.extend(request, params))
3119
3239
  else:
3120
- productType = None
3121
- productType, params = self.handle_product_type_and_params(market, params)
3122
3240
  request['productType'] = productType
3123
3241
  response = await self.publicMixGetV2MixMarketTicker(self.extend(request, params))
3124
3242
  #
@@ -3152,34 +3270,94 @@ class bitget(Exchange, ImplicitAPI):
3152
3270
  #
3153
3271
  # swap and future
3154
3272
  #
3155
- # {
3273
+ # {
3156
3274
  # "code": "00000",
3157
3275
  # "msg": "success",
3158
- # "requestTime": 1700533070357,
3276
+ # "requestTime": 1750332210369,
3159
3277
  # "data": [
3160
3278
  # {
3161
3279
  # "symbol": "BTCUSDT",
3162
- # "lastPr": "37577.2",
3163
- # "askPr": "37577.3",
3164
- # "bidPr": "37577.2",
3165
- # "bidSz": "3.679",
3166
- # "askSz": "0.02",
3167
- # "high24h": "37765",
3168
- # "low24h": "36628.9",
3169
- # "ts": "1700533070359",
3170
- # "change24h": "0.00288",
3171
- # "baseVolume": "108606.181",
3172
- # "quoteVolume": "4051316303.9608",
3173
- # "usdtVolume": "4051316303.9608",
3174
- # "openUtc": "37451.5",
3175
- # "changeUtc24h": "0.00336",
3176
- # "indexPrice": "37574.489253",
3177
- # "fundingRate": "0.0001",
3178
- # "holdingAmount": "53464.529",
3280
+ # "lastPr": "104823.8",
3281
+ # "askPr": "104823.8",
3282
+ # "bidPr": "104823.5",
3283
+ # "bidSz": "0.703",
3284
+ # "askSz": "13.894",
3285
+ # "high24h": "105289.3",
3286
+ # "low24h": "103447.9",
3287
+ # "ts": "1750332210370",
3288
+ # "change24h": "0.00471",
3289
+ # "baseVolume": "79089.5675",
3290
+ # "quoteVolume": "8274870921.80485",
3291
+ # "usdtVolume": "8274870921.80485",
3292
+ # "openUtc": "104833",
3293
+ # "changeUtc24h": "-0.00009",
3294
+ # "indexPrice": "104881.953125",
3295
+ # "fundingRate": "-0.000014",
3296
+ # "holdingAmount": "7452.6421",
3179
3297
  # "deliveryStartTime": null,
3180
3298
  # "deliveryTime": null,
3181
3299
  # "deliveryStatus": "",
3182
- # "open24h": "37235.7"
3300
+ # "open24h": "104332.3",
3301
+ # "markPrice": "104824.2"
3302
+ # }
3303
+ # ]
3304
+ # }
3305
+ #
3306
+ # spot uta
3307
+ #
3308
+ # {
3309
+ # "code": "00000",
3310
+ # "msg": "success",
3311
+ # "requestTime": 1750330653575,
3312
+ # "data": [
3313
+ # {
3314
+ # "category": "SPOT",
3315
+ # "symbol": "BTCUSDT",
3316
+ # "ts": "1750330651972",
3317
+ # "lastPrice": "104900.2",
3318
+ # "openPrice24h": "104321.2",
3319
+ # "highPrice24h": "107956.8",
3320
+ # "lowPrice24h": "103600.1",
3321
+ # "ask1Price": "104945.8",
3322
+ # "bid1Price": "104880.6",
3323
+ # "bid1Size": "0.266534",
3324
+ # "ask1Size": "0.014001",
3325
+ # "price24hPcnt": "0.00555",
3326
+ # "volume24h": "355.941109",
3327
+ # "turnover24h": "37302936.008134"
3328
+ # }
3329
+ # ]
3330
+ # }
3331
+ #
3332
+ # swap and future uta
3333
+ #
3334
+ # {
3335
+ # "code": "00000",
3336
+ # "msg": "success",
3337
+ # "requestTime": 1750332731203,
3338
+ # "data": [
3339
+ # {
3340
+ # "category": "USDT-FUTURES",
3341
+ # "symbol": "BTCUSDT",
3342
+ # "ts": "1750332730472",
3343
+ # "lastPrice": "104738",
3344
+ # "openPrice24h": "104374",
3345
+ # "highPrice24h": "105289.3",
3346
+ # "lowPrice24h": "103447.9",
3347
+ # "ask1Price": "104738",
3348
+ # "bid1Price": "104737.7",
3349
+ # "bid1Size": "2.036",
3350
+ # "ask1Size": "8.094",
3351
+ # "price24hPcnt": "0.00349",
3352
+ # "volume24h": "79101.6477",
3353
+ # "turnover24h": "8276293391.45973",
3354
+ # "indexPrice": "104785.956168",
3355
+ # "markPrice": "104738",
3356
+ # "fundingRate": "-0.000007",
3357
+ # "openInterest": "7465.5938",
3358
+ # "deliveryStartTime": "",
3359
+ # "deliveryTime": "",
3360
+ # "deliveryStatus": ""
3183
3361
  # }
3184
3362
  # ]
3185
3363
  # }
@@ -3219,9 +3397,11 @@ class bitget(Exchange, ImplicitAPI):
3219
3397
 
3220
3398
  https://www.bitget.com/api-doc/spot/market/Get-Tickers
3221
3399
  https://www.bitget.com/api-doc/contract/market/Get-All-Symbol-Ticker
3400
+ https://www.bitget.com/api-doc/uta/public/Tickers
3222
3401
 
3223
3402
  :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
3224
3403
  :param dict [params]: extra parameters specific to the exchange API endpoint
3404
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
3225
3405
  :param str [params.subType]: *contract only* 'linear', 'inverse'
3226
3406
  :param str [params.productType]: *contract only* 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
3227
3407
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -3242,7 +3422,15 @@ class bitget(Exchange, ImplicitAPI):
3242
3422
  productType = None
3243
3423
  productType, params = self.handle_product_type_and_params(market, params)
3244
3424
  # only if passedSubType and productType is None, then use spot
3245
- if type == 'spot' and passedSubType is None:
3425
+ uta = None
3426
+ uta, params = self.handle_option_and_params(params, 'fetchTickers', 'uta', False)
3427
+ if uta:
3428
+ symbolsLength = len(symbols)
3429
+ if (symbols is not None) and (symbolsLength == 1):
3430
+ request['symbol'] = market['id']
3431
+ request['category'] = productType
3432
+ response = await self.publicUtaGetV3MarketTickers(self.extend(request, params))
3433
+ elif type == 'spot' and passedSubType is None:
3246
3434
  response = await self.publicSpotGetV2SpotMarketTickers(self.extend(request, params))
3247
3435
  else:
3248
3436
  request['productType'] = productType
@@ -3304,6 +3492,65 @@ class bitget(Exchange, ImplicitAPI):
3304
3492
  # ]
3305
3493
  # }
3306
3494
  #
3495
+ # spot uta
3496
+ #
3497
+ # {
3498
+ # "code": "00000",
3499
+ # "msg": "success",
3500
+ # "requestTime": 1750330653575,
3501
+ # "data": [
3502
+ # {
3503
+ # "category": "SPOT",
3504
+ # "symbol": "BTCUSDT",
3505
+ # "ts": "1750330651972",
3506
+ # "lastPrice": "104900.2",
3507
+ # "openPrice24h": "104321.2",
3508
+ # "highPrice24h": "107956.8",
3509
+ # "lowPrice24h": "103600.1",
3510
+ # "ask1Price": "104945.8",
3511
+ # "bid1Price": "104880.6",
3512
+ # "bid1Size": "0.266534",
3513
+ # "ask1Size": "0.014001",
3514
+ # "price24hPcnt": "0.00555",
3515
+ # "volume24h": "355.941109",
3516
+ # "turnover24h": "37302936.008134"
3517
+ # }
3518
+ # ]
3519
+ # }
3520
+ #
3521
+ # swap and future uta
3522
+ #
3523
+ # {
3524
+ # "code": "00000",
3525
+ # "msg": "success",
3526
+ # "requestTime": 1750332731203,
3527
+ # "data": [
3528
+ # {
3529
+ # "category": "USDT-FUTURES",
3530
+ # "symbol": "BTCUSDT",
3531
+ # "ts": "1750332730472",
3532
+ # "lastPrice": "104738",
3533
+ # "openPrice24h": "104374",
3534
+ # "highPrice24h": "105289.3",
3535
+ # "lowPrice24h": "103447.9",
3536
+ # "ask1Price": "104738",
3537
+ # "bid1Price": "104737.7",
3538
+ # "bid1Size": "2.036",
3539
+ # "ask1Size": "8.094",
3540
+ # "price24hPcnt": "0.00349",
3541
+ # "volume24h": "79101.6477",
3542
+ # "turnover24h": "8276293391.45973",
3543
+ # "indexPrice": "104785.956168",
3544
+ # "markPrice": "104738",
3545
+ # "fundingRate": "-0.000007",
3546
+ # "openInterest": "7465.5938",
3547
+ # "deliveryStartTime": "",
3548
+ # "deliveryTime": "",
3549
+ # "deliveryStatus": ""
3550
+ # }
3551
+ # ]
3552
+ # }
3553
+ #
3307
3554
  data = self.safe_list(response, 'data', [])
3308
3555
  return self.parse_tickers(data, symbols)
3309
3556
 
@@ -3390,19 +3637,53 @@ class bitget(Exchange, ImplicitAPI):
3390
3637
  # "cTime": "1700720700342"
3391
3638
  # }
3392
3639
  #
3640
+ # uta fetchTrades
3641
+ #
3642
+ # {
3643
+ # "execId": "1319896716324937729",
3644
+ # "price": "105909.1",
3645
+ # "size": "6.3090",
3646
+ # "side": "sell",
3647
+ # "ts": "1750413820344"
3648
+ # }
3649
+ #
3650
+ # uta fetchMyTrades
3651
+ #
3652
+ # {
3653
+ # "execId": "1322441401010528257",
3654
+ # "orderId": "1322441400976261120",
3655
+ # "category": "USDT-FUTURES",
3656
+ # "symbol": "BTCUSDT",
3657
+ # "orderType": "market",
3658
+ # "side": "sell",
3659
+ # "execPrice": "107005.4",
3660
+ # "execQty": "0.0001",
3661
+ # "execValue": "10.7005",
3662
+ # "tradeScope": "taker",
3663
+ # "feeDetail": [{
3664
+ # "feeCoin": "USDT",
3665
+ # "fee":"0.00642032"
3666
+ # }],
3667
+ # "createdTime": "1751020520451",
3668
+ # "updatedTime": "1751020520458",
3669
+ # "execPnl": "0.00017"
3670
+ # }
3671
+ #
3393
3672
  marketId = self.safe_string(trade, 'symbol')
3394
3673
  symbol = self.safe_symbol(marketId, market)
3395
- timestamp = self.safe_integer_2(trade, 'cTime', 'ts')
3674
+ timestamp = self.safe_integer_n(trade, ['cTime', 'ts', 'createdTime'])
3396
3675
  fee = None
3397
3676
  feeDetail = self.safe_value(trade, 'feeDetail')
3398
3677
  posMode = self.safe_string(trade, 'posMode')
3399
- feeStructure = feeDetail[0] if (posMode is not None) else feeDetail
3678
+ category = self.safe_string(trade, 'category')
3679
+ isFeeStructure = (posMode is not None) or (category is not None)
3680
+ feeStructure = feeDetail[0] if isFeeStructure else feeDetail
3400
3681
  if feeStructure is not None:
3401
3682
  currencyCode = self.safe_currency_code(self.safe_string(feeStructure, 'feeCoin'))
3402
3683
  fee = {
3403
3684
  'currency': currencyCode,
3404
3685
  }
3405
- feeCostString = self.safe_string(feeStructure, 'totalFee')
3686
+ feeCostString = self.safe_string_2(feeStructure, 'totalFee', 'fee')
3406
3687
  deduction = self.safe_string(feeStructure, 'deduction') is True if 'yes' else False
3407
3688
  if deduction:
3408
3689
  fee['cost'] = feeCostString
@@ -3410,15 +3691,15 @@ class bitget(Exchange, ImplicitAPI):
3410
3691
  fee['cost'] = Precise.string_neg(feeCostString)
3411
3692
  return self.safe_trade({
3412
3693
  'info': trade,
3413
- 'id': self.safe_string(trade, 'tradeId'),
3694
+ 'id': self.safe_string_2(trade, 'tradeId', 'execId'),
3414
3695
  'order': self.safe_string(trade, 'orderId'),
3415
3696
  'symbol': symbol,
3416
3697
  'side': self.safe_string_lower(trade, 'side'),
3417
3698
  'type': self.safe_string(trade, 'orderType'),
3418
3699
  'takerOrMaker': self.safe_string(trade, 'tradeScope'),
3419
- 'price': self.safe_string_2(trade, 'priceAvg', 'price'),
3420
- 'amount': self.safe_string_2(trade, 'baseVolume', 'size'),
3421
- 'cost': self.safe_string_2(trade, 'quoteVolume', 'amount'),
3700
+ 'price': self.safe_string_n(trade, ['priceAvg', 'price', 'execPrice']),
3701
+ 'amount': self.safe_string_n(trade, ['baseVolume', 'size', 'execQty']),
3702
+ 'cost': self.safe_string_n(trade, ['quoteVolume', 'amount', 'execValue']),
3422
3703
  'timestamp': timestamp,
3423
3704
  'datetime': self.iso8601(timestamp),
3424
3705
  'fee': fee,
@@ -3432,11 +3713,13 @@ class bitget(Exchange, ImplicitAPI):
3432
3713
  https://www.bitget.com/api-doc/spot/market/Get-Market-Trades
3433
3714
  https://www.bitget.com/api-doc/contract/market/Get-Recent-Fills
3434
3715
  https://www.bitget.com/api-doc/contract/market/Get-Fills-History
3716
+ https://www.bitget.com/api-doc/uta/public/Fills
3435
3717
 
3436
3718
  :param str symbol: unified symbol of the market to fetch trades for
3437
3719
  :param int [since]: timestamp in ms of the earliest trade to fetch
3438
3720
  :param int [limit]: the maximum amount of trades to fetch
3439
3721
  :param dict [params]: extra parameters specific to the exchange API endpoint
3722
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
3440
3723
  :param int [params.until]: *only applies to publicSpotGetV2SpotMarketFillsHistory and publicMixGetV2MixMarketFillsHistory* the latest time in ms to fetch trades for
3441
3724
  :param boolean [params.paginate]: *only applies to publicSpotGetV2SpotMarketFillsHistory and publicMixGetV2MixMarketFillsHistory* default False, when True will automatically paginate by calling self endpoint multiple times
3442
3725
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
@@ -3450,14 +3733,28 @@ class bitget(Exchange, ImplicitAPI):
3450
3733
  request: dict = {
3451
3734
  'symbol': market['id'],
3452
3735
  }
3736
+ uta = None
3737
+ uta, params = self.handle_option_and_params(params, 'fetchTrades', 'uta', False)
3453
3738
  if limit is not None:
3454
- if market['contract']:
3739
+ if uta:
3740
+ request['limit'] = min(limit, 100)
3741
+ elif market['contract']:
3455
3742
  request['limit'] = min(limit, 1000)
3456
3743
  else:
3457
3744
  request['limit'] = limit
3458
3745
  options = self.safe_value(self.options, 'fetchTrades', {})
3459
3746
  response = None
3460
- if market['spot']:
3747
+ productType = None
3748
+ productType, params = self.handle_product_type_and_params(market, params)
3749
+ if uta:
3750
+ if productType == 'SPOT':
3751
+ marginMode = None
3752
+ marginMode, params = self.handle_margin_mode_and_params('fetchTrades', params)
3753
+ if marginMode is not None:
3754
+ productType = 'MARGIN'
3755
+ request['category'] = productType
3756
+ response = await self.publicUtaGetV3MarketFills(self.extend(request, params))
3757
+ elif market['spot']:
3461
3758
  spotOptions = self.safe_value(options, 'spot', {})
3462
3759
  defaultSpotMethod = self.safe_string(spotOptions, 'method', 'publicSpotGetV2SpotMarketFillsHistory')
3463
3760
  spotMethod = self.safe_string(params, 'method', defaultSpotMethod)
@@ -3474,8 +3771,6 @@ class bitget(Exchange, ImplicitAPI):
3474
3771
  defaultSwapMethod = self.safe_string(swapOptions, 'method', 'publicMixGetV2MixMarketFillsHistory')
3475
3772
  swapMethod = self.safe_string(params, 'method', defaultSwapMethod)
3476
3773
  params = self.omit(params, 'method')
3477
- productType = None
3478
- productType, params = self.handle_product_type_and_params(market, params)
3479
3774
  request['productType'] = productType
3480
3775
  if swapMethod == 'publicMixGetV2MixMarketFillsHistory':
3481
3776
  request, params = self.handle_until_option('endTime', request, params)
@@ -3521,6 +3816,23 @@ class bitget(Exchange, ImplicitAPI):
3521
3816
  # ]
3522
3817
  # }
3523
3818
  #
3819
+ # uta
3820
+ #
3821
+ # {
3822
+ # "code": "00000",
3823
+ # "msg": "success",
3824
+ # "requestTime": 1750413823980,
3825
+ # "data": [
3826
+ # {
3827
+ # "execId": "1319896716324937729",
3828
+ # "price": "105909.1",
3829
+ # "size": "6.3090",
3830
+ # "side": "sell",
3831
+ # "ts": "1750413820344"
3832
+ # }
3833
+ # ]
3834
+ # }
3835
+ #
3524
3836
  data = self.safe_list(response, 'data', [])
3525
3837
  return self.parse_trades(data, market, since, limit)
3526
3838
 
@@ -3702,13 +4014,15 @@ class bitget(Exchange, ImplicitAPI):
3702
4014
  # "1399132.341"
3703
4015
  # ]
3704
4016
  #
4017
+ inverse = self.safe_bool(market, 'inverse')
4018
+ volumeIndex = 6 if inverse else 5
3705
4019
  return [
3706
4020
  self.safe_integer(ohlcv, 0),
3707
4021
  self.safe_number(ohlcv, 1),
3708
4022
  self.safe_number(ohlcv, 2),
3709
4023
  self.safe_number(ohlcv, 3),
3710
4024
  self.safe_number(ohlcv, 4),
3711
- self.safe_number(ohlcv, 5),
4025
+ self.safe_number(ohlcv, volumeIndex),
3712
4026
  ]
3713
4027
 
3714
4028
  async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
@@ -3721,12 +4035,14 @@ class bitget(Exchange, ImplicitAPI):
3721
4035
  https://www.bitget.com/api-doc/contract/market/Get-History-Candle-Data
3722
4036
  https://www.bitget.com/api-doc/contract/market/Get-History-Index-Candle-Data
3723
4037
  https://www.bitget.com/api-doc/contract/market/Get-History-Mark-Candle-Data
4038
+ https://www.bitget.com/api-doc/uta/public/Get-Candle-Data
3724
4039
 
3725
4040
  :param str symbol: unified symbol of the market to fetch OHLCV data for
3726
4041
  :param str timeframe: the length of time each candle represents
3727
4042
  :param int [since]: timestamp in ms of the earliest candle to fetch
3728
4043
  :param int [limit]: the maximum amount of candles to fetch
3729
4044
  :param dict [params]: extra parameters specific to the exchange API endpoint
4045
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
3730
4046
  :param int [params.until]: timestamp in ms of the latest candle to fetch
3731
4047
  :param boolean [params.useHistoryEndpoint]: whether to force to use historical endpoint(it has max limit of 200)
3732
4048
  :param boolean [params.useHistoryEndpointForPagination]: whether to force to use historical endpoint for pagination(default True)
@@ -3746,12 +4062,20 @@ class bitget(Exchange, ImplicitAPI):
3746
4062
  limitForPagination = maxLimitForHistoryEndpoint if useHistoryEndpointForPagination else maxLimitForRecentEndpoint
3747
4063
  return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, limitForPagination)
3748
4064
  market = self.market(symbol)
3749
- marketType = 'spot' if market['spot'] else 'swap'
3750
- timeframes = self.options['timeframes'][marketType]
3751
4065
  request: dict = {
3752
4066
  'symbol': market['id'],
3753
- 'granularity': self.safe_string(timeframes, timeframe, timeframe),
3754
4067
  }
4068
+ marketType = None
4069
+ timeframes = None
4070
+ uta = None
4071
+ uta, params = self.handle_option_and_params(params, 'fetchOHLCV', 'uta', False)
4072
+ if uta:
4073
+ timeframes = self.options['timeframes']['uta']
4074
+ request['interval'] = self.safe_string(timeframes, timeframe, timeframe)
4075
+ else:
4076
+ marketType = 'spot' if market['spot'] else 'swap'
4077
+ timeframes = self.options['timeframes'][marketType]
4078
+ request['granularity'] = self.safe_string(timeframes, timeframe, timeframe)
3755
4079
  msInDay = 86400000
3756
4080
  now = self.milliseconds()
3757
4081
  duration = self.parse_timeframe(timeframe) * 1000
@@ -3812,21 +4136,38 @@ class bitget(Exchange, ImplicitAPI):
3812
4136
  request['limit'] = limit
3813
4137
  # make request
3814
4138
  response = None
3815
- if market['spot']:
4139
+ productType = None
4140
+ priceType = None
4141
+ priceType, params = self.handle_param_string(params, 'price')
4142
+ productType, params = self.handle_product_type_and_params(market, params)
4143
+ if uta:
4144
+ if priceType is not None:
4145
+ if priceType == 'mark':
4146
+ request['type'] = 'MARK'
4147
+ elif priceType == 'index':
4148
+ request['type'] = 'INDEX'
4149
+ request['category'] = productType
4150
+ response = await self.publicUtaGetV3MarketCandles(self.extend(request, params))
4151
+ elif market['spot']:
3816
4152
  # checks if we need history endpoint
3817
4153
  if historicalEndpointNeeded:
3818
4154
  response = await self.publicSpotGetV2SpotMarketHistoryCandles(self.extend(request, params))
3819
4155
  else:
4156
+ if not limitDefined:
4157
+ request['limit'] = 1000
4158
+ limit = 1000
3820
4159
  response = await self.publicSpotGetV2SpotMarketCandles(self.extend(request, params))
3821
4160
  else:
3822
- priceType = None
3823
- priceType, params = self.handle_param_string(params, 'price')
3824
- productType = None
3825
- productType, params = self.handle_product_type_and_params(market, params)
3826
4161
  request['productType'] = productType
3827
4162
  extended = self.extend(request, params)
3828
- # todo: mark & index also have their "recent" endpoints, but not priority now.
3829
- if priceType == 'mark':
4163
+ if not historicalEndpointNeeded and (priceType == 'mark' or priceType == 'index'):
4164
+ if not limitDefined:
4165
+ extended['limit'] = 1000
4166
+ limit = 1000
4167
+ # Recent endpoint for mark/index prices
4168
+ # https://www.bitget.com/api-doc/contract/market/Get-Candle-Data
4169
+ response = await self.publicMixGetV2MixMarketCandles(self.extend({'kLineType': priceType}, extended))
4170
+ elif priceType == 'mark':
3830
4171
  response = await self.publicMixGetV2MixMarketHistoryMarkCandles(extended)
3831
4172
  elif priceType == 'index':
3832
4173
  response = await self.publicMixGetV2MixMarketHistoryIndexCandles(extended)
@@ -3834,6 +4175,9 @@ class bitget(Exchange, ImplicitAPI):
3834
4175
  if historicalEndpointNeeded:
3835
4176
  response = await self.publicMixGetV2MixMarketHistoryCandles(extended)
3836
4177
  else:
4178
+ if not limitDefined:
4179
+ extended['limit'] = 1000
4180
+ limit = 1000
3837
4181
  response = await self.publicMixGetV2MixMarketCandles(extended)
3838
4182
  if response == '':
3839
4183
  return [] # happens when a new token is listed
@@ -3851,9 +4195,11 @@ class bitget(Exchange, ImplicitAPI):
3851
4195
  https://www.bitget.com/api-doc/margin/isolated/account/Get-Isolated-Assets
3852
4196
  https://bitgetlimited.github.io/apidoc/en/margin/#get-cross-assets
3853
4197
  https://bitgetlimited.github.io/apidoc/en/margin/#get-isolated-assets
4198
+ https://www.bitget.com/api-doc/uta/account/Get-Account
3854
4199
 
3855
4200
  :param dict [params]: extra parameters specific to the exchange API endpoint
3856
4201
  :param str [params.productType]: *contract only* 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
4202
+ :param str [params.uta]: set to True for the unified trading account(uta), defaults to False
3857
4203
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
3858
4204
  """
3859
4205
  await self.load_markets()
@@ -3861,9 +4207,16 @@ class bitget(Exchange, ImplicitAPI):
3861
4207
  marketType = None
3862
4208
  marginMode = None
3863
4209
  response = None
4210
+ uta = None
4211
+ uta, params = self.handle_option_and_params(params, 'fetchBalance', 'uta', False)
3864
4212
  marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
3865
4213
  marginMode, params = self.handle_margin_mode_and_params('fetchBalance', params)
3866
- if (marketType == 'swap') or (marketType == 'future'):
4214
+ if uta:
4215
+ response = await self.privateUtaGetV3AccountAssets(self.extend(request, params))
4216
+ results = self.safe_dict(response, 'data', {})
4217
+ assets = self.safe_list(results, 'assets', [])
4218
+ return self.parse_uta_balance(assets)
4219
+ elif (marketType == 'swap') or (marketType == 'future'):
3867
4220
  productType = None
3868
4221
  productType, params = self.handle_product_type_and_params(None, params)
3869
4222
  request['productType'] = productType
@@ -3963,9 +4316,66 @@ class bitget(Exchange, ImplicitAPI):
3963
4316
  # ]
3964
4317
  # }
3965
4318
  #
4319
+ # uta
4320
+ #
4321
+ # {
4322
+ # "code": "00000",
4323
+ # "msg": "success",
4324
+ # "requestTime": 1749980065089,
4325
+ # "data": {
4326
+ # "accountEquity": "11.13919278",
4327
+ # "usdtEquity": "11.13921165",
4328
+ # "btcEquity": "0.00011256",
4329
+ # "unrealisedPnl": "0",
4330
+ # "usdtUnrealisedPnl": "0",
4331
+ # "btcUnrealizedPnl": "0",
4332
+ # "effEquity": "6.19299777",
4333
+ # "mmr": "0",
4334
+ # "imr": "0",
4335
+ # "mgnRatio": "0",
4336
+ # "positionMgnRatio": "0",
4337
+ # "assets": [
4338
+ # {
4339
+ # "coin": "USDT",
4340
+ # "equity": "6.19300826",
4341
+ # "usdValue": "6.19299777",
4342
+ # "balance": "6.19300826",
4343
+ # "available": "6.19300826",
4344
+ # "debt": "0",
4345
+ # "locked": "0"
4346
+ # }
4347
+ # ]
4348
+ # }
4349
+ # }
4350
+ #
3966
4351
  data = self.safe_value(response, 'data', [])
3967
4352
  return self.parse_balance(data)
3968
4353
 
4354
+ def parse_uta_balance(self, balance) -> Balances:
4355
+ result: dict = {'info': balance}
4356
+ #
4357
+ # {
4358
+ # "coin": "USDT",
4359
+ # "equity": "6.19300826",
4360
+ # "usdValue": "6.19299777",
4361
+ # "balance": "6.19300826",
4362
+ # "available": "6.19300826",
4363
+ # "debt": "0",
4364
+ # "locked": "0"
4365
+ # }
4366
+ #
4367
+ for i in range(0, len(balance)):
4368
+ entry = balance[i]
4369
+ account = self.account()
4370
+ currencyId = self.safe_string(entry, 'coin')
4371
+ code = self.safe_currency_code(currencyId)
4372
+ account['debt'] = self.safe_string(entry, 'debt')
4373
+ account['used'] = self.safe_string(entry, 'locked')
4374
+ account['free'] = self.safe_string(entry, 'available')
4375
+ account['total'] = self.safe_string(entry, 'balance')
4376
+ result[code] = account
4377
+ return self.safe_balance(result)
4378
+
3969
4379
  def parse_balance(self, balance) -> Balances:
3970
4380
  result: dict = {'info': balance}
3971
4381
  #
@@ -4099,7 +4509,7 @@ class bitget(Exchange, ImplicitAPI):
4099
4509
  # },
4100
4510
  # ]
4101
4511
  #
4102
- # spot, swap, future and spot margin: cancelOrder, cancelOrders
4512
+ # spot, swap, future, spot margin and uta: cancelOrder, cancelOrders, cancelAllOrders
4103
4513
  #
4104
4514
  # {
4105
4515
  # "orderId": "1098758604547850241",
@@ -4228,6 +4638,66 @@ class bitget(Exchange, ImplicitAPI):
4228
4638
  # "stopLossTriggerType": "fill_price",
4229
4639
  # }
4230
4640
  #
4641
+ # uta: fetchOrder, fetchOpenOrders, fetchCanceledAndClosedOrders
4642
+ #
4643
+ # {
4644
+ # "orderId": "1320244799629316096",
4645
+ # "clientOid": "1320244799633510400",
4646
+ # "category": "USDT-FUTURES",
4647
+ # "symbol": "BTCUSDT",
4648
+ # "orderType": "limit",
4649
+ # "side": "buy",
4650
+ # "price": "50000",
4651
+ # "qty": "0.001",
4652
+ # "amount": "0",
4653
+ # "cumExecQty": "0",
4654
+ # "cumExecValue": "0",
4655
+ # "avgPrice": "0",
4656
+ # "timeInForce": "gtc",
4657
+ # "orderStatus": "live",
4658
+ # "posSide": "long",
4659
+ # "holdMode": "hedge_mode",
4660
+ # "reduceOnly": "NO",
4661
+ # "feeDetail": [{
4662
+ # "feeCoin": "",
4663
+ # "fee": ""
4664
+ # }],
4665
+ # "createdTime": "1750496809871",
4666
+ # "updatedTime": "1750496809886",
4667
+ # "cancelReason": "",
4668
+ # "execType": "normal",
4669
+ # "stpMode": "none",
4670
+ # "tpTriggerBy": null,
4671
+ # "slTriggerBy": null,
4672
+ # "takeProfit": null,
4673
+ # "stopLoss": null,
4674
+ # "tpOrderType": null,
4675
+ # "slOrderType": null,
4676
+ # "tpLimitPrice": null,
4677
+ # "slLimitPrice": null
4678
+ # }
4679
+ #
4680
+ # uta trigger: fetchClosedOrders, fetchCanceledOrders
4681
+ #
4682
+ # {
4683
+ # "orderId": "1330984742276198400",
4684
+ # "clientOid": "1330984742276198400",
4685
+ # "symbol": "BTCUSDT",
4686
+ # "category": "USDT-FUTURES",
4687
+ # "qty": "0.001",
4688
+ # "posSide": "long",
4689
+ # "tpTriggerBy": "market",
4690
+ # "slTriggerBy": "mark",
4691
+ # "takeProfit": "",
4692
+ # "stopLoss": "112000",
4693
+ # "tpOrderType": "market",
4694
+ # "slOrderType": "limit",
4695
+ # "tpLimitPrice": "",
4696
+ # "slLimitPrice": "111000",
4697
+ # "createdTime": "1753057411736",
4698
+ # "updatedTime": "1753058267412"
4699
+ # }
4700
+ #
4231
4701
  errorMessage = self.safe_string(order, 'errorMsg')
4232
4702
  if errorMessage is not None:
4233
4703
  return self.safe_order({
@@ -4236,16 +4706,16 @@ class bitget(Exchange, ImplicitAPI):
4236
4706
  'clientOrderId': self.safe_string_2(order, 'clientOrderId', 'clientOid'),
4237
4707
  'status': 'rejected',
4238
4708
  }, market)
4239
- isContractOrder = ('posSide' in order)
4709
+ posSide = self.safe_string(order, 'posSide')
4710
+ isContractOrder = (posSide is not None)
4240
4711
  marketType = 'contract' if isContractOrder else 'spot'
4241
4712
  if market is not None:
4242
4713
  marketType = market['type']
4243
4714
  marketId = self.safe_string(order, 'symbol')
4244
4715
  market = self.safe_market(marketId, market, None, marketType)
4245
- timestamp = self.safe_integer_2(order, 'cTime', 'ctime')
4246
- updateTimestamp = self.safe_integer(order, 'uTime')
4247
- rawStatus = self.safe_string_2(order, 'status', 'state')
4248
- rawStatus = self.safe_string(order, 'planStatus', rawStatus)
4716
+ timestamp = self.safe_integer_n(order, ['cTime', 'ctime', 'createdTime'])
4717
+ updateTimestamp = self.safe_integer_2(order, 'uTime', 'updatedTime')
4718
+ rawStatus = self.safe_string_n(order, ['status', 'state', 'orderStatus', 'planStatus'])
4249
4719
  fee = None
4250
4720
  feeCostString = self.safe_string(order, 'fee')
4251
4721
  if feeCostString is not None:
@@ -4255,21 +4725,30 @@ class bitget(Exchange, ImplicitAPI):
4255
4725
  'currency': market['settle'],
4256
4726
  }
4257
4727
  feeDetail = self.safe_value(order, 'feeDetail')
4258
- if feeDetail is not None:
4259
- parsedFeeDetail = json.loads(feeDetail)
4260
- feeValues = list(parsedFeeDetail.values())
4261
- feeObject = None
4262
- for i in range(0, len(feeValues)):
4263
- feeValue = feeValues[i]
4264
- if self.safe_value(feeValue, 'feeCoinCode') is not None:
4265
- feeObject = feeValue
4266
- break
4728
+ uta = self.safe_string(order, 'category') is not None
4729
+ if uta:
4730
+ feeResult = self.safe_dict(feeDetail, 0, {})
4731
+ utaFee = self.safe_string(feeResult, 'fee')
4267
4732
  fee = {
4268
- 'cost': self.parse_number(Precise.string_neg(self.safe_string(feeObject, 'totalFee'))),
4269
- 'currency': self.safe_currency_code(self.safe_string(feeObject, 'feeCoinCode')),
4733
+ 'cost': self.parse_number(Precise.string_neg(utaFee)),
4734
+ 'currency': market['settle'],
4270
4735
  }
4736
+ else:
4737
+ if feeDetail is not None:
4738
+ parsedFeeDetail = json.loads(feeDetail)
4739
+ feeValues = list(parsedFeeDetail.values())
4740
+ feeObject = None
4741
+ for i in range(0, len(feeValues)):
4742
+ feeValue = feeValues[i]
4743
+ if self.safe_value(feeValue, 'feeCoinCode') is not None:
4744
+ feeObject = feeValue
4745
+ break
4746
+ fee = {
4747
+ 'cost': self.parse_number(Precise.string_neg(self.safe_string(feeObject, 'totalFee'))),
4748
+ 'currency': self.safe_currency_code(self.safe_string(feeObject, 'feeCoinCode')),
4749
+ }
4271
4750
  postOnly = None
4272
- timeInForce = self.safe_string_upper(order, 'force')
4751
+ timeInForce = self.safe_string_upper_2(order, 'force', 'timeInForce')
4273
4752
  if timeInForce == 'POST_ONLY':
4274
4753
  postOnly = True
4275
4754
  timeInForce = 'PO'
@@ -4285,7 +4764,7 @@ class bitget(Exchange, ImplicitAPI):
4285
4764
  price = self.safe_string(order, 'priceAvg')
4286
4765
  average = self.safe_string(order, 'basePrice')
4287
4766
  else:
4288
- price = self.safe_string_2(order, 'price', 'executePrice')
4767
+ price = self.safe_string_n(order, ['price', 'executePrice', 'slLimitPrice', 'tpLimitPrice'])
4289
4768
  average = self.safe_string(order, 'priceAvg')
4290
4769
  size = None
4291
4770
  filled = None
@@ -4295,8 +4774,8 @@ class bitget(Exchange, ImplicitAPI):
4295
4774
  size = baseSize
4296
4775
  filled = self.safe_string(order, 'size')
4297
4776
  else:
4298
- size = self.safe_string(order, 'size')
4299
- filled = self.safe_string(order, 'baseVolume')
4777
+ size = self.safe_string_2(order, 'size', 'qty')
4778
+ filled = self.safe_string_2(order, 'baseVolume', 'cumExecQty')
4300
4779
  side = self.safe_string(order, 'side')
4301
4780
  posMode = self.safe_string(order, 'posMode')
4302
4781
  if posMode == 'hedge_mode' and reduceOnly:
@@ -4329,8 +4808,8 @@ class bitget(Exchange, ImplicitAPI):
4329
4808
  'postOnly': postOnly,
4330
4809
  'reduceOnly': reduceOnly,
4331
4810
  'triggerPrice': self.safe_number(order, 'triggerPrice'),
4332
- 'takeProfitPrice': self.safe_number_2(order, 'presetStopSurplusPrice', 'stopSurplusTriggerPrice'),
4333
- 'stopLossPrice': self.safe_number_2(order, 'presetStopLossPrice', 'stopLossTriggerPrice'),
4811
+ 'takeProfitPrice': self.safe_number_n(order, ['presetStopSurplusPrice', 'stopSurplusTriggerPrice', 'takeProfit']),
4812
+ 'stopLossPrice': self.safe_number_n(order, ['presetStopLossPrice', 'stopLossTriggerPrice', 'stopLoss']),
4334
4813
  'status': self.parse_order_status(rawStatus),
4335
4814
  'fee': fee,
4336
4815
  'trades': None,
@@ -4369,6 +4848,8 @@ class bitget(Exchange, ImplicitAPI):
4369
4848
  https://www.bitget.com/api-doc/contract/plan/Place-Plan-Order
4370
4849
  https://www.bitget.com/api-doc/margin/cross/trade/Cross-Place-Order
4371
4850
  https://www.bitget.com/api-doc/margin/isolated/trade/Isolated-Place-Order
4851
+ https://www.bitget.com/api-doc/uta/trade/Place-Order
4852
+ https://www.bitget.com/api-doc/uta/strategy/Place-Strategy-Order
4372
4853
 
4373
4854
  :param str symbol: unified symbol of the market to create an order in
4374
4855
  :param str type: 'market' or 'limit'
@@ -4398,6 +4879,8 @@ class bitget(Exchange, ImplicitAPI):
4398
4879
  :param boolean [params.oneWayMode]: *swap and future only* required to set self to True in one_way_mode and you can leave self in hedge_mode, can adjust the mode using the setPositionMode() method
4399
4880
  :param bool [params.hedged]: *swap and future only* True for hedged mode, False for one way mode, default is False
4400
4881
  :param bool [params.reduceOnly]: True or False whether the order is reduce-only
4882
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
4883
+ :param str [params.posSide]: *uta only* hedged two-way position side, long or short
4401
4884
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4402
4885
  """
4403
4886
  await self.load_markets()
@@ -4413,24 +4896,33 @@ class bitget(Exchange, ImplicitAPI):
4413
4896
  isStopLossTriggerOrder = stopLossTriggerPrice is not None
4414
4897
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
4415
4898
  isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
4416
- request = self.create_order_request(symbol, type, side, amount, price, params)
4417
4899
  response = None
4418
- if market['spot']:
4419
- if isTriggerOrder:
4420
- response = await self.privateSpotPostV2SpotTradePlacePlanOrder(request)
4421
- elif marginMode == 'isolated':
4422
- response = await self.privateMarginPostV2MarginIsolatedPlaceOrder(request)
4423
- elif marginMode == 'cross':
4424
- response = await self.privateMarginPostV2MarginCrossedPlaceOrder(request)
4900
+ uta = None
4901
+ uta, params = self.handle_option_and_params(params, 'createOrder', 'uta', False)
4902
+ if uta:
4903
+ request = self.create_uta_order_request(symbol, type, side, amount, price, params)
4904
+ if isStopLossOrTakeProfitTrigger:
4905
+ response = await self.privateUtaPostV3TradePlaceStrategyOrder(request)
4425
4906
  else:
4426
- response = await self.privateSpotPostV2SpotTradePlaceOrder(request)
4907
+ response = await self.privateUtaPostV3TradePlaceOrder(request)
4427
4908
  else:
4428
- if isTriggerOrder or isTrailingPercentOrder:
4429
- response = await self.privateMixPostV2MixOrderPlacePlanOrder(request)
4430
- elif isStopLossOrTakeProfitTrigger:
4431
- response = await self.privateMixPostV2MixOrderPlaceTpslOrder(request)
4909
+ request = self.create_order_request(symbol, type, side, amount, price, params)
4910
+ if market['spot']:
4911
+ if isTriggerOrder:
4912
+ response = await self.privateSpotPostV2SpotTradePlacePlanOrder(request)
4913
+ elif marginMode == 'isolated':
4914
+ response = await self.privateMarginPostV2MarginIsolatedPlaceOrder(request)
4915
+ elif marginMode == 'cross':
4916
+ response = await self.privateMarginPostV2MarginCrossedPlaceOrder(request)
4917
+ else:
4918
+ response = await self.privateSpotPostV2SpotTradePlaceOrder(request)
4432
4919
  else:
4433
- response = await self.privateMixPostV2MixOrderPlaceOrder(request)
4920
+ if isTriggerOrder or isTrailingPercentOrder:
4921
+ response = await self.privateMixPostV2MixOrderPlacePlanOrder(request)
4922
+ elif isStopLossOrTakeProfitTrigger:
4923
+ response = await self.privateMixPostV2MixOrderPlaceTpslOrder(request)
4924
+ else:
4925
+ response = await self.privateMixPostV2MixOrderPlaceOrder(request)
4434
4926
  #
4435
4927
  # {
4436
4928
  # "code": "00000",
@@ -4445,24 +4937,124 @@ class bitget(Exchange, ImplicitAPI):
4445
4937
  data = self.safe_dict(response, 'data', {})
4446
4938
  return self.parse_order(data, market)
4447
4939
 
4448
- def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
4940
+ def create_uta_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
4449
4941
  market = self.market(symbol)
4450
- marketType = None
4451
- marginMode = None
4452
- marketType, params = self.handle_market_type_and_params('createOrder', market, params)
4453
- marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
4942
+ productType = None
4943
+ productType, params = self.handle_product_type_and_params(market, params)
4944
+ if productType == 'SPOT':
4945
+ marginMode = None
4946
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
4947
+ if marginMode is not None:
4948
+ productType = 'MARGIN'
4454
4949
  request: dict = {
4950
+ 'category': productType,
4455
4951
  'symbol': market['id'],
4456
- 'orderType': type,
4952
+ 'qty': self.amount_to_precision(symbol, amount),
4953
+ 'side': side,
4457
4954
  }
4458
- isMarketOrder = type == 'market'
4459
- triggerPrice = self.safe_value_2(params, 'stopPrice', 'triggerPrice')
4460
- stopLossTriggerPrice = self.safe_value(params, 'stopLossPrice')
4461
- takeProfitTriggerPrice = self.safe_value(params, 'takeProfitPrice')
4955
+ clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
4956
+ if clientOrderId is not None:
4957
+ request['clientOid'] = clientOrderId
4958
+ params = self.omit(params, 'clientOrderId')
4959
+ stopLossTriggerPrice = self.safe_number(params, 'stopLossPrice')
4960
+ takeProfitTriggerPrice = self.safe_number(params, 'takeProfitPrice')
4462
4961
  stopLoss = self.safe_value(params, 'stopLoss')
4463
4962
  takeProfit = self.safe_value(params, 'takeProfit')
4464
- isTriggerOrder = triggerPrice is not None
4465
- isStopLossTriggerOrder = stopLossTriggerPrice is not None
4963
+ isStopLoss = stopLoss is not None
4964
+ isTakeProfit = takeProfit is not None
4965
+ isStopLossTrigger = stopLossTriggerPrice is not None
4966
+ isTakeProfitTrigger = takeProfitTriggerPrice is not None
4967
+ isStopLossOrTakeProfitTrigger = isStopLossTrigger or isTakeProfitTrigger
4968
+ if isStopLossOrTakeProfitTrigger:
4969
+ if isStopLossTrigger:
4970
+ slType = self.safe_string(params, 'slTriggerBy', 'mark')
4971
+ request['slTriggerBy'] = slType
4972
+ request['stopLoss'] = self.price_to_precision(symbol, stopLossTriggerPrice)
4973
+ if price is not None:
4974
+ request['slLimitPrice'] = self.price_to_precision(symbol, price)
4975
+ request['slOrderType'] = self.safe_string(params, 'slOrderType', 'limit')
4976
+ else:
4977
+ request['slOrderType'] = self.safe_string(params, 'slOrderType', 'market')
4978
+ elif isTakeProfitTrigger:
4979
+ tpType = self.safe_string(params, 'tpTriggerBy', 'mark')
4980
+ request['tpTriggerBy'] = tpType
4981
+ request['takeProfit'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
4982
+ if price is not None:
4983
+ request['tpLimitPrice'] = self.price_to_precision(symbol, price)
4984
+ request['tpOrderType'] = self.safe_string(params, 'tpOrderType', 'limit')
4985
+ else:
4986
+ request['tpOrderType'] = self.safe_string(params, 'tpOrderType', 'market')
4987
+ params = self.omit(params, ['stopLossPrice', 'takeProfitPrice'])
4988
+ else:
4989
+ if isStopLoss:
4990
+ slTriggerPrice = self.safe_number_2(stopLoss, 'triggerPrice', 'stopPrice')
4991
+ slLimitPrice = self.safe_number(stopLoss, 'price')
4992
+ request['stopLoss'] = self.price_to_precision(symbol, slTriggerPrice)
4993
+ if slLimitPrice is not None:
4994
+ request['slLimitPrice'] = self.price_to_precision(symbol, slLimitPrice)
4995
+ request['slOrderType'] = self.safe_string(params, 'slOrderType', 'limit')
4996
+ else:
4997
+ request['slOrderType'] = self.safe_string(params, 'slOrderType', 'market')
4998
+ if isTakeProfit:
4999
+ tpTriggerPrice = self.safe_number_2(takeProfit, 'triggerPrice', 'stopPrice')
5000
+ tpLimitPrice = self.safe_number(takeProfit, 'price')
5001
+ request['takeProfit'] = self.price_to_precision(symbol, tpTriggerPrice)
5002
+ if tpLimitPrice is not None:
5003
+ request['tpLimitPrice'] = self.price_to_precision(symbol, tpLimitPrice)
5004
+ request['tpOrderType'] = self.safe_string(params, 'tpOrderType', 'limit')
5005
+ else:
5006
+ request['tpOrderType'] = self.safe_string(params, 'tpOrderType', 'market')
5007
+ isMarketOrder = type == 'market'
5008
+ if not isMarketOrder:
5009
+ request['price'] = self.price_to_precision(symbol, price)
5010
+ request['orderType'] = type
5011
+ exchangeSpecificTifParam = self.safe_string(params, 'timeInForce')
5012
+ postOnly = None
5013
+ postOnly, params = self.handle_post_only(isMarketOrder, exchangeSpecificTifParam == 'post_only', params)
5014
+ defaultTimeInForce = self.safe_string_upper(self.options, 'defaultTimeInForce')
5015
+ timeInForce = self.safe_string_upper(params, 'timeInForce', defaultTimeInForce)
5016
+ if postOnly:
5017
+ request['timeInForce'] = 'post_only'
5018
+ elif timeInForce == 'GTC':
5019
+ request['timeInForce'] = 'gtc'
5020
+ elif timeInForce == 'FOK':
5021
+ request['timeInForce'] = 'fok'
5022
+ elif timeInForce == 'IOC':
5023
+ request['timeInForce'] = 'ioc'
5024
+ reduceOnly = self.safe_bool(params, 'reduceOnly', False)
5025
+ hedged = None
5026
+ hedged, params = self.handle_param_bool(params, 'hedged', False)
5027
+ if reduceOnly:
5028
+ if hedged or isStopLossOrTakeProfitTrigger:
5029
+ reduceOnlyPosSide = 'long' if (side == 'sell') else 'short'
5030
+ request['posSide'] = reduceOnlyPosSide
5031
+ elif not isStopLossOrTakeProfitTrigger:
5032
+ request['reduceOnly'] = 'yes'
5033
+ else:
5034
+ if hedged:
5035
+ posSide = 'long' if (side == 'buy') else 'short'
5036
+ request['posSide'] = posSide
5037
+ params = self.omit(params, ['stopLoss', 'takeProfit', 'postOnly', 'reduceOnly', 'hedged'])
5038
+ return self.extend(request, params)
5039
+
5040
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
5041
+ market = self.market(symbol)
5042
+ marketType = None
5043
+ marginMode = None
5044
+ marketType, params = self.handle_market_type_and_params('createOrder', market, params)
5045
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
5046
+ request: dict = {
5047
+ 'symbol': market['id'],
5048
+ 'orderType': type,
5049
+ }
5050
+ isMarketOrder = type == 'market'
5051
+ triggerPrice = self.safe_value_2(params, 'stopPrice', 'triggerPrice')
5052
+ stopLossTriggerPrice = self.safe_value(params, 'stopLossPrice')
5053
+ takeProfitTriggerPrice = self.safe_value(params, 'takeProfitPrice')
5054
+ stopLoss = self.safe_value(params, 'stopLoss')
5055
+ takeProfit = self.safe_value(params, 'takeProfit')
5056
+ isTriggerOrder = triggerPrice is not None
5057
+ isStopLossTriggerOrder = stopLossTriggerPrice is not None
4466
5058
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
4467
5059
  isStopLoss = stopLoss is not None
4468
5060
  isTakeProfit = takeProfit is not None
@@ -4516,16 +5108,16 @@ class bitget(Exchange, ImplicitAPI):
4516
5108
  if price is not None:
4517
5109
  request['executePrice'] = self.price_to_precision(symbol, price)
4518
5110
  if isStopLoss:
4519
- slTriggerPrice = self.safe_number_2(stopLoss, 'triggerPrice', 'stopPrice')
5111
+ slTriggerPrice = self.safe_string_2(stopLoss, 'triggerPrice', 'stopPrice')
4520
5112
  request['stopLossTriggerPrice'] = self.price_to_precision(symbol, slTriggerPrice)
4521
- slPrice = self.safe_number(stopLoss, 'price')
5113
+ slPrice = self.safe_string(stopLoss, 'price')
4522
5114
  request['stopLossExecutePrice'] = self.price_to_precision(symbol, slPrice)
4523
5115
  slType = self.safe_string(stopLoss, 'type', 'mark_price')
4524
5116
  request['stopLossTriggerType'] = slType
4525
5117
  if isTakeProfit:
4526
- tpTriggerPrice = self.safe_number_2(takeProfit, 'triggerPrice', 'stopPrice')
5118
+ tpTriggerPrice = self.safe_string_2(takeProfit, 'triggerPrice', 'stopPrice')
4527
5119
  request['stopSurplusTriggerPrice'] = self.price_to_precision(symbol, tpTriggerPrice)
4528
- tpPrice = self.safe_number(takeProfit, 'price')
5120
+ tpPrice = self.safe_string(takeProfit, 'price')
4529
5121
  request['stopSurplusExecutePrice'] = self.price_to_precision(symbol, tpPrice)
4530
5122
  tpType = self.safe_string(takeProfit, 'type', 'mark_price')
4531
5123
  request['stopSurplusTriggerType'] = tpType
@@ -4618,6 +5210,52 @@ class bitget(Exchange, ImplicitAPI):
4618
5210
  raise NotSupported(self.id + ' createOrder() does not support ' + marketType + ' orders')
4619
5211
  return self.extend(request, params)
4620
5212
 
5213
+ async def create_uta_orders(self, orders: List[OrderRequest], params={}):
5214
+ await self.load_markets()
5215
+ ordersRequests = []
5216
+ symbol = None
5217
+ marginMode = None
5218
+ for i in range(0, len(orders)):
5219
+ rawOrder = orders[i]
5220
+ marketId = self.safe_string(rawOrder, 'symbol')
5221
+ if symbol is None:
5222
+ symbol = marketId
5223
+ else:
5224
+ if symbol != marketId:
5225
+ raise BadRequest(self.id + ' createOrders() requires all orders to have the same symbol')
5226
+ type = self.safe_string(rawOrder, 'type')
5227
+ side = self.safe_string(rawOrder, 'side')
5228
+ amount = self.safe_value(rawOrder, 'amount')
5229
+ price = self.safe_value(rawOrder, 'price')
5230
+ orderParams = self.safe_value(rawOrder, 'params', {})
5231
+ marginResult = self.handle_margin_mode_and_params('createOrders', orderParams)
5232
+ currentMarginMode = marginResult[0]
5233
+ if currentMarginMode is not None:
5234
+ if marginMode is None:
5235
+ marginMode = currentMarginMode
5236
+ else:
5237
+ if marginMode != currentMarginMode:
5238
+ raise BadRequest(self.id + ' createOrders() requires all orders to have the same margin mode(isolated or cross)')
5239
+ orderRequest = self.create_uta_order_request(marketId, type, side, amount, price, orderParams)
5240
+ ordersRequests.append(orderRequest)
5241
+ market = self.market(symbol)
5242
+ response = await self.privateUtaPostV3TradePlaceBatch(ordersRequests)
5243
+ #
5244
+ # {
5245
+ # "code": "00000",
5246
+ # "msg": "success",
5247
+ # "requestTime": 1752810184560,
5248
+ # "data": [
5249
+ # {
5250
+ # "orderId": "1329947796441513984",
5251
+ # "clientOid": "1329947796483457024"
5252
+ # },
5253
+ # ]
5254
+ # }
5255
+ #
5256
+ data = self.safe_list(response, 'data', [])
5257
+ return self.parse_orders(data, market)
5258
+
4621
5259
  async def create_orders(self, orders: List[OrderRequest], params={}):
4622
5260
  """
4623
5261
  create a list of trade orders(all orders should be of the same symbol)
@@ -4626,12 +5264,18 @@ class bitget(Exchange, ImplicitAPI):
4626
5264
  https://www.bitget.com/api-doc/contract/trade/Batch-Order
4627
5265
  https://www.bitget.com/api-doc/margin/isolated/trade/Isolated-Batch-Order
4628
5266
  https://www.bitget.com/api-doc/margin/cross/trade/Cross-Batch-Order
5267
+ https://www.bitget.com/api-doc/uta/trade/Place-Batch
4629
5268
 
4630
5269
  :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
4631
5270
  :param dict [params]: extra parameters specific to the api endpoint
5271
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
4632
5272
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4633
5273
  """
4634
5274
  await self.load_markets()
5275
+ uta = None
5276
+ uta, params = self.handle_option_and_params(params, 'createOrders', 'uta', False)
5277
+ if uta:
5278
+ return await self.create_uta_orders(orders, params)
4635
5279
  ordersRequests = []
4636
5280
  symbol = None
4637
5281
  marginMode = None
@@ -4717,6 +5361,8 @@ class bitget(Exchange, ImplicitAPI):
4717
5361
  https://www.bitget.com/api-doc/contract/trade/Modify-Order
4718
5362
  https://www.bitget.com/api-doc/contract/plan/Modify-Tpsl-Order
4719
5363
  https://www.bitget.com/api-doc/contract/plan/Modify-Plan-Order
5364
+ https://www.bitget.com/api-doc/uta/trade/Modify-Order
5365
+ https://www.bitget.com/api-doc/uta/strategy/Modify-Strategy-Order
4720
5366
 
4721
5367
  :param str id: cancel order id
4722
5368
  :param str symbol: unified symbol of the market to create an order in
@@ -4739,6 +5385,7 @@ class bitget(Exchange, ImplicitAPI):
4739
5385
  :param str [params.trailingPercent]: *swap and future only* the percent to trail away from the current market price, rate can not be greater than 10
4740
5386
  :param str [params.trailingTriggerPrice]: *swap and future only* the price to trigger a trailing stop order, default uses the price argument
4741
5387
  :param str [params.newTriggerType]: *swap and future only* 'fill_price', 'mark_price' or 'index_price'
5388
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
4742
5389
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4743
5390
  """
4744
5391
  await self.load_markets()
@@ -4767,7 +5414,39 @@ class bitget(Exchange, ImplicitAPI):
4767
5414
  request['clientOid'] = clientOrderId
4768
5415
  params = self.omit(params, ['stopPrice', 'triggerType', 'stopLossPrice', 'takeProfitPrice', 'stopLoss', 'takeProfit', 'clientOrderId', 'trailingTriggerPrice', 'trailingPercent'])
4769
5416
  response = None
4770
- if market['spot']:
5417
+ productType = None
5418
+ uta = None
5419
+ productType, params = self.handle_product_type_and_params(market, params)
5420
+ uta, params = self.handle_option_and_params(params, 'editOrder', 'uta', False)
5421
+ if uta:
5422
+ if amount is not None:
5423
+ request['qty'] = self.amount_to_precision(symbol, amount)
5424
+ if isStopLossOrder or isTakeProfitOrder:
5425
+ if isStopLossOrder:
5426
+ slType = self.safe_string(params, 'slTriggerBy', 'mark')
5427
+ request['slTriggerBy'] = slType
5428
+ request['stopLoss'] = self.price_to_precision(symbol, stopLossPrice)
5429
+ if price is not None:
5430
+ request['slLimitPrice'] = self.price_to_precision(symbol, price)
5431
+ request['slOrderType'] = self.safe_string(params, 'slOrderType', 'limit')
5432
+ else:
5433
+ request['slOrderType'] = self.safe_string(params, 'slOrderType', 'market')
5434
+ elif isTakeProfitOrder:
5435
+ tpType = self.safe_string(params, 'tpTriggerBy', 'mark')
5436
+ request['tpTriggerBy'] = tpType
5437
+ request['takeProfit'] = self.price_to_precision(symbol, takeProfitPrice)
5438
+ if price is not None:
5439
+ request['tpLimitPrice'] = self.price_to_precision(symbol, price)
5440
+ request['tpOrderType'] = self.safe_string(params, 'tpOrderType', 'limit')
5441
+ else:
5442
+ request['tpOrderType'] = self.safe_string(params, 'tpOrderType', 'market')
5443
+ params = self.omit(params, ['stopLossPrice', 'takeProfitPrice'])
5444
+ response = await self.privateUtaPostV3TradeModifyStrategyOrder(self.extend(request, params))
5445
+ else:
5446
+ if price is not None:
5447
+ request['price'] = self.price_to_precision(symbol, price)
5448
+ response = await self.privateUtaPostV3TradeModifyOrder(self.extend(request, params))
5449
+ elif market['spot']:
4771
5450
  if triggerPrice is None:
4772
5451
  raise NotSupported(self.id + ' editOrder() only supports plan/trigger spot orders')
4773
5452
  editMarketBuyOrderRequiresPrice = self.safe_bool(self.options, 'editMarketBuyOrderRequiresPrice', True)
@@ -4789,8 +5468,6 @@ class bitget(Exchange, ImplicitAPI):
4789
5468
  if (not market['swap']) and (not market['future']):
4790
5469
  raise NotSupported(self.id + ' editOrder() does not support ' + market['type'] + ' orders')
4791
5470
  request['symbol'] = market['id']
4792
- productType = None
4793
- productType, params = self.handle_product_type_and_params(market, params)
4794
5471
  request['productType'] = productType
4795
5472
  if not isTakeProfitOrder and not isStopLossOrder:
4796
5473
  request['newSize'] = self.amount_to_precision(symbol, amount)
@@ -4866,6 +5543,8 @@ class bitget(Exchange, ImplicitAPI):
4866
5543
  https://www.bitget.com/api-doc/contract/plan/Cancel-Plan-Order
4867
5544
  https://www.bitget.com/api-doc/margin/cross/trade/Cross-Cancel-Order
4868
5545
  https://www.bitget.com/api-doc/margin/isolated/trade/Isolated-Cancel-Order
5546
+ https://www.bitget.com/api-doc/uta/trade/Cancel-Order
5547
+ https://www.bitget.com/api-doc/uta/strategy/Cancel-Strategy-Order
4869
5548
 
4870
5549
  :param str id: order id
4871
5550
  :param str symbol: unified symbol of the market the order was made in
@@ -4874,6 +5553,7 @@ class bitget(Exchange, ImplicitAPI):
4874
5553
  :param boolean [params.trigger]: set to True for canceling trigger orders
4875
5554
  :param str [params.planType]: *swap only* either profit_plan, loss_plan, normal_plan, pos_profit, pos_loss, moving_plan or track_plan
4876
5555
  :param boolean [params.trailing]: set to True if you want to cancel a trailing order
5556
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
4877
5557
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4878
5558
  """
4879
5559
  if symbol is None:
@@ -4891,7 +5571,15 @@ class bitget(Exchange, ImplicitAPI):
4891
5571
  request['symbol'] = market['id']
4892
5572
  if not ((market['swap'] or market['future']) and trigger):
4893
5573
  request['orderId'] = id
4894
- if (market['swap']) or (market['future']):
5574
+ uta = None
5575
+ uta, params = self.handle_option_and_params(params, 'cancelOrder', 'uta', False)
5576
+ if uta:
5577
+ request['orderId'] = id
5578
+ if trigger:
5579
+ response = await self.privateUtaPostV3TradeCancelStrategyOrder(self.extend(request, params))
5580
+ else:
5581
+ response = await self.privateUtaPostV3TradeCancelOrder(self.extend(request, params))
5582
+ elif (market['swap']) or (market['future']):
4895
5583
  productType = None
4896
5584
  productType, params = self.handle_product_type_and_params(market, params)
4897
5585
  request['productType'] = productType
@@ -4964,15 +5652,60 @@ class bitget(Exchange, ImplicitAPI):
4964
5652
  # }
4965
5653
  # }
4966
5654
  #
5655
+ # uta trigger
5656
+ #
5657
+ # {
5658
+ # "code": "00000",
5659
+ # "msg": "success",
5660
+ # "requestTime": "1753058267399",
5661
+ # "data": null
5662
+ # }
5663
+ #
4967
5664
  data = self.safe_value(response, 'data', {})
4968
5665
  order = None
4969
- if (market['swap'] or market['future']) and trigger:
5666
+ if (market['swap'] or market['future']) and trigger and not uta:
4970
5667
  orderInfo = self.safe_value(data, 'successList', [])
4971
5668
  order = orderInfo[0]
4972
5669
  else:
4973
- order = data
5670
+ if uta and trigger:
5671
+ order = response
5672
+ else:
5673
+ order = data
4974
5674
  return self.parse_order(order, market)
4975
5675
 
5676
+ async def cancel_uta_orders(self, ids, symbol: Str = None, params={}):
5677
+ if symbol is None:
5678
+ raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
5679
+ await self.load_markets()
5680
+ market = self.market(symbol)
5681
+ productType = None
5682
+ productType, params = self.handle_product_type_and_params(market, params)
5683
+ requestList = []
5684
+ for i in range(0, len(ids)):
5685
+ individualId = ids[i]
5686
+ order: dict = {
5687
+ 'orderId': individualId,
5688
+ 'symbol': market['id'],
5689
+ 'category': productType,
5690
+ }
5691
+ requestList.append(order)
5692
+ response = await self.privateUtaPostV3TradeCancelBatch(requestList)
5693
+ #
5694
+ # {
5695
+ # "code": "00000",
5696
+ # "msg": "success",
5697
+ # "requestTime": 1752813731517,
5698
+ # "data": [
5699
+ # {
5700
+ # "orderId": "1329948909442023424",
5701
+ # "clientOid": "1329948909446217728"
5702
+ # },
5703
+ # ]
5704
+ # }
5705
+ #
5706
+ data = self.safe_list(response, 'data', [])
5707
+ return self.parse_orders(data, market)
5708
+
4976
5709
  async def cancel_orders(self, ids, symbol: Str = None, params={}):
4977
5710
  """
4978
5711
  cancel multiple orders
@@ -4982,18 +5715,24 @@ class bitget(Exchange, ImplicitAPI):
4982
5715
  https://www.bitget.com/api-doc/contract/plan/Cancel-Plan-Order
4983
5716
  https://www.bitget.com/api-doc/margin/cross/trade/Cross-Batch-Cancel-Order
4984
5717
  https://www.bitget.com/api-doc/margin/isolated/trade/Isolated-Batch-Cancel-Orders
5718
+ https://www.bitget.com/api-doc/uta/trade/Cancel-Batch
4985
5719
 
4986
5720
  :param str[] ids: order ids
4987
5721
  :param str symbol: unified market symbol, default is None
4988
5722
  :param dict [params]: extra parameters specific to the exchange API endpoint
4989
5723
  :param str [params.marginMode]: 'isolated' or 'cross' for spot margin trading
4990
5724
  :param boolean [params.trigger]: *contract only* set to True for canceling trigger orders
5725
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
4991
5726
  :returns dict: an array of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
4992
5727
  """
4993
5728
  if symbol is None:
4994
5729
  raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
4995
5730
  await self.load_markets()
4996
5731
  market = self.market(symbol)
5732
+ uta = None
5733
+ uta, params = self.handle_option_and_params(params, 'cancelOrders', 'uta', False)
5734
+ if uta:
5735
+ return await self.cancel_uta_orders(ids, symbol, params)
4997
5736
  marginMode = None
4998
5737
  marginMode, params = self.handle_margin_mode_and_params('cancelOrders', params)
4999
5738
  trigger = self.safe_value_2(params, 'stop', 'trigger')
@@ -5058,11 +5797,13 @@ class bitget(Exchange, ImplicitAPI):
5058
5797
  https://www.bitget.com/api-doc/contract/trade/Batch-Cancel-Orders
5059
5798
  https://bitgetlimited.github.io/apidoc/en/margin/#isolated-batch-cancel-orders
5060
5799
  https://bitgetlimited.github.io/apidoc/en/margin/#cross-batch-cancel-order
5800
+ https://www.bitget.com/api-doc/uta/trade/Cancel-All-Order
5061
5801
 
5062
5802
  :param str symbol: unified market symbol
5063
5803
  :param dict [params]: extra parameters specific to the exchange API endpoint
5064
5804
  :param str [params.marginMode]: 'isolated' or 'cross' for spot margin trading
5065
5805
  :param boolean [params.trigger]: *contract only* set to True for canceling trigger orders
5806
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
5066
5807
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
5067
5808
  """
5068
5809
  if symbol is None:
@@ -5071,13 +5812,38 @@ class bitget(Exchange, ImplicitAPI):
5071
5812
  market = self.market(symbol)
5072
5813
  marginMode = None
5073
5814
  marginMode, params = self.handle_margin_mode_and_params('cancelAllOrders', params)
5815
+ productType = None
5816
+ productType, params = self.handle_product_type_and_params(market, params)
5074
5817
  request: dict = {
5075
5818
  'symbol': market['id'],
5076
5819
  }
5077
5820
  trigger = self.safe_bool_2(params, 'stop', 'trigger')
5078
5821
  params = self.omit(params, ['stop', 'trigger'])
5079
5822
  response = None
5080
- if market['spot']:
5823
+ uta = None
5824
+ uta, params = self.handle_option_and_params(params, 'cancelAllOrders', 'uta', False)
5825
+ if uta:
5826
+ if productType == 'SPOT':
5827
+ if marginMode is not None:
5828
+ productType = 'MARGIN'
5829
+ request['category'] = productType
5830
+ response = await self.privateUtaPostV3TradeCancelSymbolOrder(self.extend(request, params))
5831
+ #
5832
+ # {
5833
+ # "code": "00000",
5834
+ # "msg": "success",
5835
+ # "requestTime": 1750751578138,
5836
+ # "data": {
5837
+ # "list": [
5838
+ # {
5839
+ # "orderId": "1321313242969427968",
5840
+ # "clientOid": "1321313242969427969"
5841
+ # }
5842
+ # ]
5843
+ # }
5844
+ # }
5845
+ #
5846
+ elif market['spot']:
5081
5847
  if marginMode is not None:
5082
5848
  if marginMode == 'cross':
5083
5849
  response = await self.privateMarginPostMarginV1CrossOrderBatchCancelOrder(self.extend(request, params))
@@ -5129,8 +5895,6 @@ class bitget(Exchange, ImplicitAPI):
5129
5895
  }),
5130
5896
  ]
5131
5897
  else:
5132
- productType = None
5133
- productType, params = self.handle_product_type_and_params(market, params)
5134
5898
  request['productType'] = productType
5135
5899
  if trigger:
5136
5900
  response = await self.privateMixPostV2MixOrderCancelPlanOrder(self.extend(request, params))
@@ -5151,9 +5915,13 @@ class bitget(Exchange, ImplicitAPI):
5151
5915
  # }
5152
5916
  # }
5153
5917
  data = self.safe_dict(response, 'data')
5154
- resultList = self.safe_list_2(data, 'resultList', 'successList')
5918
+ resultList = self.safe_list_n(data, ['resultList', 'successList', 'list'])
5155
5919
  failureList = self.safe_list_2(data, 'failure', 'failureList')
5156
- responseList = self.array_concat(resultList, failureList)
5920
+ responseList = None
5921
+ if (resultList is not None) and (failureList is not None):
5922
+ responseList = self.array_concat(resultList, failureList)
5923
+ else:
5924
+ responseList = resultList
5157
5925
  return self.parse_orders(responseList)
5158
5926
 
5159
5927
  async def fetch_order(self, id: str, symbol: Str = None, params={}):
@@ -5162,10 +5930,12 @@ class bitget(Exchange, ImplicitAPI):
5162
5930
 
5163
5931
  https://www.bitget.com/api-doc/spot/trade/Get-Order-Info
5164
5932
  https://www.bitget.com/api-doc/contract/trade/Get-Order-Details
5933
+ https://www.bitget.com/api-doc/uta/trade/Get-Order-Details
5165
5934
 
5166
5935
  :param str id: the order id
5167
5936
  :param str symbol: unified symbol of the market the order was made in
5168
5937
  :param dict [params]: extra parameters specific to the exchange API endpoint
5938
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
5169
5939
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5170
5940
  """
5171
5941
  if symbol is None:
@@ -5176,7 +5946,11 @@ class bitget(Exchange, ImplicitAPI):
5176
5946
  'orderId': id,
5177
5947
  }
5178
5948
  response = None
5179
- if market['spot']:
5949
+ uta = None
5950
+ uta, params = self.handle_option_and_params(params, 'fetchOrder', 'uta', False)
5951
+ if uta:
5952
+ response = await self.privateUtaGetV3TradeOrderInfo(self.extend(request, params))
5953
+ elif market['spot']:
5180
5954
  response = await self.privateSpotGetV2SpotTradeOrderInfo(self.extend(request, params))
5181
5955
  elif market['swap'] or market['future']:
5182
5956
  request['symbol'] = market['id']
@@ -5253,13 +6027,60 @@ class bitget(Exchange, ImplicitAPI):
5253
6027
  # }
5254
6028
  # }
5255
6029
  #
5256
- if isinstance(response, str):
6030
+ # uta
6031
+ #
6032
+ # {
6033
+ # "code": "00000",
6034
+ # "msg": "success",
6035
+ # "requestTime": 1750496858333,
6036
+ # "data": {
6037
+ # "orderId": "1320244799629316096",
6038
+ # "clientOid": "1320244799633510400",
6039
+ # "category": "USDT-FUTURES",
6040
+ # "symbol": "BTCUSDT",
6041
+ # "orderType": "limit",
6042
+ # "side": "buy",
6043
+ # "price": "50000",
6044
+ # "qty": "0.001",
6045
+ # "amount": "0",
6046
+ # "cumExecQty": "0",
6047
+ # "cumExecValue": "0",
6048
+ # "avgPrice": "0",
6049
+ # "timeInForce": "gtc",
6050
+ # "orderStatus": "live",
6051
+ # "posSide": "long",
6052
+ # "holdMode": "hedge_mode",
6053
+ # "reduceOnly": "NO",
6054
+ # "feeDetail": [{
6055
+ # "feeCoin": "",
6056
+ # "fee": ""
6057
+ # }],
6058
+ # "createdTime": "1750496809871",
6059
+ # "updatedTime": "1750496809886",
6060
+ # "cancelReason": "",
6061
+ # "execType": "normal",
6062
+ # "stpMode": "none",
6063
+ # "tpTriggerBy": null,
6064
+ # "slTriggerBy": null,
6065
+ # "takeProfit": null,
6066
+ # "stopLoss": null,
6067
+ # "tpOrderType": null,
6068
+ # "slOrderType": null,
6069
+ # "tpLimitPrice": null,
6070
+ # "slLimitPrice": null
6071
+ # }
6072
+ # }
6073
+ #
6074
+ if not uta and (isinstance(response, str)):
5257
6075
  response = json.loads(response)
5258
6076
  data = self.safe_dict(response, 'data')
5259
6077
  if (data is not None):
5260
6078
  if not isinstance(data, list):
5261
6079
  return self.parse_order(data, market)
5262
6080
  dataList = self.safe_list(response, 'data', [])
6081
+ dataListLength = len(dataList)
6082
+ if dataListLength == 0:
6083
+ raise OrderNotFound(self.id + ' fetchOrder() could not find order id ' + id + ' in ' + self.json(response))
5263
6084
  first = self.safe_dict(dataList, 0, {})
5264
6085
  return self.parse_order(first, market)
5265
6086
  # first = self.safe_dict(data, 0, data)
@@ -5275,6 +6096,7 @@ class bitget(Exchange, ImplicitAPI):
5275
6096
  https://www.bitget.com/api-doc/contract/plan/get-orders-plan-pending
5276
6097
  https://www.bitget.com/api-doc/margin/cross/trade/Get-Cross-Open-Orders
5277
6098
  https://www.bitget.com/api-doc/margin/isolated/trade/Isolated-Open-Orders
6099
+ https://www.bitget.com/api-doc/uta/strategy/Get-Unfilled-Strategy-Orders
5278
6100
 
5279
6101
  :param str symbol: unified market symbol
5280
6102
  :param int [since]: the earliest time in ms to fetch open orders for
@@ -5286,6 +6108,7 @@ class bitget(Exchange, ImplicitAPI):
5286
6108
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
5287
6109
  :param str [params.isPlan]: *swap only* 'plan' for stop orders and 'profit_loss' for tp/sl orders, default is 'plan'
5288
6110
  :param boolean [params.trailing]: set to True if you want to fetch trailing orders
6111
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
5289
6112
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
5290
6113
  """
5291
6114
  await self.load_markets()
@@ -5294,6 +6117,8 @@ class bitget(Exchange, ImplicitAPI):
5294
6117
  request: dict = {}
5295
6118
  marginMode = None
5296
6119
  marginMode, params = self.handle_margin_mode_and_params('fetchOpenOrders', params)
6120
+ uta = None
6121
+ uta, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'uta', False)
5297
6122
  if symbol is not None:
5298
6123
  market = self.market(symbol)
5299
6124
  request['symbol'] = market['id']
@@ -5307,58 +6132,71 @@ class bitget(Exchange, ImplicitAPI):
5307
6132
  paginate, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'paginate')
5308
6133
  if paginate:
5309
6134
  cursorReceived = None
5310
- if type == 'spot':
6135
+ cursorSent = None
6136
+ if uta:
6137
+ cursorReceived = 'cursor'
6138
+ cursorSent = 'cursor'
6139
+ elif type == 'spot':
5311
6140
  if marginMode is not None:
5312
6141
  cursorReceived = 'minId'
6142
+ cursorSent = 'idLessThan'
5313
6143
  else:
5314
6144
  cursorReceived = 'endId'
5315
- return await self.fetch_paginated_call_cursor('fetchOpenOrders', symbol, since, limit, params, cursorReceived, 'idLessThan')
6145
+ cursorSent = 'idLessThan'
6146
+ return await self.fetch_paginated_call_cursor('fetchOpenOrders', symbol, since, limit, params, cursorReceived, cursorSent)
5316
6147
  response = None
5317
6148
  trailing = self.safe_bool(params, 'trailing')
5318
6149
  trigger = self.safe_bool_2(params, 'stop', 'trigger')
5319
6150
  planTypeDefined = self.safe_string(params, 'planType') is not None
5320
6151
  isTrigger = (trigger or planTypeDefined)
5321
- params = self.omit(params, ['stop', 'trigger', 'trailing'])
5322
6152
  request, params = self.handle_until_option('endTime', request, params)
5323
6153
  if since is not None:
5324
6154
  request['startTime'] = since
5325
6155
  if limit is not None:
5326
6156
  request['limit'] = limit
5327
- if (type == 'swap') or (type == 'future') or (marginMode is not None):
6157
+ if not uta and ((type == 'swap') or (type == 'future') or (marginMode is not None)):
5328
6158
  clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
5329
6159
  params = self.omit(params, 'clientOrderId')
5330
6160
  if clientOrderId is not None:
5331
6161
  request['clientOid'] = clientOrderId
5332
- query = None
5333
- query = self.omit(params, ['type'])
5334
- if type == 'spot':
6162
+ productType = None
6163
+ productType, params = self.handle_product_type_and_params(market, params)
6164
+ params = self.omit(params, ['type', 'stop', 'trigger', 'trailing'])
6165
+ if uta:
6166
+ if type == 'spot':
6167
+ if marginMode is not None:
6168
+ productType = 'MARGIN'
6169
+ request['category'] = productType
6170
+ if trigger:
6171
+ response = await self.privateUtaGetV3TradeUnfilledStrategyOrders(self.extend(request, params))
6172
+ else:
6173
+ response = await self.privateUtaGetV3TradeUnfilledOrders(self.extend(request, params))
6174
+ elif type == 'spot':
5335
6175
  if marginMode is not None:
5336
6176
  if since is None:
5337
6177
  since = self.milliseconds() - 7776000000
5338
6178
  request['startTime'] = since
5339
6179
  if marginMode == 'isolated':
5340
- response = await self.privateMarginGetV2MarginIsolatedOpenOrders(self.extend(request, query))
6180
+ response = await self.privateMarginGetV2MarginIsolatedOpenOrders(self.extend(request, params))
5341
6181
  elif marginMode == 'cross':
5342
- response = await self.privateMarginGetV2MarginCrossedOpenOrders(self.extend(request, query))
6182
+ response = await self.privateMarginGetV2MarginCrossedOpenOrders(self.extend(request, params))
5343
6183
  else:
5344
6184
  if trigger:
5345
- response = await self.privateSpotGetV2SpotTradeCurrentPlanOrder(self.extend(request, query))
6185
+ response = await self.privateSpotGetV2SpotTradeCurrentPlanOrder(self.extend(request, params))
5346
6186
  else:
5347
- response = await self.privateSpotGetV2SpotTradeUnfilledOrders(self.extend(request, query))
6187
+ response = await self.privateSpotGetV2SpotTradeUnfilledOrders(self.extend(request, params))
5348
6188
  else:
5349
- productType = None
5350
- productType, query = self.handle_product_type_and_params(market, query)
5351
6189
  request['productType'] = productType
5352
6190
  if trailing:
5353
6191
  planType = self.safe_string(params, 'planType', 'track_plan')
5354
6192
  request['planType'] = planType
5355
- response = await self.privateMixGetV2MixOrderOrdersPlanPending(self.extend(request, query))
6193
+ response = await self.privateMixGetV2MixOrderOrdersPlanPending(self.extend(request, params))
5356
6194
  elif isTrigger:
5357
- planType = self.safe_string(query, 'planType', 'normal_plan')
6195
+ planType = self.safe_string(params, 'planType', 'normal_plan')
5358
6196
  request['planType'] = planType
5359
- response = await self.privateMixGetV2MixOrderOrdersPlanPending(self.extend(request, query))
6197
+ response = await self.privateMixGetV2MixOrderOrdersPlanPending(self.extend(request, params))
5360
6198
  else:
5361
- response = await self.privateMixGetV2MixOrderOrdersPending(self.extend(request, query))
6199
+ response = await self.privateMixGetV2MixOrderOrdersPending(self.extend(request, params))
5362
6200
  #
5363
6201
  # spot
5364
6202
  #
@@ -5534,8 +6372,92 @@ class bitget(Exchange, ImplicitAPI):
5534
6372
  # }
5535
6373
  # }
5536
6374
  #
6375
+ # uta
6376
+ #
6377
+ # {
6378
+ # "code": "00000",
6379
+ # "msg": "success",
6380
+ # "requestTime": 1750753395850,
6381
+ # "data": {
6382
+ # "list": [
6383
+ # {
6384
+ # "orderId": "1321320757371228160",
6385
+ # "clientOid": "1321320757371228161",
6386
+ # "category": "USDT-FUTURES",
6387
+ # "symbol": "BTCUSDT",
6388
+ # "orderType": "limit",
6389
+ # "side": "buy",
6390
+ # "price": "50000",
6391
+ # "qty": "0.001",
6392
+ # "amount": "0",
6393
+ # "cumExecQty": "0",
6394
+ # "cumExecValue": "0",
6395
+ # "avgPrice": "0",
6396
+ # "timeInForce": "gtc",
6397
+ # "orderStatus": "live",
6398
+ # "posSide": "long",
6399
+ # "holdMode": "hedge_mode",
6400
+ # "reduceOnly": "NO",
6401
+ # "feeDetail": [
6402
+ # {
6403
+ # "feeCoin": "",
6404
+ # "fee": ""
6405
+ # }
6406
+ # ],
6407
+ # "createdTime": "1750753338186",
6408
+ # "updatedTime": "1750753338203",
6409
+ # "stpMode": "none",
6410
+ # "tpTriggerBy": null,
6411
+ # "slTriggerBy": null,
6412
+ # "takeProfit": null,
6413
+ # "stopLoss": null,
6414
+ # "tpOrderType": null,
6415
+ # "slOrderType": null,
6416
+ # "tpLimitPrice": null,
6417
+ # "slLimitPrice": null
6418
+ # }
6419
+ # ],
6420
+ # "cursor": "1321320757371228160"
6421
+ # }
6422
+ # }
6423
+ #
6424
+ # uta trigger
6425
+ #
6426
+ # {
6427
+ # "code": "00000",
6428
+ # "msg": "success",
6429
+ # "requestTime": 1753057527060,
6430
+ # "data": [
6431
+ # {
6432
+ # "orderId": "1330984742276198400",
6433
+ # "clientOid": "1330984742276198400",
6434
+ # "symbol": "BTCUSDT",
6435
+ # "category": "USDT-FUTURES",
6436
+ # "qty": "0.001",
6437
+ # "posSide": "long",
6438
+ # "tpTriggerBy": "market",
6439
+ # "slTriggerBy": "mark",
6440
+ # "takeProfit": "",
6441
+ # "stopLoss":"114000",
6442
+ # "tpOrderType": "market",
6443
+ # "slOrderType": "limit",
6444
+ # "tpLimitPrice": "",
6445
+ # "slLimitPrice": "113000",
6446
+ # "createdTime": "1753057411736",
6447
+ # "updatedTime": "1753057411747"
6448
+ # }
6449
+ # ]
6450
+ # }
6451
+ #
5537
6452
  data = self.safe_value(response, 'data')
5538
- if type == 'spot':
6453
+ if uta:
6454
+ result = None
6455
+ if trigger:
6456
+ result = self.safe_list(response, 'data', [])
6457
+ else:
6458
+ result = self.safe_list(data, 'list', [])
6459
+ return self.parse_orders(result, market, since, limit)
6460
+ elif type == 'spot':
5539
6461
  if (marginMode is not None) or trigger:
5540
6462
  resultList = self.safe_list(data, 'orderList', [])
5541
6463
  return self.parse_orders(resultList, market, since, limit)
@@ -5554,6 +6476,7 @@ class bitget(Exchange, ImplicitAPI):
5554
6476
  https://www.bitget.com/api-doc/contract/plan/orders-plan-history
5555
6477
  https://www.bitget.com/api-doc/margin/cross/trade/Get-Cross-Order-History
5556
6478
  https://www.bitget.com/api-doc/margin/isolated/trade/Get-Isolated-Order-History
6479
+ https://www.bitget.com/api-doc/uta/trade/Get-Order-History
5557
6480
 
5558
6481
  :param str symbol: unified market symbol of the closed orders
5559
6482
  :param int [since]: timestamp in ms of the earliest order
@@ -5581,6 +6504,7 @@ class bitget(Exchange, ImplicitAPI):
5581
6504
  https://www.bitget.com/api-doc/contract/plan/orders-plan-history
5582
6505
  https://www.bitget.com/api-doc/margin/cross/trade/Get-Cross-Order-History
5583
6506
  https://www.bitget.com/api-doc/margin/isolated/trade/Get-Isolated-Order-History
6507
+ https://www.bitget.com/api-doc/uta/trade/Get-Order-History
5584
6508
 
5585
6509
  :param str symbol: unified market symbol of the canceled orders
5586
6510
  :param int [since]: timestamp in ms of the earliest order
@@ -5607,6 +6531,8 @@ class bitget(Exchange, ImplicitAPI):
5607
6531
  https://www.bitget.com/api-doc/contract/plan/orders-plan-history
5608
6532
  https://www.bitget.com/api-doc/margin/cross/trade/Get-Cross-Order-History
5609
6533
  https://www.bitget.com/api-doc/margin/isolated/trade/Get-Isolated-Order-History
6534
+ https://www.bitget.com/api-doc/uta/trade/Get-Order-History
6535
+ https://www.bitget.com/api-doc/uta/strategy/Get-History-Strategy-Orders
5610
6536
 
5611
6537
  fetches information on multiple canceled and closed orders made by the user
5612
6538
  :param str symbol: unified market symbol of the market orders were made in
@@ -5619,8 +6545,13 @@ class bitget(Exchange, ImplicitAPI):
5619
6545
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
5620
6546
  :param str [params.isPlan]: *swap only* 'plan' for stop orders and 'profit_loss' for tp/sl orders, default is 'plan'
5621
6547
  :param boolean [params.trailing]: set to True if you want to fetch trailing orders
6548
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
5622
6549
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
5623
6550
  """
6551
+ uta = None
6552
+ uta, params = self.handle_option_and_params(params, 'fetchCanceledAndClosedOrders', 'uta', False)
6553
+ if uta:
6554
+ return await self.fetch_uta_canceled_and_closed_orders(symbol, since, limit, params)
5624
6555
  await self.load_markets()
5625
6556
  market = None
5626
6557
  request: dict = {}
@@ -5882,42 +6813,160 @@ class bitget(Exchange, ImplicitAPI):
5882
6813
  orders = self.safe_list(response, 'data', [])
5883
6814
  return self.parse_orders(orders, market, since, limit)
5884
6815
 
5885
- async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
5886
- """
5887
- fetch the history of changes, actions done by the user or operations that altered the balance of the user
5888
-
5889
- https://www.bitget.com/api-doc/spot/account/Get-Account-Bills
5890
- https://www.bitget.com/api-doc/contract/account/Get-Account-Bill
5891
-
5892
- :param str [code]: unified currency code, default is None
5893
- :param int [since]: timestamp in ms of the earliest ledger entry, default is None
5894
- :param int [limit]: max number of ledger entries to return, default is None
5895
- :param dict [params]: extra parameters specific to the exchange API endpoint
5896
- :param int [params.until]: end time in ms
5897
- :param str [params.symbol]: *contract only* unified market symbol
5898
- :param str [params.productType]: *contract only* 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
5899
- :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
5900
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
5901
- """
6816
+ async def fetch_uta_canceled_and_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
5902
6817
  await self.load_markets()
5903
- symbol = self.safe_string(params, 'symbol')
5904
- params = self.omit(params, 'symbol')
5905
6818
  market = None
5906
6819
  if symbol is not None:
5907
6820
  market = self.market(symbol)
5908
- marketType = None
5909
- marketType, params = self.handle_market_type_and_params('fetchLedger', market, params)
6821
+ productType = None
6822
+ productType, params = self.handle_product_type_and_params(market, params)
6823
+ if productType == 'SPOT':
6824
+ marginMode = None
6825
+ marginMode, params = self.handle_margin_mode_and_params('fetchCanceledAndClosedOrders', params)
6826
+ if marginMode is not None:
6827
+ productType = 'MARGIN'
6828
+ request: dict = {
6829
+ 'category': productType,
6830
+ }
5910
6831
  paginate = False
5911
- paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
6832
+ paginate, params = self.handle_option_and_params(params, 'fetchCanceledAndClosedOrders', 'paginate')
5912
6833
  if paginate:
5913
- cursorReceived = None
5914
- if marketType != 'spot':
5915
- cursorReceived = 'endId'
5916
- return await self.fetch_paginated_call_cursor('fetchLedger', symbol, since, limit, params, cursorReceived, 'idLessThan')
5917
- currency = None
5918
- request: dict = {}
5919
- if code is not None:
5920
- currency = self.currency(code)
6834
+ return await self.fetch_paginated_call_cursor('fetchCanceledAndClosedOrders', symbol, since, limit, params, 'cursor', 'cursor')
6835
+ request, params = self.handle_until_option('endTime', request, params)
6836
+ if since is not None:
6837
+ request['startTime'] = since
6838
+ if limit is not None:
6839
+ request['limit'] = limit
6840
+ response = None
6841
+ trigger = self.safe_bool_2(params, 'stop', 'trigger')
6842
+ params = self.omit(params, ['stop', 'trigger'])
6843
+ if trigger:
6844
+ response = await self.privateUtaGetV3TradeHistoryStrategyOrders(self.extend(request, params))
6845
+ else:
6846
+ response = await self.privateUtaGetV3TradeHistoryOrders(self.extend(request, params))
6847
+ #
6848
+ # uta
6849
+ #
6850
+ # {
6851
+ # "code": "00000",
6852
+ # "msg": "success",
6853
+ # "requestTime": 1752531592855,
6854
+ # "data": {
6855
+ # "list": [
6856
+ # {
6857
+ # "orderId": "1322441400976261120",
6858
+ # "clientOid": "1322441400976261121",
6859
+ # "category": "USDT-FUTURES",
6860
+ # "symbol": "BTCUSDT",
6861
+ # "orderType": "market",
6862
+ # "side": "sell",
6863
+ # "price": "0",
6864
+ # "qty": "0.0001",
6865
+ # "amount": "0",
6866
+ # "cumExecQty": "0.0001",
6867
+ # "cumExecValue": "10.7005",
6868
+ # "avgPrice": "107005.4",
6869
+ # "timeInForce": "gtc",
6870
+ # "orderStatus": "filled",
6871
+ # "posSide": "long",
6872
+ # "holdMode": "hedge_mode",
6873
+ # "reduceOnly": "NO",
6874
+ # "feeDetail": [
6875
+ # {
6876
+ # "feeCoin": "USDT",
6877
+ # "fee": "0.00642032"
6878
+ # }
6879
+ # ],
6880
+ # "createdTime": "1751020520442",
6881
+ # "updatedTime": "1751020520457",
6882
+ # "cancelReason": "",
6883
+ # "execType": "normal",
6884
+ # "stpMode": "none",
6885
+ # "tpTriggerBy": null,
6886
+ # "slTriggerBy": null,
6887
+ # "takeProfit": null,
6888
+ # "stopLoss": null,
6889
+ # "tpOrderType": null,
6890
+ # "slOrderType": null,
6891
+ # "tpLimitPrice": null,
6892
+ # "slLimitPrice": null
6893
+ # },
6894
+ # ],
6895
+ # "cursor": "1322441328637100035"
6896
+ # }
6897
+ # }
6898
+ #
6899
+ # uta trigger
6900
+ #
6901
+ # {
6902
+ # "code": "00000",
6903
+ # "msg": "success",
6904
+ # "requestTime": 1753058447920,
6905
+ # "data": {
6906
+ # "list": [
6907
+ # {
6908
+ # "orderId": "1330984742276198400",
6909
+ # "clientOid": "1330984742276198400",
6910
+ # "symbol": "BTCUSDT",
6911
+ # "category": "USDT-FUTURES",
6912
+ # "qty": "0.001",
6913
+ # "posSide": "long",
6914
+ # "tpTriggerBy": "market",
6915
+ # "slTriggerBy": "mark",
6916
+ # "takeProfit": "",
6917
+ # "stopLoss": "112000",
6918
+ # "tpOrderType": "market",
6919
+ # "slOrderType": "limit",
6920
+ # "tpLimitPrice": "",
6921
+ # "slLimitPrice": "111000",
6922
+ # "createdTime": "1753057411736",
6923
+ # "updatedTime": "1753058267412"
6924
+ # },
6925
+ # ],
6926
+ # "cursor": 1330960754317619202
6927
+ # }
6928
+ # }
6929
+ #
6930
+ data = self.safe_dict(response, 'data', {})
6931
+ orders = self.safe_list(data, 'list', [])
6932
+ return self.parse_orders(orders, market, since, limit)
6933
+
6934
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
6935
+ """
6936
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
6937
+
6938
+ https://www.bitget.com/api-doc/spot/account/Get-Account-Bills
6939
+ https://www.bitget.com/api-doc/contract/account/Get-Account-Bill
6940
+
6941
+ :param str [code]: unified currency code, default is None
6942
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
6943
+ :param int [limit]: max number of ledger entries to return, default is None
6944
+ :param dict [params]: extra parameters specific to the exchange API endpoint
6945
+ :param int [params.until]: end time in ms
6946
+ :param str [params.symbol]: *contract only* unified market symbol
6947
+ :param str [params.productType]: *contract only* 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
6948
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
6949
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
6950
+ """
6951
+ await self.load_markets()
6952
+ symbol = self.safe_string(params, 'symbol')
6953
+ params = self.omit(params, 'symbol')
6954
+ market = None
6955
+ if symbol is not None:
6956
+ market = self.market(symbol)
6957
+ marketType = None
6958
+ marketType, params = self.handle_market_type_and_params('fetchLedger', market, params)
6959
+ paginate = False
6960
+ paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
6961
+ if paginate:
6962
+ cursorReceived = None
6963
+ if marketType != 'spot':
6964
+ cursorReceived = 'endId'
6965
+ return await self.fetch_paginated_call_cursor('fetchLedger', symbol, since, limit, params, cursorReceived, 'idLessThan')
6966
+ currency = None
6967
+ request: dict = {}
6968
+ if code is not None:
6969
+ currency = self.currency(code)
5921
6970
  request['coin'] = currency['id']
5922
6971
  request, params = self.handle_until_option('endTime', request, params)
5923
6972
  if since is not None:
@@ -6097,55 +7146,67 @@ class bitget(Exchange, ImplicitAPI):
6097
7146
  https://www.bitget.com/api-doc/contract/trade/Get-Order-Fills
6098
7147
  https://www.bitget.com/api-doc/margin/cross/trade/Get-Cross-Order-Fills
6099
7148
  https://www.bitget.com/api-doc/margin/isolated/trade/Get-Isolated-Transaction-Details
7149
+ https://www.bitget.com/api-doc/uta/trade/Get-Order-Fills
6100
7150
 
6101
7151
  :param str symbol: unified market symbol
6102
7152
  :param int [since]: the earliest time in ms to fetch trades for
6103
7153
  :param int [limit]: the maximum number of trades structures to retrieve
6104
7154
  :param dict [params]: extra parameters specific to the exchange API endpoint
6105
7155
  :param int [params.until]: the latest time in ms to fetch trades for
7156
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
6106
7157
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
6107
7158
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
6108
7159
  """
6109
- if symbol is None:
7160
+ uta = None
7161
+ uta, params = self.handle_option_and_params(params, 'fetchMyTrades', 'uta', False)
7162
+ if not uta and (symbol is None):
6110
7163
  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
6111
7164
  await self.load_markets()
6112
7165
  market = self.market(symbol)
6113
- marginMode = None
6114
- marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
7166
+ request: dict = {}
7167
+ request, params = self.handle_until_option('endTime', request, params)
7168
+ if since is not None:
7169
+ request['startTime'] = since
7170
+ if limit is not None:
7171
+ request['limit'] = limit
6115
7172
  paginate = False
7173
+ marginMode = None
6116
7174
  paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
7175
+ marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
6117
7176
  if paginate:
6118
7177
  cursorReceived = None
6119
- if market['spot']:
7178
+ cursorSent = None
7179
+ if uta:
7180
+ cursorReceived = 'cursor'
7181
+ cursorSent = 'cursor'
7182
+ elif market['spot']:
6120
7183
  if marginMode is not None:
6121
7184
  cursorReceived = 'minId'
7185
+ cursorSent = 'idLessThan'
6122
7186
  else:
6123
7187
  cursorReceived = 'endId'
6124
- return await self.fetch_paginated_call_cursor('fetchMyTrades', symbol, since, limit, params, cursorReceived, 'idLessThan')
7188
+ cursorSent = 'idLessThan'
7189
+ return await self.fetch_paginated_call_cursor('fetchMyTrades', symbol, since, limit, params, cursorReceived, cursorSent)
6125
7190
  response = None
6126
- request: dict = {
6127
- 'symbol': market['id'],
6128
- }
6129
- request, params = self.handle_until_option('endTime', request, params)
6130
- if since is not None:
6131
- request['startTime'] = since
6132
- if limit is not None:
6133
- request['limit'] = limit
6134
- if market['spot']:
6135
- if marginMode is not None:
6136
- if since is None:
6137
- request['startTime'] = self.milliseconds() - 7776000000
6138
- if marginMode == 'isolated':
6139
- response = await self.privateMarginGetV2MarginIsolatedFills(self.extend(request, params))
6140
- elif marginMode == 'cross':
6141
- response = await self.privateMarginGetV2MarginCrossedFills(self.extend(request, params))
6142
- else:
6143
- response = await self.privateSpotGetV2SpotTradeFills(self.extend(request, params))
7191
+ if uta:
7192
+ response = await self.privateUtaGetV3TradeFills(self.extend(request, params))
6144
7193
  else:
6145
- productType = None
6146
- productType, params = self.handle_product_type_and_params(market, params)
6147
- request['productType'] = productType
6148
- response = await self.privateMixGetV2MixOrderFills(self.extend(request, params))
7194
+ request['symbol'] = market['id']
7195
+ if market['spot']:
7196
+ if marginMode is not None:
7197
+ if since is None:
7198
+ request['startTime'] = self.milliseconds() - 7776000000
7199
+ if marginMode == 'isolated':
7200
+ response = await self.privateMarginGetV2MarginIsolatedFills(self.extend(request, params))
7201
+ elif marginMode == 'cross':
7202
+ response = await self.privateMarginGetV2MarginCrossedFills(self.extend(request, params))
7203
+ else:
7204
+ response = await self.privateSpotGetV2SpotTradeFills(self.extend(request, params))
7205
+ else:
7206
+ productType = None
7207
+ productType, params = self.handle_product_type_and_params(market, params)
7208
+ request['productType'] = productType
7209
+ response = await self.privateMixGetV2MixOrderFills(self.extend(request, params))
6149
7210
  #
6150
7211
  # spot
6151
7212
  #
@@ -6245,10 +7306,45 @@ class bitget(Exchange, ImplicitAPI):
6245
7306
  # }
6246
7307
  # }
6247
7308
  #
7309
+ # uta
7310
+ #
7311
+ # {
7312
+ # "code": "00000",
7313
+ # "msg": "success",
7314
+ # "requestTime": 1751099666579,
7315
+ # "data": {
7316
+ # "list": [
7317
+ # {
7318
+ # "execId": "1322441401010528257",
7319
+ # "orderId": "1322441400976261120",
7320
+ # "category": "USDT-FUTURES",
7321
+ # "symbol": "BTCUSDT",
7322
+ # "orderType": "market",
7323
+ # "side": "sell",
7324
+ # "execPrice": "107005.4",
7325
+ # "execQty": "0.0001",
7326
+ # "execValue": "10.7005",
7327
+ # "tradeScope": "taker",
7328
+ # "feeDetail": [{
7329
+ # "feeCoin": "USDT",
7330
+ # "fee":"0.00642032"
7331
+ # }],
7332
+ # "createdTime": "1751020520451",
7333
+ # "updatedTime": "1751020520458",
7334
+ # "execPnl": "0.00017"
7335
+ # },
7336
+ # ],
7337
+ # "cursor": "1322061241878880257"
7338
+ # }
7339
+ # }
7340
+ #
6248
7341
  data = self.safe_value(response, 'data')
6249
- if (market['swap']) or (market['future']):
6250
- fillList = self.safe_list(data, 'fillList', [])
6251
- return self.parse_trades(fillList, market, since, limit)
7342
+ if uta:
7343
+ fills = self.safe_list(data, 'list', [])
7344
+ return self.parse_trades(fills, market, since, limit)
7345
+ elif (market['swap'] or (market['future'])):
7346
+ fills = self.safe_list(data, 'fillList', [])
7347
+ return self.parse_trades(fills, market, since, limit)
6252
7348
  elif marginMode is not None:
6253
7349
  fills = self.safe_list(data, 'fills', [])
6254
7350
  return self.parse_trades(fills, market, since, limit)
@@ -6259,9 +7355,11 @@ class bitget(Exchange, ImplicitAPI):
6259
7355
  fetch data on a single open contract trade position
6260
7356
 
6261
7357
  https://www.bitget.com/api-doc/contract/position/get-single-position
7358
+ https://www.bitget.com/api-doc/uta/trade/Get-Position
6262
7359
 
6263
7360
  :param str symbol: unified market symbol of the market the position is held in
6264
7361
  :param dict [params]: extra parameters specific to the exchange API endpoint
7362
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
6265
7363
  :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
6266
7364
  """
6267
7365
  await self.load_markets()
@@ -6270,42 +7368,90 @@ class bitget(Exchange, ImplicitAPI):
6270
7368
  productType, params = self.handle_product_type_and_params(market, params)
6271
7369
  request: dict = {
6272
7370
  'symbol': market['id'],
6273
- 'marginCoin': market['settleId'],
6274
- 'productType': productType,
6275
7371
  }
6276
- response = await self.privateMixGetV2MixPositionSinglePosition(self.extend(request, params))
6277
- #
6278
- # {
6279
- # "code": "00000",
6280
- # "msg": "success",
6281
- # "requestTime": 1700807531673,
6282
- # "data": [
6283
- # {
6284
- # "marginCoin": "USDT",
6285
- # "symbol": "BTCUSDT",
6286
- # "holdSide": "long",
6287
- # "openDelegateSize": "0",
6288
- # "marginSize": "3.73555",
6289
- # "available": "0.002",
6290
- # "locked": "0",
6291
- # "total": "0.002",
6292
- # "leverage": "20",
6293
- # "achievedProfits": "0",
6294
- # "openPriceAvg": "37355.5",
6295
- # "marginMode": "crossed",
6296
- # "posMode": "hedge_mode",
6297
- # "unrealizedPL": "0.007",
6298
- # "liquidationPrice": "31724.970702417",
6299
- # "keepMarginRate": "0.004",
6300
- # "markPrice": "37359",
6301
- # "marginRatio": "0.029599540355",
6302
- # "cTime": "1700807507275"
6303
- # }
6304
- # ]
6305
- # }
6306
- #
6307
- data = self.safe_list(response, 'data', [])
6308
- first = self.safe_dict(data, 0, {})
7372
+ response = None
7373
+ uta = None
7374
+ result = None
7375
+ uta, params = self.handle_option_and_params(params, 'fetchPosition', 'uta', False)
7376
+ if uta:
7377
+ request['category'] = productType
7378
+ response = await self.privateUtaGetV3PositionCurrentPosition(self.extend(request, params))
7379
+ #
7380
+ # {
7381
+ # "code": "00000",
7382
+ # "msg": "success",
7383
+ # "requestTime": 1750929905423,
7384
+ # "data": {
7385
+ # "list": [
7386
+ # {
7387
+ # "category": "USDT-FUTURES",
7388
+ # "symbol": "BTCUSDT",
7389
+ # "marginCoin": "USDT",
7390
+ # "holdMode": "hedge_mode",
7391
+ # "posSide": "long",
7392
+ # "marginMode": "crossed",
7393
+ # "positionBalance": "5.435199",
7394
+ # "available": "0.001",
7395
+ # "frozen": "0",
7396
+ # "total": "0.001",
7397
+ # "leverage": "20",
7398
+ # "curRealisedPnl": "0",
7399
+ # "avgPrice": "107410.3",
7400
+ # "positionStatus": "normal",
7401
+ # "unrealisedPnl": "0.0047",
7402
+ # "liquidationPrice": "0",
7403
+ # "mmr": "0.004",
7404
+ # "profitRate": "0.0008647337475591",
7405
+ # "markPrice": "107415.3",
7406
+ # "breakEvenPrice": "107539.2",
7407
+ # "totalFunding": "0",
7408
+ # "openFeeTotal": "-0.06444618",
7409
+ # "closeFeeTotal": "0",
7410
+ # "createdTime": "1750495670699",
7411
+ # "updatedTime": "1750929883465"
7412
+ # }
7413
+ # ]
7414
+ # }
7415
+ # }
7416
+ #
7417
+ data = self.safe_dict(response, 'data', {})
7418
+ result = self.safe_list(data, 'list', [])
7419
+ else:
7420
+ request['marginCoin'] = market['settleId']
7421
+ request['productType'] = productType
7422
+ response = await self.privateMixGetV2MixPositionSinglePosition(self.extend(request, params))
7423
+ #
7424
+ # {
7425
+ # "code": "00000",
7426
+ # "msg": "success",
7427
+ # "requestTime": 1700807531673,
7428
+ # "data": [
7429
+ # {
7430
+ # "marginCoin": "USDT",
7431
+ # "symbol": "BTCUSDT",
7432
+ # "holdSide": "long",
7433
+ # "openDelegateSize": "0",
7434
+ # "marginSize": "3.73555",
7435
+ # "available": "0.002",
7436
+ # "locked": "0",
7437
+ # "total": "0.002",
7438
+ # "leverage": "20",
7439
+ # "achievedProfits": "0",
7440
+ # "openPriceAvg": "37355.5",
7441
+ # "marginMode": "crossed",
7442
+ # "posMode": "hedge_mode",
7443
+ # "unrealizedPL": "0.007",
7444
+ # "liquidationPrice": "31724.970702417",
7445
+ # "keepMarginRate": "0.004",
7446
+ # "markPrice": "37359",
7447
+ # "marginRatio": "0.029599540355",
7448
+ # "cTime": "1700807507275"
7449
+ # }
7450
+ # ]
7451
+ # }
7452
+ #
7453
+ result = self.safe_list(response, 'data', [])
7454
+ first = self.safe_dict(result, 0, {})
6309
7455
  return self.parse_position(first, market)
6310
7456
 
6311
7457
  async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
@@ -6468,6 +7614,36 @@ class bitget(Exchange, ImplicitAPI):
6468
7614
  # "cTime": "1700807507275"
6469
7615
  # }
6470
7616
  #
7617
+ # uta: fetchPosition
7618
+ #
7619
+ # {
7620
+ # "category": "USDT-FUTURES",
7621
+ # "symbol": "BTCUSDT",
7622
+ # "marginCoin": "USDT",
7623
+ # "holdMode": "hedge_mode",
7624
+ # "posSide": "long",
7625
+ # "marginMode": "crossed",
7626
+ # "positionBalance": "5.435199",
7627
+ # "available": "0.001",
7628
+ # "frozen": "0",
7629
+ # "total": "0.001",
7630
+ # "leverage": "20",
7631
+ # "curRealisedPnl": "0",
7632
+ # "avgPrice": "107410.3",
7633
+ # "positionStatus": "normal",
7634
+ # "unrealisedPnl": "0.0047",
7635
+ # "liquidationPrice": "0",
7636
+ # "mmr": "0.004",
7637
+ # "profitRate": "0.0008647337475591",
7638
+ # "markPrice": "107415.3",
7639
+ # "breakEvenPrice": "107539.2",
7640
+ # "totalFunding": "0",
7641
+ # "openFeeTotal": "-0.06444618",
7642
+ # "closeFeeTotal": "0",
7643
+ # "createdTime": "1750495670699",
7644
+ # "updatedTime": "1750929883465"
7645
+ # }
7646
+ #
6471
7647
  # fetchPositions: privateMixGetV2MixPositionAllPosition
6472
7648
  #
6473
7649
  # {
@@ -6519,32 +7695,55 @@ class bitget(Exchange, ImplicitAPI):
6519
7695
  # "clientOid": "1120923953904893956"
6520
7696
  # }
6521
7697
  #
7698
+ # uta: fetchPositionsHistory
7699
+ #
7700
+ # {
7701
+ # "positionId": "1322441328637100049",
7702
+ # "category": "USDT-FUTURES",
7703
+ # "symbol": "BTCUSDT",
7704
+ # "marginCoin": "USDT",
7705
+ # "holdMode": "hedge_mode",
7706
+ # "posSide": "long",
7707
+ # "marginMode": "crossed",
7708
+ # "openPriceAvg": "107003.7",
7709
+ # "closePriceAvg": "107005.4",
7710
+ # "openTotalPos": "0.0001",
7711
+ # "closeTotalPos": "0.0001",
7712
+ # "cumRealisedPnl": "0.00017",
7713
+ # "netProfit": "-0.01267055",
7714
+ # "totalFunding": "0",
7715
+ # "openFeeTotal": "-0.00642022",
7716
+ # "closeFeeTotal": "-0.00642032",
7717
+ # "createdTime": "1751020503195",
7718
+ # "updatedTime": "1751020520458"
7719
+ # }
7720
+ #
6522
7721
  marketId = self.safe_string(position, 'symbol')
6523
7722
  market = self.safe_market(marketId, market, None, 'contract')
6524
7723
  symbol = market['symbol']
6525
- timestamp = self.safe_integer_2(position, 'cTime', 'ctime')
7724
+ timestamp = self.safe_integer_n(position, ['cTime', 'ctime', 'createdTime'])
6526
7725
  marginMode = self.safe_string(position, 'marginMode')
6527
7726
  collateral = None
6528
7727
  initialMargin = None
6529
- unrealizedPnl = self.safe_string(position, 'unrealizedPL')
6530
- rawCollateral = self.safe_string(position, 'marginSize')
7728
+ unrealizedPnl = self.safe_string_2(position, 'unrealizedPL', 'unrealisedPnl')
7729
+ rawCollateral = self.safe_string_2(position, 'marginSize', 'positionBalance')
6531
7730
  if marginMode == 'isolated':
6532
7731
  collateral = Precise.string_add(rawCollateral, unrealizedPnl)
6533
7732
  elif marginMode == 'crossed':
6534
7733
  marginMode = 'cross'
6535
7734
  initialMargin = rawCollateral
6536
- holdMode = self.safe_string(position, 'posMode')
7735
+ holdMode = self.safe_string_2(position, 'posMode', 'holdMode')
6537
7736
  hedged = None
6538
7737
  if holdMode == 'hedge_mode':
6539
7738
  hedged = True
6540
7739
  elif holdMode == 'one_way_mode':
6541
7740
  hedged = False
6542
- side = self.safe_string(position, 'holdSide')
7741
+ side = self.safe_string_2(position, 'holdSide', 'posSide')
6543
7742
  leverage = self.safe_string(position, 'leverage')
6544
7743
  contractSizeNumber = self.safe_value(market, 'contractSize')
6545
7744
  contractSize = self.number_to_string(contractSizeNumber)
6546
- baseAmount = self.safe_string(position, 'total')
6547
- entryPrice = self.safe_string_2(position, 'openPriceAvg', 'openAvgPrice')
7745
+ baseAmount = self.safe_string_2(position, 'total', 'openTotalPos')
7746
+ entryPrice = self.safe_string_n(position, ['openPriceAvg', 'openAvgPrice', 'avgPrice'])
6548
7747
  maintenanceMarginPercentage = self.safe_string(position, 'keepMarginRate')
6549
7748
  openNotional = Precise.string_mul(entryPrice, baseAmount)
6550
7749
  if initialMargin is None:
@@ -6576,31 +7775,31 @@ class bitget(Exchange, ImplicitAPI):
6576
7775
  percentage = Precise.string_mul(Precise.string_div(unrealizedPnl, initialMargin, 4), '100')
6577
7776
  return self.safe_position({
6578
7777
  'info': position,
6579
- 'id': self.safe_string(position, 'orderId'),
7778
+ 'id': self.safe_string_2(position, 'orderId', 'positionId'),
6580
7779
  'symbol': symbol,
6581
7780
  'notional': self.parse_number(notional),
6582
7781
  'marginMode': marginMode,
6583
7782
  'liquidationPrice': liquidationPrice,
6584
7783
  'entryPrice': self.parse_number(entryPrice),
6585
7784
  'unrealizedPnl': self.parse_number(unrealizedPnl),
6586
- 'realizedPnl': self.safe_number(position, 'pnl'),
7785
+ 'realizedPnl': self.safe_number_n(position, ['pnl', 'curRealisedPnl', 'cumRealisedPnl']),
6587
7786
  'percentage': self.parse_number(percentage),
6588
7787
  'contracts': contracts,
6589
7788
  'contractSize': contractSizeNumber,
6590
7789
  'markPrice': self.parse_number(markPrice),
6591
- 'lastPrice': self.safe_number(position, 'closeAvgPrice'),
7790
+ 'lastPrice': self.safe_number_2(position, 'closeAvgPrice', 'closePriceAvg'),
6592
7791
  'side': side,
6593
7792
  'hedged': hedged,
6594
7793
  'timestamp': timestamp,
6595
7794
  'datetime': self.iso8601(timestamp),
6596
- 'lastUpdateTimestamp': self.safe_integer(position, 'utime'),
7795
+ 'lastUpdateTimestamp': self.safe_integer_2(position, 'utime', 'updatedTime'),
6597
7796
  'maintenanceMargin': self.parse_number(maintenanceMargin),
6598
7797
  'maintenanceMarginPercentage': self.parse_number(maintenanceMarginPercentage),
6599
7798
  'collateral': self.parse_number(collateral),
6600
7799
  'initialMargin': self.parse_number(initialMargin),
6601
7800
  'initialMarginPercentage': self.parse_number(initialMarginPercentage),
6602
7801
  'leverage': self.parse_number(leverage),
6603
- 'marginRatio': self.safe_number(position, 'marginRatio'),
7802
+ 'marginRatio': self.safe_number_2(position, 'marginRatio', 'mmr'),
6604
7803
  'stopLossPrice': None,
6605
7804
  'takeProfitPrice': None,
6606
7805
  })
@@ -6610,54 +7809,82 @@ class bitget(Exchange, ImplicitAPI):
6610
7809
  fetches historical funding rate prices
6611
7810
 
6612
7811
  https://www.bitget.com/api-doc/contract/market/Get-History-Funding-Rate
7812
+ https://www.bitget.com/api-doc/uta/public/Get-History-Funding-Rate
6613
7813
 
6614
7814
  :param str symbol: unified symbol of the market to fetch the funding rate history for
6615
7815
  :param int [since]: timestamp in ms of the earliest funding rate to fetch
6616
7816
  :param int [limit]: the maximum amount of funding rate structures to fetch
6617
7817
  :param dict [params]: extra parameters specific to the exchange API endpoint
7818
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
6618
7819
  :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
6619
7820
  :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
6620
7821
  """
6621
7822
  if symbol is None:
6622
7823
  raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
6623
7824
  await self.load_markets()
6624
- paginate = False
6625
- paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
6626
- if paginate:
6627
- return await self.fetch_paginated_call_incremental('fetchFundingRateHistory', symbol, since, limit, params, 'pageNo', 100)
6628
7825
  market = self.market(symbol)
6629
- productType = None
6630
- productType, params = self.handle_product_type_and_params(market, params)
6631
7826
  request: dict = {
6632
7827
  'symbol': market['id'],
6633
- 'productType': productType,
6634
- # 'pageSize': limit, # default 20
6635
- # 'pageNo': 1,
6636
7828
  }
6637
- if limit is not None:
6638
- request['pageSize'] = limit
6639
- response = await self.publicMixGetV2MixMarketHistoryFundRate(self.extend(request, params))
6640
- #
6641
- # {
6642
- # "code": "00000",
6643
- # "msg": "success",
6644
- # "requestTime": 1652406728393,
6645
- # "data": [
6646
- # {
6647
- # "symbol": "BTCUSDT",
6648
- # "fundingRate": "-0.0003",
6649
- # "fundingTime": "1652396400000"
6650
- # },
6651
- # ]
6652
- # }
6653
- #
6654
- data = self.safe_value(response, 'data', [])
7829
+ productType = None
7830
+ uta = None
7831
+ response = None
7832
+ result = None
7833
+ productType, params = self.handle_product_type_and_params(market, params)
7834
+ uta, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'uta', False)
7835
+ if uta:
7836
+ if limit is not None:
7837
+ request['limit'] = limit
7838
+ request['category'] = productType
7839
+ response = await self.publicUtaGetV3MarketHistoryFundRate(self.extend(request, params))
7840
+ #
7841
+ # {
7842
+ # "code": "00000",
7843
+ # "msg": "success",
7844
+ # "requestTime": 1750435113658,
7845
+ # "data": {
7846
+ # "resultList": [
7847
+ # {
7848
+ # "symbol": "BTCUSDT",
7849
+ # "fundingRate": "-0.000017",
7850
+ # "fundingRateTimestamp": "1750431600000"
7851
+ # },
7852
+ # ]
7853
+ # }
7854
+ # }
7855
+ #
7856
+ data = self.safe_dict(response, 'data', {})
7857
+ result = self.safe_list(data, 'resultList', [])
7858
+ else:
7859
+ paginate = False
7860
+ paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
7861
+ if paginate:
7862
+ return await self.fetch_paginated_call_incremental('fetchFundingRateHistory', symbol, since, limit, params, 'pageNo', 100)
7863
+ if limit is not None:
7864
+ request['pageSize'] = limit
7865
+ request['productType'] = productType
7866
+ response = await self.publicMixGetV2MixMarketHistoryFundRate(self.extend(request, params))
7867
+ #
7868
+ # {
7869
+ # "code": "00000",
7870
+ # "msg": "success",
7871
+ # "requestTime": 1652406728393,
7872
+ # "data": [
7873
+ # {
7874
+ # "symbol": "BTCUSDT",
7875
+ # "fundingRate": "-0.0003",
7876
+ # "fundingTime": "1652396400000"
7877
+ # },
7878
+ # ]
7879
+ # }
7880
+ #
7881
+ result = self.safe_list(response, 'data', [])
6655
7882
  rates = []
6656
- for i in range(0, len(data)):
6657
- entry = data[i]
7883
+ for i in range(0, len(result)):
7884
+ entry = result[i]
6658
7885
  marketId = self.safe_string(entry, 'symbol')
6659
7886
  symbolInner = self.safe_symbol(marketId, market)
6660
- timestamp = self.safe_integer(entry, 'fundingTime')
7887
+ timestamp = self.safe_integer_2(entry, 'fundingTime', 'fundingRateTimestamp')
6661
7888
  rates.append({
6662
7889
  'info': entry,
6663
7890
  'symbol': symbolInner,
@@ -6674,9 +7901,11 @@ class bitget(Exchange, ImplicitAPI):
6674
7901
 
6675
7902
  https://www.bitget.com/api-doc/contract/market/Get-Current-Funding-Rate
6676
7903
  https://www.bitget.com/api-doc/contract/market/Get-Symbol-Next-Funding-Time
7904
+ https://www.bitget.com/api-doc/uta/public/Get-Current-Funding-Rate
6677
7905
 
6678
7906
  :param str symbol: unified market symbol
6679
7907
  :param dict [params]: extra parameters specific to the exchange API endpoint
7908
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
6680
7909
  :param str [params.method]: either(default) 'publicMixGetV2MixMarketCurrentFundRate' or 'publicMixGetV2MixMarketFundingTime'
6681
7910
  :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
6682
7911
  """
@@ -6688,46 +7917,68 @@ class bitget(Exchange, ImplicitAPI):
6688
7917
  productType, params = self.handle_product_type_and_params(market, params)
6689
7918
  request: dict = {
6690
7919
  'symbol': market['id'],
6691
- 'productType': productType,
6692
7920
  }
6693
- method = None
6694
- method, params = self.handle_option_and_params(params, 'fetchFundingRate', 'method', 'publicMixGetV2MixMarketCurrentFundRate')
7921
+ uta = None
6695
7922
  response = None
6696
- if method == 'publicMixGetV2MixMarketCurrentFundRate':
6697
- response = await self.publicMixGetV2MixMarketCurrentFundRate(self.extend(request, params))
7923
+ uta, params = self.handle_option_and_params(params, 'fetchFundingRate', 'uta', False)
7924
+ if uta:
7925
+ response = await self.publicUtaGetV3MarketCurrentFundRate(self.extend(request, params))
6698
7926
  #
6699
7927
  # {
6700
7928
  # "code": "00000",
6701
7929
  # "msg": "success",
6702
- # "requestTime": 1745500709429,
7930
+ # "requestTime": 1750897372153,
6703
7931
  # "data": [
6704
7932
  # {
6705
7933
  # "symbol": "BTCUSDT",
6706
- # "fundingRate": "-0.000013",
7934
+ # "fundingRate": "0.00001",
6707
7935
  # "fundingRateInterval": "8",
6708
- # "nextUpdate": "1745510400000",
7936
+ # "nextUpdate": "1750924800000",
6709
7937
  # "minFundingRate": "-0.003",
6710
7938
  # "maxFundingRate": "0.003"
6711
7939
  # }
6712
7940
  # ]
6713
7941
  # }
6714
7942
  #
6715
- elif method == 'publicMixGetV2MixMarketFundingTime':
6716
- response = await self.publicMixGetV2MixMarketFundingTime(self.extend(request, params))
6717
- #
6718
- # {
6719
- # "code": "00000",
6720
- # "msg": "success",
6721
- # "requestTime": 1745402092428,
6722
- # "data": [
6723
- # {
6724
- # "symbol": "BTCUSDT",
6725
- # "nextFundingTime": "1745424000000",
6726
- # "ratePeriod": "8"
6727
- # }
6728
- # ]
6729
- # }
6730
- #
7943
+ else:
7944
+ request['productType'] = productType
7945
+ method = None
7946
+ method, params = self.handle_option_and_params(params, 'fetchFundingRate', 'method', 'publicMixGetV2MixMarketCurrentFundRate')
7947
+ if method == 'publicMixGetV2MixMarketCurrentFundRate':
7948
+ response = await self.publicMixGetV2MixMarketCurrentFundRate(self.extend(request, params))
7949
+ #
7950
+ # {
7951
+ # "code": "00000",
7952
+ # "msg": "success",
7953
+ # "requestTime": 1745500709429,
7954
+ # "data": [
7955
+ # {
7956
+ # "symbol": "BTCUSDT",
7957
+ # "fundingRate": "-0.000013",
7958
+ # "fundingRateInterval": "8",
7959
+ # "nextUpdate": "1745510400000",
7960
+ # "minFundingRate": "-0.003",
7961
+ # "maxFundingRate": "0.003"
7962
+ # }
7963
+ # ]
7964
+ # }
7965
+ #
7966
+ elif method == 'publicMixGetV2MixMarketFundingTime':
7967
+ response = await self.publicMixGetV2MixMarketFundingTime(self.extend(request, params))
7968
+ #
7969
+ # {
7970
+ # "code": "00000",
7971
+ # "msg": "success",
7972
+ # "requestTime": 1745402092428,
7973
+ # "data": [
7974
+ # {
7975
+ # "symbol": "BTCUSDT",
7976
+ # "nextFundingTime": "1745424000000",
7977
+ # "ratePeriod": "8"
7978
+ # }
7979
+ # ]
7980
+ # }
7981
+ #
6731
7982
  data = self.safe_list(response, 'data', [])
6732
7983
  return self.parse_funding_rate(data[0], market)
6733
7984
 
@@ -6791,7 +8042,7 @@ class bitget(Exchange, ImplicitAPI):
6791
8042
 
6792
8043
  def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
6793
8044
  #
6794
- # fetchFundingRate: publicMixGetV2MixMarketCurrentFundRate
8045
+ # fetchFundingRate: publicMixGetV2MixMarketCurrentFundRate, publicUtaGetV3MarketCurrentFundRate
6795
8046
  #
6796
8047
  # {
6797
8048
  # "symbol": "BTCUSDT",
@@ -7137,11 +8388,14 @@ class bitget(Exchange, ImplicitAPI):
7137
8388
  set the level of leverage for a market
7138
8389
 
7139
8390
  https://www.bitget.com/api-doc/contract/account/Change-Leverage
8391
+ https://www.bitget.com/api-doc/uta/account/Change-Leverage
7140
8392
 
7141
8393
  :param int leverage: the rate of leverage
7142
8394
  :param str symbol: unified market symbol
7143
8395
  :param dict [params]: extra parameters specific to the exchange API endpoint
7144
8396
  :param str [params.holdSide]: *isolated only* position direction, 'long' or 'short'
8397
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
8398
+ :param boolean [params.posSide]: required for uta isolated margin, long or short
7145
8399
  :returns dict: response from the exchange
7146
8400
  """
7147
8401
  if symbol is None:
@@ -7152,27 +8406,47 @@ class bitget(Exchange, ImplicitAPI):
7152
8406
  productType, params = self.handle_product_type_and_params(market, params)
7153
8407
  request: dict = {
7154
8408
  'symbol': market['id'],
7155
- 'marginCoin': market['settleId'],
7156
8409
  'leverage': self.number_to_string(leverage),
7157
- 'productType': productType,
7158
- # 'holdSide': 'long',
7159
8410
  }
7160
- response = await self.privateMixPostV2MixAccountSetLeverage(self.extend(request, params))
7161
- #
7162
- # {
7163
- # "code": "00000",
7164
- # "msg": "success",
7165
- # "requestTime": 1700864711517,
7166
- # "data": {
7167
- # "symbol": "BTCUSDT",
7168
- # "marginCoin": "USDT",
7169
- # "longLeverage": "25",
7170
- # "shortLeverage": "25",
7171
- # "crossMarginLeverage": "25",
7172
- # "marginMode": "crossed"
7173
- # }
7174
- # }
7175
- #
8411
+ uta = None
8412
+ response = None
8413
+ uta, params = self.handle_option_and_params(params, 'setLeverage', 'uta', False)
8414
+ if uta:
8415
+ if productType == 'SPOT':
8416
+ marginMode = None
8417
+ marginMode, params = self.handle_margin_mode_and_params('fetchTrades', params)
8418
+ if marginMode is not None:
8419
+ productType = 'MARGIN'
8420
+ request['coin'] = market['settleId']
8421
+ request['category'] = productType
8422
+ response = await self.privateUtaPostV3AccountSetLeverage(self.extend(request, params))
8423
+ #
8424
+ # {
8425
+ # "code": "00000",
8426
+ # "msg": "success",
8427
+ # "requestTime": 1752815940833,
8428
+ # "data": "success"
8429
+ # }
8430
+ #
8431
+ else:
8432
+ request['marginCoin'] = market['settleId']
8433
+ request['productType'] = productType
8434
+ response = await self.privateMixPostV2MixAccountSetLeverage(self.extend(request, params))
8435
+ #
8436
+ # {
8437
+ # "code": "00000",
8438
+ # "msg": "success",
8439
+ # "requestTime": 1700864711517,
8440
+ # "data": {
8441
+ # "symbol": "BTCUSDT",
8442
+ # "marginCoin": "USDT",
8443
+ # "longLeverage": "25",
8444
+ # "shortLeverage": "25",
8445
+ # "crossMarginLeverage": "25",
8446
+ # "marginMode": "crossed"
8447
+ # }
8448
+ # }
8449
+ #
7176
8450
  return response
7177
8451
 
7178
8452
  async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
@@ -7225,35 +8499,51 @@ class bitget(Exchange, ImplicitAPI):
7225
8499
  set hedged to True or False for a market
7226
8500
 
7227
8501
  https://www.bitget.com/api-doc/contract/account/Change-Hold-Mode
8502
+ https://www.bitget.com/api-doc/uta/account/Change-Position-Mode
7228
8503
 
7229
8504
  :param bool hedged: set to True to use dualSidePosition
7230
8505
  :param str symbol: not used by bitget setPositionMode()
7231
8506
  :param dict [params]: extra parameters specific to the exchange API endpoint
7232
- :param str [params.productType]: required if symbol is None: 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
8507
+ :param str [params.productType]: required if not uta and symbol is None: 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
8508
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
7233
8509
  :returns dict: response from the exchange
7234
8510
  """
7235
8511
  await self.load_markets()
7236
8512
  posMode = 'hedge_mode' if hedged else 'one_way_mode'
8513
+ request: dict = {}
7237
8514
  market = None
7238
8515
  if symbol is not None:
7239
8516
  market = self.market(symbol)
7240
8517
  productType = None
8518
+ uta = None
8519
+ response = None
7241
8520
  productType, params = self.handle_product_type_and_params(market, params)
7242
- request: dict = {
7243
- 'posMode': posMode,
7244
- 'productType': productType,
7245
- }
7246
- response = await self.privateMixPostV2MixAccountSetPositionMode(self.extend(request, params))
7247
- #
7248
- # {
7249
- # "code": "00000",
7250
- # "msg": "success",
7251
- # "requestTime": 1700865608009,
7252
- # "data": {
7253
- # "posMode": "hedge_mode"
7254
- # }
7255
- # }
7256
- #
8521
+ uta, params = self.handle_option_and_params(params, 'setPositionMode', 'uta', False)
8522
+ if uta:
8523
+ request['holdMode'] = posMode
8524
+ response = await self.privateUtaPostV3AccountSetHoldMode(self.extend(request, params))
8525
+ #
8526
+ # {
8527
+ # "code": "00000",
8528
+ # "msg": "success",
8529
+ # "requestTime": 1752816734592,
8530
+ # "data": "success"
8531
+ # }
8532
+ #
8533
+ else:
8534
+ request['posMode'] = posMode
8535
+ request['productType'] = productType
8536
+ response = await self.privateMixPostV2MixAccountSetPositionMode(self.extend(request, params))
8537
+ #
8538
+ # {
8539
+ # "code": "00000",
8540
+ # "msg": "success",
8541
+ # "requestTime": 1700865608009,
8542
+ # "data": {
8543
+ # "posMode": "hedge_mode"
8544
+ # }
8545
+ # }
8546
+ #
7257
8547
  return response
7258
8548
 
7259
8549
  async def fetch_open_interest(self, symbol: str, params={}):
@@ -7261,9 +8551,11 @@ class bitget(Exchange, ImplicitAPI):
7261
8551
  retrieves the open interest of a contract trading pair
7262
8552
 
7263
8553
  https://www.bitget.com/api-doc/contract/market/Get-Open-Interest
8554
+ https://www.bitget.com/api-doc/uta/public/Get-Open-Interest
7264
8555
 
7265
8556
  :param str symbol: unified CCXT market symbol
7266
8557
  :param dict [params]: exchange specific parameters
8558
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
7267
8559
  :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
7268
8560
  """
7269
8561
  await self.load_markets()
@@ -7274,29 +8566,54 @@ class bitget(Exchange, ImplicitAPI):
7274
8566
  productType, params = self.handle_product_type_and_params(market, params)
7275
8567
  request: dict = {
7276
8568
  'symbol': market['id'],
7277
- 'productType': productType,
7278
8569
  }
7279
- response = await self.publicMixGetV2MixMarketOpenInterest(self.extend(request, params))
7280
- #
7281
- # {
7282
- # "code": "00000",
7283
- # "msg": "success",
7284
- # "requestTime": 1700866041022,
7285
- # "data": {
7286
- # "openInterestList": [
7287
- # {
7288
- # "symbol": "BTCUSDT",
7289
- # "size": "52234.134"
7290
- # }
7291
- # ],
7292
- # "ts": "1700866041023"
7293
- # }
7294
- # }
7295
- #
8570
+ uta = None
8571
+ response = None
8572
+ uta, params = self.handle_option_and_params(params, 'fetchOpenInterest', 'uta', False)
8573
+ if uta:
8574
+ request['category'] = productType
8575
+ response = await self.publicUtaGetV3MarketOpenInterest(self.extend(request, params))
8576
+ #
8577
+ # {
8578
+ # "code": "00000",
8579
+ # "msg": "success",
8580
+ # "requestTime": 1751101221545,
8581
+ # "data": {
8582
+ # "list": [
8583
+ # {
8584
+ # "symbol": "BTCUSDT",
8585
+ # "openInterest": "18166.3583"
8586
+ # }
8587
+ # ],
8588
+ # "ts": "1751101220993"
8589
+ # }
8590
+ # }
8591
+ #
8592
+ else:
8593
+ request['productType'] = productType
8594
+ response = await self.publicMixGetV2MixMarketOpenInterest(self.extend(request, params))
8595
+ #
8596
+ # {
8597
+ # "code": "00000",
8598
+ # "msg": "success",
8599
+ # "requestTime": 1700866041022,
8600
+ # "data": {
8601
+ # "openInterestList": [
8602
+ # {
8603
+ # "symbol": "BTCUSDT",
8604
+ # "size": "52234.134"
8605
+ # }
8606
+ # ],
8607
+ # "ts": "1700866041023"
8608
+ # }
8609
+ # }
8610
+ #
7296
8611
  data = self.safe_dict(response, 'data', {})
7297
8612
  return self.parse_open_interest(data, market)
7298
8613
 
7299
8614
  def parse_open_interest(self, interest, market: Market = None):
8615
+ #
8616
+ # default
7300
8617
  #
7301
8618
  # {
7302
8619
  # "openInterestList": [
@@ -7308,12 +8625,24 @@ class bitget(Exchange, ImplicitAPI):
7308
8625
  # "ts": "1700866041023"
7309
8626
  # }
7310
8627
  #
7311
- data = self.safe_value(interest, 'openInterestList', [])
8628
+ # uta
8629
+ #
8630
+ # {
8631
+ # "list": [
8632
+ # {
8633
+ # "symbol": "BTCUSDT",
8634
+ # "openInterest": "18166.3583"
8635
+ # }
8636
+ # ],
8637
+ # "ts": "1751101220993"
8638
+ # }
8639
+ #
8640
+ data = self.safe_list_2(interest, 'openInterestList', 'list', [])
7312
8641
  timestamp = self.safe_integer(interest, 'ts')
7313
8642
  marketId = self.safe_string(data[0], 'symbol')
7314
8643
  return self.safe_open_interest({
7315
8644
  'symbol': self.safe_symbol(marketId, market, None, 'contract'),
7316
- 'openInterestAmount': self.safe_number(data[0], 'size'),
8645
+ 'openInterestAmount': self.safe_number_2(data[0], 'size', 'openInterest'),
7317
8646
  'openInterestValue': None,
7318
8647
  'timestamp': timestamp,
7319
8648
  'datetime': self.iso8601(timestamp),
@@ -8036,10 +9365,11 @@ class bitget(Exchange, ImplicitAPI):
8036
9365
  fetch the rate of interest to borrow a currency for margin trading
8037
9366
 
8038
9367
  https://www.bitget.com/api-doc/margin/cross/account/Get-Cross-Margin-Interest-Rate-And-Borrowable
9368
+ https://www.bitget.com/api-doc/uta/public/Get-Margin-Loans
8039
9369
 
8040
9370
  :param str code: unified currency code
8041
9371
  :param dict [params]: extra parameters specific to the exchange API endpoint
8042
- :param str [params.symbol]: required for isolated margin
9372
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
8043
9373
  :returns dict: a `borrow rate structure <https://github.com/ccxt/ccxt/wiki/Manual#borrow-rate-structure>`
8044
9374
  """
8045
9375
  await self.load_markets()
@@ -8047,40 +9377,62 @@ class bitget(Exchange, ImplicitAPI):
8047
9377
  request: dict = {
8048
9378
  'coin': currency['id'],
8049
9379
  }
8050
- response = await self.privateMarginGetV2MarginCrossedInterestRateAndLimit(self.extend(request, params))
8051
- #
8052
- # {
8053
- # "code": "00000",
8054
- # "msg": "success",
8055
- # "requestTime": 1700879047861,
8056
- # "data": [
8057
- # {
8058
- # "coin": "BTC",
8059
- # "leverage": "3",
8060
- # "transferable": True,
8061
- # "borrowable": True,
8062
- # "dailyInterestRate": "0.00007",
8063
- # "annualInterestRate": "0.02555",
8064
- # "maxBorrowableAmount": "26",
8065
- # "vipList": [
8066
- # {"level":"0","limit":"26","dailyInterestRate":"0.00007","annualInterestRate":"0.02555","discountRate":"1"},
8067
- # {"level":"1","limit":"26.78","dailyInterestRate":"0.0000679","annualInterestRate":"0.0247835","discountRate":"0.97"},
8068
- # {"level":"2","limit":"28.08","dailyInterestRate":"0.0000644","annualInterestRate":"0.023506","discountRate":"0.92"},
8069
- # {"level":"3","limit":"30.16","dailyInterestRate":"0.0000602","annualInterestRate":"0.021973","discountRate":"0.86"},
8070
- # {"level":"4","limit":"34.58","dailyInterestRate":"0.0000525","annualInterestRate":"0.0191625","discountRate":"0.75"},
8071
- # {"level":"5","limit":"43.16","dailyInterestRate":"0.000042","annualInterestRate":"0.01533","discountRate":"0.6"}
8072
- # ]
8073
- # }
8074
- # ]
8075
- # }
8076
- #
9380
+ uta = None
9381
+ response = None
9382
+ result = None
9383
+ uta, params = self.handle_option_and_params(params, 'fetchCrossBorrowRate', 'uta', False)
9384
+ if uta:
9385
+ response = await self.publicUtaGetV3MarketMarginLoans(self.extend(request, params))
9386
+ #
9387
+ # {
9388
+ # "code": "00000",
9389
+ # "msg": "success",
9390
+ # "requestTime": 1752817798893,
9391
+ # "data": {
9392
+ # "dailyInterest": "0.00100008",
9393
+ # "annualInterest": "0.3650292",
9394
+ # "limit": "100"
9395
+ # }
9396
+ # }
9397
+ #
9398
+ result = self.safe_dict(response, 'data', {})
9399
+ else:
9400
+ response = await self.privateMarginGetV2MarginCrossedInterestRateAndLimit(self.extend(request, params))
9401
+ #
9402
+ # {
9403
+ # "code": "00000",
9404
+ # "msg": "success",
9405
+ # "requestTime": 1700879047861,
9406
+ # "data": [
9407
+ # {
9408
+ # "coin": "BTC",
9409
+ # "leverage": "3",
9410
+ # "transferable": True,
9411
+ # "borrowable": True,
9412
+ # "dailyInterestRate": "0.00007",
9413
+ # "annualInterestRate": "0.02555",
9414
+ # "maxBorrowableAmount": "26",
9415
+ # "vipList": [
9416
+ # {"level":"0","limit":"26","dailyInterestRate":"0.00007","annualInterestRate":"0.02555","discountRate":"1"},
9417
+ # {"level":"1","limit":"26.78","dailyInterestRate":"0.0000679","annualInterestRate":"0.0247835","discountRate":"0.97"},
9418
+ # {"level":"2","limit":"28.08","dailyInterestRate":"0.0000644","annualInterestRate":"0.023506","discountRate":"0.92"},
9419
+ # {"level":"3","limit":"30.16","dailyInterestRate":"0.0000602","annualInterestRate":"0.021973","discountRate":"0.86"},
9420
+ # {"level":"4","limit":"34.58","dailyInterestRate":"0.0000525","annualInterestRate":"0.0191625","discountRate":"0.75"},
9421
+ # {"level":"5","limit":"43.16","dailyInterestRate":"0.000042","annualInterestRate":"0.01533","discountRate":"0.6"}
9422
+ # ]
9423
+ # }
9424
+ # ]
9425
+ # }
9426
+ #
9427
+ data = self.safe_value(response, 'data', [])
9428
+ result = self.safe_value(data, 0, {})
8077
9429
  timestamp = self.safe_integer(response, 'requestTime')
8078
- data = self.safe_value(response, 'data', [])
8079
- first = self.safe_value(data, 0, {})
8080
- first['timestamp'] = timestamp
8081
- return self.parse_borrow_rate(first, currency)
9430
+ result['timestamp'] = timestamp
9431
+ return self.parse_borrow_rate(result, currency)
8082
9432
 
8083
9433
  def parse_borrow_rate(self, info, currency: Currency = None):
9434
+ #
9435
+ # default
8084
9436
  #
8085
9437
  # {
8086
9438
  # "coin": "BTC",
@@ -8100,11 +9452,19 @@ class bitget(Exchange, ImplicitAPI):
8100
9452
  # ]
8101
9453
  # }
8102
9454
  #
9455
+ # uta
9456
+ #
9457
+ # {
9458
+ # "dailyInterest": "0.00100008",
9459
+ # "annualInterest": "0.3650292",
9460
+ # "limit": "100"
9461
+ # }
9462
+ #
8103
9463
  currencyId = self.safe_string(info, 'coin')
8104
9464
  timestamp = self.safe_integer(info, 'timestamp')
8105
9465
  return {
8106
9466
  'currency': self.safe_currency_code(currencyId, currency),
8107
- 'rate': self.safe_number(info, 'dailyInterestRate'),
9467
+ 'rate': self.safe_number_2(info, 'dailyInterestRate', 'dailyInterest'),
8108
9468
  'period': 86400000, # 1-Day
8109
9469
  'timestamp': timestamp,
8110
9470
  'datetime': self.iso8601(timestamp),
@@ -8260,42 +9620,68 @@ class bitget(Exchange, ImplicitAPI):
8260
9620
  closes an open position for a market
8261
9621
 
8262
9622
  https://www.bitget.com/api-doc/contract/trade/Flash-Close-Position
9623
+ https://www.bitget.com/api-doc/uta/trade/Close-All-Positions
8263
9624
 
8264
9625
  :param str symbol: unified CCXT market symbol
8265
9626
  :param str [side]: one-way mode: 'buy' or 'sell', hedge-mode: 'long' or 'short'
8266
9627
  :param dict [params]: extra parameters specific to the exchange API endpoint
9628
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
8267
9629
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
8268
9630
  """
8269
9631
  await self.load_markets()
8270
9632
  market = self.market(symbol)
8271
- productType = None
8272
- productType, params = self.handle_product_type_and_params(market, params)
8273
9633
  request: dict = {
8274
9634
  'symbol': market['id'],
8275
- 'productType': productType,
8276
9635
  }
8277
- if side is not None:
8278
- request['holdSide'] = side
8279
- response = await self.privateMixPostV2MixOrderClosePositions(self.extend(request, params))
8280
- #
8281
- # {
8282
- # "code": "00000",
8283
- # "msg": "success",
8284
- # "requestTime": 1702975017017,
8285
- # "data": {
8286
- # "successList": [
8287
- # {
8288
- # "orderId": "1120923953904893955",
8289
- # "clientOid": "1120923953904893956"
8290
- # }
8291
- # ],
8292
- # "failureList": [],
8293
- # "result": False
8294
- # }
8295
- # }
8296
- #
9636
+ productType = None
9637
+ uta = None
9638
+ response = None
9639
+ productType, params = self.handle_product_type_and_params(market, params)
9640
+ uta, params = self.handle_option_and_params(params, 'closePosition', 'uta', False)
9641
+ if uta:
9642
+ if side is not None:
9643
+ request['posSide'] = side
9644
+ request['category'] = productType
9645
+ response = await self.privateUtaPostV3TradeClosePositions(self.extend(request, params))
9646
+ #
9647
+ # {
9648
+ # "code": "00000",
9649
+ # "msg": "success",
9650
+ # "requestTime": 1751020218384,
9651
+ # "data": {
9652
+ # "list": [
9653
+ # {
9654
+ # "orderId": "1322440134099320832",
9655
+ # "clientOid": "1322440134099320833"
9656
+ # }
9657
+ # ]
9658
+ # }
9659
+ # }
9660
+ #
9661
+ else:
9662
+ if side is not None:
9663
+ request['holdSide'] = side
9664
+ request['productType'] = productType
9665
+ response = await self.privateMixPostV2MixOrderClosePositions(self.extend(request, params))
9666
+ #
9667
+ # {
9668
+ # "code": "00000",
9669
+ # "msg": "success",
9670
+ # "requestTime": 1702975017017,
9671
+ # "data": {
9672
+ # "successList": [
9673
+ # {
9674
+ # "orderId": "1120923953904893955",
9675
+ # "clientOid": "1120923953904893956"
9676
+ # }
9677
+ # ],
9678
+ # "failureList": [],
9679
+ # "result": False
9680
+ # }
9681
+ # }
9682
+ #
8297
9683
  data = self.safe_value(response, 'data', {})
8298
- order = self.safe_list(data, 'successList', [])
9684
+ order = self.safe_list_2(data, 'successList', 'list', [])
8299
9685
  return self.parse_order(order[0], market)
8300
9686
 
8301
9687
  async def close_all_positions(self, params={}) -> List[Position]:
@@ -8303,37 +9689,60 @@ class bitget(Exchange, ImplicitAPI):
8303
9689
  closes all open positions for a market type
8304
9690
 
8305
9691
  https://www.bitget.com/api-doc/contract/trade/Flash-Close-Position
9692
+ https://www.bitget.com/api-doc/uta/trade/Close-All-Positions
8306
9693
 
8307
9694
  :param dict [params]: extra parameters specific to the exchange API endpoint
8308
9695
  :param str [params.productType]: 'USDT-FUTURES', 'USDC-FUTURES', 'COIN-FUTURES', 'SUSDT-FUTURES', 'SUSDC-FUTURES' or 'SCOIN-FUTURES'
9696
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
8309
9697
  :returns dict[]: A list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
8310
9698
  """
8311
9699
  await self.load_markets()
9700
+ request: dict = {}
8312
9701
  productType = None
9702
+ uta = None
9703
+ response = None
8313
9704
  productType, params = self.handle_product_type_and_params(None, params)
8314
- request: dict = {
8315
- 'productType': productType,
8316
- }
8317
- response = await self.privateMixPostV2MixOrderClosePositions(self.extend(request, params))
8318
- #
8319
- # {
8320
- # "code": "00000",
8321
- # "msg": "success",
8322
- # "requestTime": 1702975017017,
8323
- # "data": {
8324
- # "successList": [
8325
- # {
8326
- # "orderId": "1120923953904893955",
8327
- # "clientOid": "1120923953904893956"
8328
- # }
8329
- # ],
8330
- # "failureList": [],
8331
- # "result": False
8332
- # }
8333
- # }
8334
- #
9705
+ uta, params = self.handle_option_and_params(params, 'closeAllPositions', 'uta', False)
9706
+ if uta:
9707
+ request['category'] = productType
9708
+ response = await self.privateUtaPostV3TradeClosePositions(self.extend(request, params))
9709
+ #
9710
+ # {
9711
+ # "code": "00000",
9712
+ # "msg": "success",
9713
+ # "requestTime": 1751020218384,
9714
+ # "data": {
9715
+ # "list": [
9716
+ # {
9717
+ # "orderId": "1322440134099320832",
9718
+ # "clientOid": "1322440134099320833"
9719
+ # }
9720
+ # ]
9721
+ # }
9722
+ # }
9723
+ #
9724
+ else:
9725
+ request['productType'] = productType
9726
+ response = await self.privateMixPostV2MixOrderClosePositions(self.extend(request, params))
9727
+ #
9728
+ # {
9729
+ # "code": "00000",
9730
+ # "msg": "success",
9731
+ # "requestTime": 1702975017017,
9732
+ # "data": {
9733
+ # "successList": [
9734
+ # {
9735
+ # "orderId": "1120923953904893955",
9736
+ # "clientOid": "1120923953904893956"
9737
+ # }
9738
+ # ],
9739
+ # "failureList": [],
9740
+ # "result": False
9741
+ # }
9742
+ # }
9743
+ #
8335
9744
  data = self.safe_value(response, 'data', {})
8336
- orderInfo = self.safe_list(data, 'successList', [])
9745
+ orderInfo = self.safe_list_2(data, 'successList', 'list', [])
8337
9746
  return self.parse_positions(orderInfo, None, params)
8338
9747
 
8339
9748
  async def fetch_margin_mode(self, symbol: str, params={}) -> MarginMode:
@@ -8401,21 +9810,23 @@ class bitget(Exchange, ImplicitAPI):
8401
9810
  fetches historical positions
8402
9811
 
8403
9812
  https://www.bitget.com/api-doc/contract/position/Get-History-Position
9813
+ https://www.bitget.com/api-doc/uta/trade/Get-Position-History
8404
9814
 
8405
9815
  :param str[] [symbols]: unified contract symbols
8406
9816
  :param int [since]: timestamp in ms of the earliest position to fetch, default=3 months ago, max range for params["until"] - since is 3 months
8407
9817
  :param int [limit]: the maximum amount of records to fetch, default=20, max=100
8408
9818
  :param dict params: extra parameters specific to the exchange api endpoint
8409
9819
  :param int [params.until]: timestamp in ms of the latest position to fetch, max range for params["until"] - since is 3 months
8410
-
8411
- EXCHANGE SPECIFIC PARAMETERS
8412
9820
  :param str [params.productType]: USDT-FUTURES(default), COIN-FUTURES, USDC-FUTURES, SUSDT-FUTURES, SCOIN-FUTURES, or SUSDC-FUTURES
9821
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
8413
9822
  :returns dict[]: a list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
8414
9823
  """
8415
9824
  await self.load_markets()
8416
- until = self.safe_integer(params, 'until')
8417
- params = self.omit(params, 'until')
8418
9825
  request: dict = {}
9826
+ market = None
9827
+ productType = None
9828
+ uta = None
9829
+ response = None
8419
9830
  if symbols is not None:
8420
9831
  symbolsLength = len(symbols)
8421
9832
  if symbolsLength > 0:
@@ -8425,40 +9836,77 @@ class bitget(Exchange, ImplicitAPI):
8425
9836
  request['startTime'] = since
8426
9837
  if limit is not None:
8427
9838
  request['limit'] = limit
8428
- if until is not None:
8429
- request['endTime'] = until
8430
- response = await self.privateMixGetV2MixPositionHistoryPosition(self.extend(request, params))
8431
- #
8432
- # {
8433
- # code: '00000',
8434
- # msg: 'success',
8435
- # requestTime: '1712794148791',
8436
- # data: {
8437
- # list: [
8438
- # {
8439
- # symbol: 'XRPUSDT',
8440
- # marginCoin: 'USDT',
8441
- # holdSide: 'long',
8442
- # openAvgPrice: '0.64967',
8443
- # closeAvgPrice: '0.58799',
8444
- # marginMode: 'isolated',
8445
- # openTotalPos: '10',
8446
- # closeTotalPos: '10',
8447
- # pnl: '-0.62976205',
8448
- # netProfit: '-0.65356802',
8449
- # totalFunding: '-0.01638',
8450
- # openFee: '-0.00389802',
8451
- # closeFee: '-0.00352794',
8452
- # ctime: '1709590322199',
8453
- # utime: '1709667583395'
8454
- # },
8455
- # ...
8456
- # ]
8457
- # }
8458
- # }
8459
- #
8460
- data = self.safe_dict(response, 'data')
8461
- responseList = self.safe_list(data, 'list')
9839
+ request, params = self.handle_until_option('endTime', request, params)
9840
+ productType, params = self.handle_product_type_and_params(market, params)
9841
+ uta, params = self.handle_option_and_params(params, 'fetchPositionsHistory', 'uta', False)
9842
+ if uta:
9843
+ request['category'] = productType
9844
+ response = await self.privateUtaGetV3PositionHistoryPosition(self.extend(request, params))
9845
+ #
9846
+ # {
9847
+ # "code": "00000",
9848
+ # "msg": "success",
9849
+ # "requestTime": 1751020950427,
9850
+ # "data": {
9851
+ # "list": [
9852
+ # {
9853
+ # "positionId": "1322441328637100049",
9854
+ # "category": "USDT-FUTURES",
9855
+ # "symbol": "BTCUSDT",
9856
+ # "marginCoin": "USDT",
9857
+ # "holdMode": "hedge_mode",
9858
+ # "posSide": "long",
9859
+ # "marginMode": "crossed",
9860
+ # "openPriceAvg": "107003.7",
9861
+ # "closePriceAvg": "107005.4",
9862
+ # "openTotalPos": "0.0001",
9863
+ # "closeTotalPos": "0.0001",
9864
+ # "cumRealisedPnl": "0.00017",
9865
+ # "netProfit": "-0.01267055",
9866
+ # "totalFunding": "0",
9867
+ # "openFeeTotal": "-0.00642022",
9868
+ # "closeFeeTotal": "-0.00642032",
9869
+ # "createdTime": "1751020503195",
9870
+ # "updatedTime": "1751020520458"
9871
+ # },
9872
+ # ],
9873
+ # "cursor": "1322440134158041089"
9874
+ # }
9875
+ # }
9876
+ #
9877
+ else:
9878
+ response = await self.privateMixGetV2MixPositionHistoryPosition(self.extend(request, params))
9879
+ #
9880
+ # {
9881
+ # code: '00000',
9882
+ # msg: 'success',
9883
+ # requestTime: '1712794148791',
9884
+ # data: {
9885
+ # list: [
9886
+ # {
9887
+ # symbol: 'XRPUSDT',
9888
+ # marginCoin: 'USDT',
9889
+ # holdSide: 'long',
9890
+ # openAvgPrice: '0.64967',
9891
+ # closeAvgPrice: '0.58799',
9892
+ # marginMode: 'isolated',
9893
+ # openTotalPos: '10',
9894
+ # closeTotalPos: '10',
9895
+ # pnl: '-0.62976205',
9896
+ # netProfit: '-0.65356802',
9897
+ # totalFunding: '-0.01638',
9898
+ # openFee: '-0.00389802',
9899
+ # closeFee: '-0.00352794',
9900
+ # ctime: '1709590322199',
9901
+ # utime: '1709667583395'
9902
+ # },
9903
+ # ...
9904
+ # ]
9905
+ # }
9906
+ # }
9907
+ #
9908
+ data = self.safe_dict(response, 'data', {})
9909
+ responseList = self.safe_list(data, 'list', [])
8462
9910
  positions = self.parse_positions(responseList, symbols, params)
8463
9911
  return self.filter_by_since_limit(positions, since, limit)
8464
9912
 
@@ -8730,9 +10178,11 @@ class bitget(Exchange, ImplicitAPI):
8730
10178
  fetch the current funding rate interval
8731
10179
 
8732
10180
  https://www.bitget.com/api-doc/contract/market/Get-Symbol-Next-Funding-Time
10181
+ https://www.bitget.com/api-doc/uta/public/Get-Current-Funding-Rate
8733
10182
 
8734
10183
  :param str symbol: unified market symbol
8735
10184
  :param dict [params]: extra parameters specific to the exchange API endpoint
10185
+ :param boolean [params.uta]: set to True for the unified trading account(uta), defaults to False
8736
10186
  :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
8737
10187
  """
8738
10188
  await self.load_markets()
@@ -8741,23 +10191,46 @@ class bitget(Exchange, ImplicitAPI):
8741
10191
  productType, params = self.handle_product_type_and_params(market, params)
8742
10192
  request: dict = {
8743
10193
  'symbol': market['id'],
8744
- 'productType': productType,
8745
10194
  }
8746
- response = await self.publicMixGetV2MixMarketFundingTime(self.extend(request, params))
8747
- #
8748
- # {
8749
- # "code": "00000",
8750
- # "msg": "success",
8751
- # "requestTime": 1727930153888,
8752
- # "data": [
8753
- # {
8754
- # "symbol": "BTCUSDT",
8755
- # "nextFundingTime": "1727942400000",
8756
- # "ratePeriod": "8"
8757
- # }
8758
- # ]
8759
- # }
8760
- #
10195
+ response = None
10196
+ uta = None
10197
+ uta, params = self.handle_option_and_params(params, 'fetchFundingInterval', 'uta', False)
10198
+ if uta:
10199
+ response = await self.publicUtaGetV3MarketCurrentFundRate(self.extend(request, params))
10200
+ #
10201
+ # {
10202
+ # "code": "00000",
10203
+ # "msg": "success",
10204
+ # "requestTime": 1752880157959,
10205
+ # "data": [
10206
+ # {
10207
+ # "symbol": "BTCUSDT",
10208
+ # "fundingRate": "0.0001",
10209
+ # "fundingRateInterval": "8",
10210
+ # "nextUpdate": "1752883200000",
10211
+ # "minFundingRate": "-0.003",
10212
+ # "maxFundingRate": "0.003"
10213
+ # }
10214
+ # ]
10215
+ # }
10216
+ #
10217
+ else:
10218
+ request['productType'] = productType
10219
+ response = await self.publicMixGetV2MixMarketFundingTime(self.extend(request, params))
10220
+ #
10221
+ # {
10222
+ # "code": "00000",
10223
+ # "msg": "success",
10224
+ # "requestTime": 1727930153888,
10225
+ # "data": [
10226
+ # {
10227
+ # "symbol": "BTCUSDT",
10228
+ # "nextFundingTime": "1727942400000",
10229
+ # "ratePeriod": "8"
10230
+ # }
10231
+ # ]
10232
+ # }
10233
+ #
8761
10234
  data = self.safe_list(response, 'data', [])
8762
10235
  first = self.safe_dict(data, 0, {})
8763
10236
  return self.parse_funding_rate(first, market)
@@ -8917,7 +10390,7 @@ class bitget(Exchange, ImplicitAPI):
8917
10390
  if method == 'POST':
8918
10391
  headers['Content-Type'] = 'application/json'
8919
10392
  sandboxMode = self.safe_bool_2(self.options, 'sandboxMode', 'sandbox', False)
8920
- if sandboxMode and (path != 'v2/public/time'):
10393
+ if sandboxMode and (path != 'v2/public/time') and (path != 'v3/market/current-fund-rate'):
8921
10394
  # https://github.com/ccxt/ccxt/issues/25252#issuecomment-2662742336
8922
10395
  if headers is None:
8923
10396
  headers = {}