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/__init__.py +1 -1
- ccxt/abstract/bitmart.py +2 -0
- ccxt/abstract/okx.py +5 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +10 -3
- ccxt/async_support/binance.py +24 -24
- ccxt/async_support/bingx.py +3 -1
- ccxt/async_support/bitfinex.py +1 -1
- ccxt/async_support/bitget.py +1 -0
- ccxt/async_support/bitmart.py +243 -2
- ccxt/async_support/bybit.py +8 -8
- ccxt/async_support/exmo.py +60 -4
- ccxt/async_support/gate.py +1 -1
- ccxt/async_support/htx.py +1 -1
- ccxt/async_support/hyperliquid.py +60 -1
- ccxt/async_support/kraken.py +123 -25
- ccxt/async_support/kucoin.py +5 -1
- ccxt/async_support/mexc.py +3 -3
- ccxt/async_support/okx.py +6 -1
- ccxt/async_support/xt.py +3 -1
- ccxt/base/exchange.py +19 -4
- ccxt/base/types.py +10 -0
- ccxt/binance.py +24 -24
- ccxt/bingx.py +3 -1
- ccxt/bitfinex.py +1 -1
- ccxt/bitget.py +1 -0
- ccxt/bitmart.py +243 -2
- ccxt/bybit.py +8 -8
- ccxt/exmo.py +60 -4
- ccxt/gate.py +1 -1
- ccxt/htx.py +1 -1
- ccxt/hyperliquid.py +60 -1
- ccxt/kraken.py +123 -25
- ccxt/kucoin.py +5 -1
- ccxt/mexc.py +3 -3
- ccxt/okx.py +6 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/xt.py +3 -1
- {ccxt-4.4.40.dist-info → ccxt-4.4.41.dist-info}/METADATA +4 -4
- {ccxt-4.4.40.dist-info → ccxt-4.4.41.dist-info}/RECORD +43 -43
- {ccxt-4.4.40.dist-info → ccxt-4.4.41.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.40.dist-info → ccxt-4.4.41.dist-info}/WHEEL +0 -0
- {ccxt-4.4.40.dist-info → ccxt-4.4.41.dist-info}/top_level.txt +0 -0
ccxt/base/exchange.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
|
7
|
-
__version__ = '4.4.
|
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
|
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 =
|
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
|
-
|
5066
|
-
if
|
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 + '
|
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
|
-
|
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
|
-
|
5111
|
+
triggerPriceIsRequired = True
|
5112
5112
|
quantityIsRequired = True
|
5113
5113
|
elif (uppercaseType == 'STOP_LOSS_LIMIT') or (uppercaseType == 'TAKE_PROFIT_LIMIT'):
|
5114
5114
|
quantityIsRequired = True
|
5115
|
-
|
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
|
5130
|
-
if
|
5131
|
-
raise InvalidOrder(self.id + ' editOrder() requires a
|
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,
|
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
|
-
|
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':
|
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 + '
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
6204
|
+
if triggerPriceIsRequired:
|
6205
6205
|
if market['contract']:
|
6206
6206
|
if stopPrice is None:
|
6207
|
-
raise InvalidOrder(self.id + ' createOrder() requires a
|
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
|
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.
|
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.
|
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.
|
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':
|
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
|
-
|
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 = (
|
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 =
|
3544
|
+
stopLossPrice = triggerPrice
|
3545
3545
|
if not isAscending and (side == 'sell'):
|
3546
3546
|
# stopLoss order against a long position
|
3547
|
-
stopLossPrice =
|
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 =
|
3552
|
+
takeProfitPrice = triggerPrice
|
3553
3553
|
if not isAscending and (side == 'buy'):
|
3554
3554
|
# takeprofit order against a short position
|
3555
|
-
takeProfitPrice =
|
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':
|
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.
|
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
|
"""
|