ccxt 4.4.40__py2.py3-none-any.whl → 4.4.41__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.40'
7
+ __version__ = '4.4.41'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -1940,6 +1940,7 @@ class Exchange(object):
1940
1940
  'fetchOHLCV': None,
1941
1941
  'fetchOHLCVWs': None,
1942
1942
  'fetchOpenInterest': None,
1943
+ 'fetchOpenInterests': None,
1943
1944
  'fetchOpenInterestHistory': None,
1944
1945
  'fetchOpenOrder': None,
1945
1946
  'fetchOpenOrders': None,
@@ -2691,6 +2692,9 @@ class Exchange(object):
2691
2692
  def fetch_open_interest(self, symbol: str, params={}):
2692
2693
  raise NotSupported(self.id + ' fetchOpenInterest() is not supported yet')
2693
2694
 
2695
+ def fetch_open_interests(self, symbols: Strings = None, params={}):
2696
+ raise NotSupported(self.id + ' fetchOpenInterests() is not supported yet')
2697
+
2694
2698
  def sign_in(self, params={}):
2695
2699
  raise NotSupported(self.id + ' signIn() is not supported yet')
2696
2700
 
@@ -5639,6 +5643,13 @@ class Exchange(object):
5639
5643
  result[parsed['symbol']] = parsed
5640
5644
  return result
5641
5645
 
5646
+ def parse_open_interests(self, response, market: Market = None):
5647
+ result = {}
5648
+ for i in range(0, len(response)):
5649
+ parsed = self.parse_open_interest(response[i], market)
5650
+ result[parsed['symbol']] = parsed
5651
+ return result
5652
+
5642
5653
  def parse_long_short_ratio(self, info: dict, market: Market = None):
5643
5654
  raise NotSupported(self.id + ' parseLongShortRatio() is not supported yet')
5644
5655
 
@@ -5733,7 +5744,7 @@ class Exchange(object):
5733
5744
  def parse_open_interest(self, interest, market: Market = None):
5734
5745
  raise NotSupported(self.id + ' parseOpenInterest() is not supported yet')
5735
5746
 
5736
- def parse_open_interests(self, response, market=None, since: Int = None, limit: Int = None):
5747
+ def parse_open_interests_history(self, response, market=None, since: Int = None, limit: Int = None):
5737
5748
  interests = []
5738
5749
  for i in range(0, len(response)):
5739
5750
  entry = response[i]
@@ -6029,7 +6040,7 @@ class Exchange(object):
6029
6040
  maxEntriesPerRequest = 1000 # default to 1000
6030
6041
  return [maxEntriesPerRequest, params]
6031
6042
 
6032
- def fetch_paginated_call_dynamic(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}, maxEntriesPerRequest: Int = None):
6043
+ def fetch_paginated_call_dynamic(self, method: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}, maxEntriesPerRequest: Int = None, removeRepeated=True):
6033
6044
  maxCalls = None
6034
6045
  maxCalls, params = self.handle_option_and_params(params, method, 'paginationCalls', 10)
6035
6046
  maxRetries = None
@@ -6037,6 +6048,8 @@ class Exchange(object):
6037
6048
  paginationDirection = None
6038
6049
  paginationDirection, params = self.handle_option_and_params(params, method, 'paginationDirection', 'backward')
6039
6050
  paginationTimestamp = None
6051
+ removeRepeatedOption = removeRepeated
6052
+ removeRepeatedOption, params = self.handle_option_and_params(params, method, 'removeRepeated', removeRepeated)
6040
6053
  calls = 0
6041
6054
  result = []
6042
6055
  errors = 0
@@ -6090,7 +6103,9 @@ class Exchange(object):
6090
6103
  errors += 1
6091
6104
  if errors > maxRetries:
6092
6105
  raise e
6093
- uniqueResults = self.remove_repeated_elements_from_array(result)
6106
+ uniqueResults = result
6107
+ if removeRepeatedOption:
6108
+ uniqueResults = self.remove_repeated_elements_from_array(result)
6094
6109
  key = 0 if (method == 'fetchOHLCV') else 'timestamp'
6095
6110
  return self.filter_by_since_limit(uniqueResults, since, limit, key)
6096
6111
 
ccxt/base/types.py CHANGED
@@ -496,6 +496,15 @@ class FundingRate(TypedDict):
496
496
  info: Dict[str, Any]
497
497
  interval: Str
498
498
 
