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