499
+ class OpenInterest(TypedDict):
500
+ symbol: Str
501
+ openInterestAmount: Num
502
+ openInterestValue: Num
503
+ baseVolume: Num
504
+ quoteVolume: Num
505
+ timestamp: Int
506
+ datetime: Str
507
+ info: Dict[str, Any]
499
508
 
500
509
  class LeverageTier:
501
510
  tier: Num
@@ -556,6 +565,7 @@ class BorrowInterest:
556
565
 
557
566
 
558
567
  FundingRates = Dict[Str, FundingRate]
568
+ OpenInterests = Dict[Str, OpenInterest]
559
569
  LastPrices = Dict[Str, LastPrice]
560
570
  Currencies = Dict[Str, CurrencyInterface]
561
571
  TradingFees = Dict[Str, TradingFeeInterface]
ccxt/binance.py CHANGED
@@ -5062,8 +5062,8 @@ class binance(Exchange, ImplicitAPI):
5062
5062
  if postOnly:
5063
5063
  uppercaseType = 'LIMIT_MAKER'
5064
5064
  request['type'] = uppercaseType
5065
- stopPrice = self.safe_number_2(params, 'stopPrice', 'triggerPrice')
5066
- if stopPrice is not None:
5065
+ triggerPrice = self.safe_number_2(params, 'stopPrice', 'triggerPrice')
5066
+ if triggerPrice is not None:
5067
5067
  if uppercaseType == 'MARKET':
5068
5068
  uppercaseType = 'STOP_LOSS'
5069
5069
  elif uppercaseType == 'LIMIT':
@@ -5071,7 +5071,7 @@ class binance(Exchange, ImplicitAPI):
5071
5071
  validOrderTypes = self.safe_list(market['info'], 'orderTypes')
5072
5072
  if not self.in_array(uppercaseType, validOrderTypes):
5073
5073
  if initialUppercaseType != uppercaseType:
5074
- raise InvalidOrder(self.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders')
5074
+ raise InvalidOrder(self.id + ' triggerPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders')
5075
5075
  else:
5076
5076
  raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market')
5077
5077
  if clientOrderId is None:
@@ -5085,7 +5085,7 @@ class binance(Exchange, ImplicitAPI):
5085
5085
  request['newOrderRespType'] = self.safe_value(self.options['newOrderRespType'], type, 'RESULT') # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
5086
5086
  timeInForceIsRequired = False
5087
5087
  priceIsRequired = False
5088
- stopPriceIsRequired = False
5088
+ triggerPriceIsRequired = False
5089
5089
  quantityIsRequired = False
5090
5090
  if uppercaseType == 'MARKET':
5091
5091
  quoteOrderQty = self.safe_bool(self.options, 'quoteOrderQty', True)
@@ -5108,11 +5108,11 @@ class binance(Exchange, ImplicitAPI):
5108
5108
  timeInForceIsRequired = True
5109
5109
  quantityIsRequired = True
5110
5110
  elif (uppercaseType == 'STOP_LOSS') or (uppercaseType == 'TAKE_PROFIT'):
5111
- stopPriceIsRequired = True
5111
+ triggerPriceIsRequired = True
5112
5112
  quantityIsRequired = True
5113
5113
  elif (uppercaseType == 'STOP_LOSS_LIMIT') or (uppercaseType == 'TAKE_PROFIT_LIMIT'):
5114
5114
  quantityIsRequired = True
5115
- stopPriceIsRequired = True
5115
+ triggerPriceIsRequired = True
5116
5116
  priceIsRequired = True
5117
5117
  timeInForceIsRequired = True
5118
5118
  elif uppercaseType == 'LIMIT_MAKER':
@@ -5126,11 +5126,11 @@ class binance(Exchange, ImplicitAPI):
5126
5126
  request['price'] = self.price_to_precision(symbol, price)
5127
5127
  if timeInForceIsRequired and (self.safe_string(params, 'timeInForce') is None):
5128
5128
  request['timeInForce'] = self.options['defaultTimeInForce'] # 'GTC' = Good To Cancel(default), 'IOC' = Immediate Or Cancel
5129
- if stopPriceIsRequired:
5130
- if stopPrice is None:
5131
- raise InvalidOrder(self.id + ' editOrder() requires a stopPrice extra param for a ' + type + ' order')
5129
+ if triggerPriceIsRequired:
5130
+ if triggerPrice is None:
5131
+ raise InvalidOrder(self.id + ' editOrder() requires a triggerPrice extra param for a ' + type + ' order')
5132
5132
  else:
5133
- request['stopPrice'] = self.price_to_precision(symbol, stopPrice)
5133
+ request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
5134
5134
  request['cancelReplaceMode'] = 'STOP_ON_FAILURE' # If the cancel request fails, the new order placement will not be attempted.
5135
5135
  cancelId = self.safe_string_2(params, 'cancelNewClientOrderId', 'cancelOrigClientOrderId')
5136
5136
  if cancelId is None:
@@ -5775,7 +5775,7 @@ class binance(Exchange, ImplicitAPI):
5775
5775
  if type == 'limit_maker':
5776
5776
  type = 'limit'
5777
5777
  stopPriceString = self.safe_string(order, 'stopPrice')
5778
- stopPrice = self.parse_number(self.omit_zero(stopPriceString))
5778
+ triggerPrice = self.parse_number(self.omit_zero(stopPriceString))
5779
5779
  feeCost = self.safe_number(order, 'fee')
5780
5780
  fee = None
5781
5781
  if feeCost is not None:
@@ -5799,7 +5799,7 @@ class binance(Exchange, ImplicitAPI):
5799
5799
  'reduceOnly': self.safe_bool(order, 'reduceOnly'),
5800
5800
  'side': side,
5801
5801
  'price': price,
5802
- 'triggerPrice': stopPrice,
5802
+ 'triggerPrice': triggerPrice,
5803
5803
  'amount': amount,
5804
5804
  'cost': cost,
5805
5805
  'average': average,
@@ -6071,7 +6071,7 @@ class binance(Exchange, ImplicitAPI):
6071
6071
  validOrderTypes = self.safe_list(market['info'], 'orderTypes')
6072
6072
  if not self.in_array(uppercaseType, validOrderTypes):
6073
6073
  if initialUppercaseType != uppercaseType:
6074
- raise InvalidOrder(self.id + ' stopPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders')
6074
+ raise InvalidOrder(self.id + ' triggerPrice parameter is not allowed for ' + symbol + ' ' + type + ' orders')
6075
6075
  else:
6076
6076
  raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type for the ' + symbol + ' market')
6077
6077
  clientOrderIdRequest = 'newClientStrategyId' if isPortfolioMarginConditional else 'newClientOrderId'
@@ -6110,7 +6110,7 @@ class binance(Exchange, ImplicitAPI):
6110
6110
  closePosition = self.safe_bool(params, 'closePosition', False)
6111
6111
  timeInForceIsRequired = False
6112
6112
  priceIsRequired = False
6113
- stopPriceIsRequired = False
6113
+ triggerPriceIsRequired = False
6114
6114
  quantityIsRequired = False
6115
6115
  #
6116
6116
  # spot/margin
@@ -6156,13 +6156,13 @@ class binance(Exchange, ImplicitAPI):
6156
6156
  timeInForceIsRequired = True
6157
6157
  quantityIsRequired = True
6158
6158
  elif (uppercaseType == 'STOP_LOSS') or (uppercaseType == 'TAKE_PROFIT'):
6159
- stopPriceIsRequired = True
6159
+ triggerPriceIsRequired = True
6160
6160
  quantityIsRequired = True
6161
6161
  if market['linear'] or market['inverse']:
6162
6162
  priceIsRequired = True
6163
6163
  elif (uppercaseType == 'STOP_LOSS_LIMIT') or (uppercaseType == 'TAKE_PROFIT_LIMIT'):
6164
6164
  quantityIsRequired = True
6165
- stopPriceIsRequired = True
6165
+ triggerPriceIsRequired = True
6166
6166
  priceIsRequired = True
6167
6167
  timeInForceIsRequired = True
6168
6168
  elif uppercaseType == 'LIMIT_MAKER':
@@ -6170,12 +6170,12 @@ class binance(Exchange, ImplicitAPI):
6170
6170
  quantityIsRequired = True
6171
6171
  elif uppercaseType == 'STOP':
6172
6172
  quantityIsRequired = True
6173
- stopPriceIsRequired = True
6173
+ triggerPriceIsRequired = True
6174
6174
  priceIsRequired = True
6175
6175
  elif (uppercaseType == 'STOP_MARKET') or (uppercaseType == 'TAKE_PROFIT_MARKET'):
6176
6176
  if not closePosition:
6177
6177
  quantityIsRequired = True
6178
- stopPriceIsRequired = True
6178
+ triggerPriceIsRequired = True
6179
6179
  elif uppercaseType == 'TRAILING_STOP_MARKET':
6180
6180
  if not closePosition:
6181
6181
  quantityIsRequired = True
@@ -6201,14 +6201,14 @@ class binance(Exchange, ImplicitAPI):
6201
6201
  request['price'] = self.price_to_precision(symbol, price)
6202
6202
  else:
6203
6203
  request['price'] = self.parse_to_numeric(price) # some options don't have the precision available
6204
- if stopPriceIsRequired:
6204
+ if triggerPriceIsRequired:
6205
6205
  if market['contract']:
6206
6206
  if stopPrice is None:
6207
- raise InvalidOrder(self.id + ' createOrder() requires a stopPrice extra param for a ' + type + ' order')
6207
+ raise InvalidOrder(self.id + ' createOrder() requires a triggerPrice extra param for a ' + type + ' order')
6208
6208
  else:
6209
6209
  # check for delta price
6210
6210
  if trailingDelta is None and stopPrice is None and trailingPercent is None:
6211
- raise InvalidOrder(self.id + ' createOrder() requires a stopPrice, trailingDelta or trailingPercent param for a ' + type + ' order')
6211
+ raise InvalidOrder(self.id + ' createOrder() requires a triggerPrice, trailingDelta or trailingPercent param for a ' + type + ' order')
6212
6212
  if stopPrice is not None:
6213
6213
  request['stopPrice'] = self.price_to_precision(symbol, stopPrice)
6214
6214
  if timeInForceIsRequired and (self.safe_string(params, 'timeInForce') is None) and (self.safe_string(request, 'timeInForce') is None):
@@ -10887,7 +10887,7 @@ class binance(Exchange, ImplicitAPI):
10887
10887
  paginate = False
10888
10888
  paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
10889
10889
  if paginate:
10890
- return self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params)
10890
+ return self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params, None, False)
10891
10891
  type = None
10892
10892
  subType = None
10893
10893
  currency = None
@@ -11962,7 +11962,7 @@ class binance(Exchange, ImplicitAPI):
11962
11962
  # ...
11963
11963
  # ]
11964
11964
  #
11965
- return self.parse_open_interests(response, market, since, limit)
11965
+ return self.parse_open_interests_history(response, market, since, limit)
11966
11966
 
11967
11967
  def fetch_open_interest(self, symbol: str, params={}):
11968
11968
  """
@@ -12025,7 +12025,7 @@ class binance(Exchange, ImplicitAPI):
12025
12025
  #
12026
12026
  if market['option']:
12027
12027
  symbol = market['symbol']
12028
- result = self.parse_open_interests(response, market)
12028
+ result = self.parse_open_interests_history(response, market)
12029
12029
  for i in range(0, len(result)):
12030
12030
  item = result[i]
12031
12031
  if item['symbol'] == symbol:
ccxt/bingx.py CHANGED
@@ -63,6 +63,7 @@ class bingx(Exchange, ImplicitAPI):
63
63
  'createTrailingAmountOrder': True,
64
64
  'createTrailingPercentOrder': True,
65
65
  'createTriggerOrder': True,
66
+ 'editOrder': True,
66
67
  'fetchBalance': True,
67
68
  'fetchCanceledOrders': True,
68
69
  'fetchClosedOrders': True,
@@ -85,6 +86,7 @@ class bingx(Exchange, ImplicitAPI):
85
86
  'fetchMarkPrice': True,
86
87
  'fetchMarkPrices': True,
87
88
  'fetchMyLiquidations': True,
89
+ 'fetchMyTrades': True,
88
90
  'fetchOHLCV': True,
89
91
  'fetchOpenInterest': True,
90
92
  'fetchOpenOrders': True,
@@ -1036,7 +1038,7 @@ class bingx(Exchange, ImplicitAPI):
1036
1038
  }
1037
1039
  request['interval'] = self.safe_string(self.timeframes, timeframe, timeframe)
1038
1040
  if since is not None:
1039
- request['startTime'] = since
1041
+ request['startTime'] = max(since - 1, 0)
1040
1042
  if limit is not None:
1041
1043
  request['limit'] = limit
1042
1044
  until = self.safe_integer_2(params, 'until', 'endTime')
ccxt/bitfinex.py CHANGED
@@ -3224,7 +3224,7 @@ class bitfinex(Exchange, ImplicitAPI):
3224
3224
  # ],
3225
3225
  # ]
3226
3226
  #
3227
- return self.parse_open_interests(response, market, since, limit)
3227
+ return self.parse_open_interests_history(response, market, since, limit)
3228
3228
 
3229
3229
  def parse_open_interest(self, interest, market: Market = None):
3230
3230
  #
ccxt/bitget.py CHANGED
@@ -1264,6 +1264,7 @@ class bitget(Exchange, ImplicitAPI):
1264
1264
  '41103': InvalidOrder, # {"code":"41103","msg":"param price scale error error","requestTime":1725635883561,"data":null}
1265
1265
  '41114': OnMaintenance, # {"code":"41114","msg":"The current trading pair is under maintenance, please refer to the official announcement for the opening time","requestTime":1679196062544,"data":null}
1266
1266
  '43011': InvalidOrder, # The parameter does not meet the specification executePrice <= 0
1267
+ '43001': OrderNotFound,
1267
1268
  '43012': InsufficientFunds, # {"code":"43012","msg":"Insufficient balance","requestTime":1711648951774,"data":null}
1268
1269
  '43025': InvalidOrder, # Plan order does not exist
1269
1270
  '43115': OnMaintenance, # {"code":"43115","msg":"The current trading pair is opening soon, please refer to the official announcement for the opening time","requestTime":1688907202434,"data":null}
ccxt/bitmart.py CHANGED
@@ -6,7 +6,7 @@
6
6
  from ccxt.base.exchange import Exchange
7
7
  from ccxt.abstract.bitmart import ImplicitAPI
8
8
  import hashlib
9
- from ccxt.base.types import Balances, BorrowInterest, Currencies, Currency, DepositAddress, Int, IsolatedBorrowRate, IsolatedBorrowRates, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, Trade, TradingFeeInterface, Transaction, TransferEntry
9
+ from ccxt.base.types import Balances, BorrowInterest, Currencies, Currency, DepositAddress, FundingHistory, Int, IsolatedBorrowRate, IsolatedBorrowRates, LedgerEntry, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, Trade, TradingFeeInterface, Transaction, TransferEntry
10
10
  from typing import List
11
11
  from ccxt.base.errors import ExchangeError
12
12
  from ccxt.base.errors import AuthenticationError
@@ -81,12 +81,13 @@ class bitmart(Exchange, ImplicitAPI):
81
81
  'fetchDeposits': True,
82
82
  'fetchDepositWithdrawFee': True,
83
83
  'fetchDepositWithdrawFees': False,
84
- 'fetchFundingHistory': None,
84
+ 'fetchFundingHistory': True,
85
85
  'fetchFundingRate': True,
86
86
  'fetchFundingRateHistory': False,
87
87
  'fetchFundingRates': False,
88
88
  'fetchIsolatedBorrowRate': True,
89
89
  'fetchIsolatedBorrowRates': True,
90
+ 'fetchLedger': True,
90
91
  'fetchLiquidations': False,
91
92
  'fetchMarginMode': False,
92
93
  'fetchMarkets': True,
@@ -173,6 +174,7 @@ class bitmart(Exchange, ImplicitAPI):
173
174
  'contract/public/depth': 5,
174
175
  'contract/public/open-interest': 30,
175
176
  'contract/public/funding-rate': 30,
177
+ 'contract/public/funding-rate-history': 30,
176
178
  'contract/public/kline': 6, # should be 5 but errors
177
179
  'account/v1/currencies': 30,
178
180
  },
@@ -223,6 +225,7 @@ class bitmart(Exchange, ImplicitAPI):
223
225
  'contract/private/position-risk': 10,
224
226
  'contract/private/affilate/rebate-list': 10,
225
227
  'contract/private/affilate/trade-list': 10,
228
+ 'contract/private/transaction-history': 10,
226
229
  },
227
230
  'post': {
228
231
  # sub-account endpoints
@@ -4375,6 +4378,62 @@ class bitmart(Exchange, ImplicitAPI):
4375
4378
  data = self.safe_dict(response, 'data', {})
4376
4379
  return self.parse_funding_rate(data, market)
4377
4380
 
4381
+ def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4382
+ """
4383
+ fetches historical funding rate prices
4384
+
4385
+ https://developer-pro.bitmart.com/en/futuresv2/#get-funding-rate-history
4386
+
4387
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
4388
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
4389
+ :param int [limit]: the maximum amount of funding rate structures to fetch
4390
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4391
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
4392
+ """
4393
+ if symbol is None:
4394
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
4395
+ self.load_markets()
4396
+ market = self.market(symbol)
4397
+ request: dict = {
4398
+ 'symbol': market['id'],
4399
+ }
4400
+ if limit is not None:
4401
+ request['limit'] = limit
4402
+ response = self.publicGetContractPublicFundingRateHistory(self.extend(request, params))
4403
+ #
4404
+ # {
4405
+ # "code": 1000,
4406
+ # "message": "Ok",
4407
+ # "data": {
4408
+ # "list": [
4409
+ # {
4410
+ # "symbol": "BTCUSDT",
4411
+ # "funding_rate": "0.000091412174",
4412
+ # "funding_time": "1734336000000"
4413
+ # },
4414
+ # ]
4415
+ # },
4416
+ # "trace": "fg73d949fgfdf6a40c8fc7f5ae6738.54.345345345345"
4417
+ # }
4418
+ #
4419
+ data = self.safe_dict(response, 'data', {})
4420
+ result = self.safe_list(data, 'list', [])
4421
+ rates = []
4422
+ for i in range(0, len(result)):
4423
+ entry = result[i]
4424
+ marketId = self.safe_string(entry, 'symbol')
4425
+ symbolInner = self.safe_symbol(marketId, market, '-', 'swap')
4426
+ timestamp = self.safe_integer(entry, 'funding_time')
4427
+ rates.append({
4428
+ 'info': entry,
4429
+ 'symbol': symbolInner,
4430
+ 'fundingRate': self.safe_number(entry, 'funding_rate'),
4431
+ 'timestamp': timestamp,
4432
+ 'datetime': self.iso8601(timestamp),
4433
+ })
4434
+ sorted = self.sort_by(rates, 'timestamp')
4435
+ return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
4436
+
4378
4437
  def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
4379
4438
  #
4380
4439
  # {
@@ -4788,6 +4847,188 @@ class bitmart(Exchange, ImplicitAPI):
4788
4847
  data = self.safe_dict(response, 'data', {})
4789
4848
  return self.parse_order(data, market)
4790
4849
 
4850
+ def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
4851
+ """
4852
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
4853
+
4854
+ https://developer-pro.bitmart.com/en/futuresv2/#get-transaction-history-keyed
4855
+
4856
+ :param str [code]: unified currency code
4857
+ :param int [since]: timestamp in ms of the earliest ledger entry
4858
+ :param int [limit]: max number of ledger entries to return
4859
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4860
+ :param int [params.until]: timestamp in ms of the latest ledger entry
4861
+ :returns dict[]: a list of `ledger structures <https://docs.ccxt.com/#/?id=ledger>`
4862
+ """
4863
+ self.load_markets()
4864
+ currency = None
4865
+ if code is not None:
4866
+ currency = self.currency(code)
4867
+ request: dict = {}
4868
+ request, params = self.handle_until_option('end_time', request, params)
4869
+ transactionsRequest = self.fetch_transactions_request(0, None, since, limit, params)
4870
+ response = self.privateGetContractPrivateTransactionHistory(transactionsRequest)
4871
+ #
4872
+ # {
4873
+ # "code": 1000,
4874
+ # "message": "Ok",
4875
+ # "data": [
4876
+ # {
4877
+ # "time": "1734422402121",
4878
+ # "type": "Funding Fee",
4879
+ # "amount": "-0.00008253",
4880
+ # "asset": "USDT",
4881
+ # "symbol": "LTCUSDT",
4882
+ # "tran_id": "1734422402121",
4883
+ # "flow_type": 3
4884
+ # },
4885
+ # ],
4886
+ # "trace": "4cd11f83c71egfhfgh842790f07241e.23.173442343427772866"
4887
+ # }
4888
+ #
4889
+ data = self.safe_list(response, 'data', [])
4890
+ return self.parse_ledger(data, currency, since, limit)
4891
+
4892
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
4893
+ #
4894
+ # {
4895
+ # "time": "1734422402121",
4896
+ # "type": "Funding Fee",
4897
+ # "amount": "-0.00008253",
4898
+ # "asset": "USDT",
4899
+ # "symbol": "LTCUSDT",
4900
+ # "tran_id": "1734422402121",
4901
+ # "flow_type": 3
4902
+ # }
4903
+ #
4904
+ amount = self.safe_string(item, 'amount')
4905
+ direction = None
4906
+ if Precise.string_le(amount, '0'):
4907
+ direction = 'out'
4908
+ amount = Precise.string_mul('-1', amount)
4909
+ else:
4910
+ direction = 'in'
4911
+ currencyId = self.safe_string(item, 'asset')
4912
+ timestamp = self.safe_integer(item, 'time')
4913
+ type = self.safe_string(item, 'type')
4914
+ return self.safe_ledger_entry({
4915
+ 'info': item,
4916
+ 'id': self.safe_string(item, 'tran_id'),
4917
+ 'direction': direction,
4918
+ 'account': None,
4919
+ 'referenceAccount': None,
4920
+ 'referenceId': self.safe_string(item, 'tradeId'),
4921
+ 'type': self.parse_ledger_entry_type(type),
4922
+ 'currency': self.safe_currency_code(currencyId, currency),
4923
+ 'amount': self.parse_number(amount),
4924
+ 'timestamp': timestamp,
4925
+ 'datetime': self.iso8601(timestamp),
4926
+ 'before': None,
4927
+ 'after': None,
4928
+ 'status': None,
4929
+ 'fee': None,
4930
+ }, currency)
4931
+
4932
+ def parse_ledger_entry_type(self, type):
4933
+ ledgerType: dict = {
4934
+ 'Commission Fee': 'fee',
4935
+ 'Funding Fee': 'fee',
4936
+ 'Realized PNL': 'trade',
4937
+ 'Transfer': 'transfer',
4938
+ 'Liquidation Clearance': 'settlement',
4939
+ }
4940
+ return self.safe_string(ledgerType, type, type)
4941
+
4942
+ def fetch_transactions_request(self, flowType: Int = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4943
+ request: dict = {}
4944
+ if flowType is not None:
4945
+ request['flow_type'] = flowType
4946
+ market = None
4947
+ if symbol is not None:
4948
+ market = self.market(symbol)
4949
+ request['symbol'] = market['id']
4950
+ if since is not None:
4951
+ request['start_time'] = since
4952
+ if limit is not None:
4953
+ request['page_size'] = limit
4954
+ request, params = self.handle_until_option('end_time', request, params)
4955
+ return self.extend(request, params)
4956
+
4957
+ def fetch_funding_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[FundingHistory]:
4958
+ """
4959
+ fetch the history of funding payments paid and received on self account
4960
+
4961
+ https://developer-pro.bitmart.com/en/futuresv2/#get-transaction-history-keyed
4962
+
4963
+ :param str [symbol]: unified market symbol
4964
+ :param int [since]: the starting timestamp in milliseconds
4965
+ :param int [limit]: the number of entries to return
4966
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4967
+ :param int [params.until]: the latest time in ms to fetch funding history for
4968
+ :returns dict[]: a list of `funding history structures <https://docs.ccxt.com/#/?id=funding-history-structure>`
4969
+ """
4970
+ self.load_markets()
4971
+ market = None
4972
+ if symbol is not None:
4973
+ market = self.market(symbol)
4974
+ request: dict = {}
4975
+ request, params = self.handle_until_option('end_time', request, params)
4976
+ transactionsRequest = self.fetch_transactions_request(3, symbol, since, limit, params)
4977
+ response = self.privateGetContractPrivateTransactionHistory(transactionsRequest)
4978
+ #
4979
+ # {
4980
+ # "code": 1000,
4981
+ # "message": "Ok",
4982
+ # "data": [
4983
+ # {
4984
+ # "time": "1734422402121",
4985
+ # "type": "Funding Fee",
4986
+ # "amount": "-0.00008253",
4987
+ # "asset": "USDT",
4988
+ # "symbol": "LTCUSDT",
4989
+ # "tran_id": "1734422402121",
4990
+ # "flow_type": 3
4991
+ # },
4992
+ # ],
4993
+ # "trace": "4cd11f83c71egfhfgh842790f07241e.23.173442343427772866"
4994
+ # }
4995
+ #
4996
+ data = self.safe_list(response, 'data', [])
4997
+ return self.parse_funding_histories(data, market, since, limit)
4998
+
4999
+ def parse_funding_history(self, contract, market: Market = None):
5000
+ #
5001
+ # {
5002
+ # "time": "1734422402121",
5003
+ # "type": "Funding Fee",
5004
+ # "amount": "-0.00008253",
5005
+ # "asset": "USDT",
5006
+ # "symbol": "LTCUSDT",
5007
+ # "tran_id": "1734422402121",
5008
+ # "flow_type": 3
5009
+ # }
5010
+ #
5011
+ marketId = self.safe_string(contract, 'symbol')
5012
+ currencyId = self.safe_string(contract, 'asset')
5013
+ timestamp = self.safe_integer(contract, 'time')
5014
+ return {
5015
+ 'info': contract,
5016
+ 'symbol': self.safe_symbol(marketId, market, None, 'swap'),
5017
+ 'code': self.safe_currency_code(currencyId),
5018
+ 'timestamp': timestamp,
5019
+ 'datetime': self.iso8601(timestamp),
5020
+ 'id': self.safe_string(contract, 'tran_id'),
5021
+ 'amount': self.safe_number(contract, 'amount'),
5022
+ }
5023
+
5024
+ def parse_funding_histories(self, contracts, market=None, since: Int = None, limit: Int = None) -> List[FundingHistory]:
5025
+ result = []
5026
+ for i in range(0, len(contracts)):
5027
+ contract = contracts[i]
5028
+ result.append(self.parse_funding_history(contract, market))
5029
+ sorted = self.sort_by(result, 'timestamp')
5030
+ return self.filter_by_since_limit(sorted, since, limit)
5031
+
4791
5032
  def nonce(self):
4792
5033
  return self.milliseconds()
4793
5034
 
ccxt/bybit.py CHANGED
@@ -3530,29 +3530,29 @@ class bybit(Exchange, ImplicitAPI):
3530
3530
  avgPrice = self.omit_zero(self.safe_string(order, 'avgPrice'))
3531
3531
  rawTimeInForce = self.safe_string(order, 'timeInForce')
3532
3532
  timeInForce = self.parse_time_in_force(rawTimeInForce)
3533
- stopPrice = self.omit_zero(self.safe_string(order, 'triggerPrice'))
3533
+ triggerPrice = self.omit_zero(self.safe_string(order, 'triggerPrice'))
3534
3534
  reduceOnly = self.safe_bool(order, 'reduceOnly')
3535
3535
  takeProfitPrice = self.omit_zero(self.safe_string(order, 'takeProfit'))
3536
3536
  stopLossPrice = self.omit_zero(self.safe_string(order, 'stopLoss'))
3537
3537
  triggerDirection = self.safe_string(order, 'triggerDirection')
3538
3538
  isAscending = (triggerDirection == '1')
3539
- isStopOrderType2 = (stopPrice is not None) and reduceOnly
3539
+ isStopOrderType2 = (triggerPrice is not None) and reduceOnly
3540
3540
  if (stopLossPrice is None) and isStopOrderType2:
3541
3541
  # check if order is stop order type 2 - stopLossPrice
3542
3542
  if isAscending and (side == 'buy'):
3543
3543
  # stopLoss order against short position
3544
- stopLossPrice = stopPrice
3544
+ stopLossPrice = triggerPrice
3545
3545
  if not isAscending and (side == 'sell'):
3546
3546
  # stopLoss order against a long position
3547
- stopLossPrice = stopPrice
3547
+ stopLossPrice = triggerPrice
3548
3548
  if (takeProfitPrice is None) and isStopOrderType2:
3549
3549
  # check if order is stop order type 2 - takeProfitPrice
3550
3550
  if isAscending and (side == 'sell'):
3551
3551
  # takeprofit order against a long position
3552
- takeProfitPrice = stopPrice
3552
+ takeProfitPrice = triggerPrice
3553
3553
  if not isAscending and (side == 'buy'):
3554
3554
  # takeprofit order against a short position
3555
- takeProfitPrice = stopPrice
3555
+ takeProfitPrice = triggerPrice
3556
3556
  return self.safe_order({
3557
3557
  'info': order,
3558
3558
  'id': id,
@@ -3568,7 +3568,7 @@ class bybit(Exchange, ImplicitAPI):
3568
3568
  'reduceOnly': self.safe_bool(order, 'reduceOnly'),
3569
3569
  'side': side,
3570
3570
  'price': price,
3571
- 'triggerPrice': stopPrice,
3571
+ 'triggerPrice': triggerPrice,
3572
3572
  'takeProfitPrice': takeProfitPrice,
3573
3573
  'stopLossPrice': stopLossPrice,
3574
3574
  'amount': amount,
@@ -6369,7 +6369,7 @@ classic accounts only/ spot not supported* fetches information on an order made
6369
6369
  data = self.add_pagination_cursor_to_result(response)
6370
6370
  id = self.safe_string(result, 'symbol')
6371
6371
  market = self.safe_market(id, market, None, 'contract')
6372
- return self.parse_open_interests(data, market, since, limit)
6372
+ return self.parse_open_interests_history(data, market, since, limit)
6373
6373
 
6374
6374
  def fetch_open_interest(self, symbol: str, params={}):
6375
6375
  """