ccxt 4.2.89__py2.py3-none-any.whl → 4.2.91__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/bingx.py +2 -0
- ccxt/abstract/bybit.py +2 -0
- ccxt/ascendex.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/ascendex.py +1 -0
- ccxt/async_support/base/exchange.py +13 -1
- ccxt/async_support/binance.py +81 -9
- ccxt/async_support/bingx.py +94 -1
- ccxt/async_support/bitfinex2.py +1 -0
- ccxt/async_support/bitget.py +2 -0
- ccxt/async_support/bitmex.py +1 -0
- ccxt/async_support/bitrue.py +1 -0
- ccxt/async_support/bybit.py +50 -0
- ccxt/async_support/coinbase.py +43 -21
- ccxt/async_support/coinbaseinternational.py +1 -0
- ccxt/async_support/coinex.py +96 -8
- ccxt/async_support/cryptocom.py +1 -0
- ccxt/async_support/delta.py +1 -0
- ccxt/async_support/digifinex.py +1 -0
- ccxt/async_support/exmo.py +1 -0
- ccxt/async_support/gate.py +2 -0
- ccxt/async_support/gemini.py +11 -9
- ccxt/async_support/hitbtc.py +1 -0
- ccxt/async_support/htx.py +1 -0
- ccxt/async_support/hyperliquid.py +1 -0
- ccxt/async_support/kraken.py +11 -8
- ccxt/async_support/kucoin.py +1 -0
- ccxt/async_support/kucoinfutures.py +32 -4
- ccxt/async_support/mexc.py +1 -0
- ccxt/async_support/okx.py +173 -38
- ccxt/async_support/phemex.py +1 -0
- ccxt/async_support/woo.py +1 -0
- ccxt/base/exchange.py +53 -14
- ccxt/base/types.py +1 -0
- ccxt/binance.py +81 -9
- ccxt/bingx.py +94 -1
- ccxt/bitfinex2.py +1 -0
- ccxt/bitget.py +2 -0
- ccxt/bitmex.py +1 -0
- ccxt/bitrue.py +1 -0
- ccxt/bybit.py +50 -0
- ccxt/coinbase.py +43 -21
- ccxt/coinbaseinternational.py +1 -0
- ccxt/coinex.py +96 -8
- ccxt/cryptocom.py +1 -0
- ccxt/delta.py +1 -0
- ccxt/digifinex.py +1 -0
- ccxt/exmo.py +1 -0
- ccxt/gate.py +2 -0
- ccxt/gemini.py +11 -9
- ccxt/hitbtc.py +1 -0
- ccxt/htx.py +1 -0
- ccxt/hyperliquid.py +1 -0
- ccxt/kraken.py +11 -8
- ccxt/kucoin.py +1 -0
- ccxt/kucoinfutures.py +32 -4
- ccxt/mexc.py +1 -0
- ccxt/okx.py +173 -38
- ccxt/phemex.py +1 -0
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/bitmex.py +35 -17
- ccxt/pro/kucoin.py +85 -0
- ccxt/pro/kucoinfutures.py +141 -76
- ccxt/test/test_async.py +15 -1
- ccxt/test/test_sync.py +15 -1
- ccxt/woo.py +1 -0
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/METADATA +4 -4
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/RECORD +71 -71
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/WHEEL +0 -0
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/top_level.txt +0 -0
ccxt/binance.py
CHANGED
@@ -120,6 +120,7 @@ class binance(Exchange, ImplicitAPI):
|
|
120
120
|
'fetchLeverages': True,
|
121
121
|
'fetchLeverageTiers': True,
|
122
122
|
'fetchLiquidations': False,
|
123
|
+
'fetchMarginAdjustmentHistory': True,
|
123
124
|
'fetchMarginMode': 'emulated',
|
124
125
|
'fetchMarginModes': True,
|
125
126
|
'fetchMarketLeverageTiers': 'emulated',
|
@@ -10329,21 +10330,37 @@ class binance(Exchange, ImplicitAPI):
|
|
10329
10330
|
# "type": 1
|
10330
10331
|
# }
|
10331
10332
|
#
|
10333
|
+
# fetchMarginAdjustmentHistory
|
10334
|
+
#
|
10335
|
+
# {
|
10336
|
+
# symbol: "XRPUSDT",
|
10337
|
+
# type: "1",
|
10338
|
+
# deltaType: "TRADE",
|
10339
|
+
# amount: "2.57148240",
|
10340
|
+
# asset: "USDT",
|
10341
|
+
# time: "1711046271555",
|
10342
|
+
# positionSide: "BOTH",
|
10343
|
+
# clientTranId: ""
|
10344
|
+
# }
|
10345
|
+
#
|
10332
10346
|
rawType = self.safe_integer(data, 'type')
|
10333
|
-
resultType = 'add' if (rawType == 1) else 'reduce'
|
10334
|
-
resultAmount = self.safe_number(data, 'amount')
|
10335
10347
|
errorCode = self.safe_string(data, 'code')
|
10336
|
-
|
10348
|
+
marketId = self.safe_string(data, 'symbol')
|
10349
|
+
timestamp = self.safe_integer(data, 'time')
|
10350
|
+
market = self.safe_market(marketId, market, None, 'swap')
|
10351
|
+
noErrorCode = errorCode is None
|
10352
|
+
success = errorCode == '200'
|
10337
10353
|
return {
|
10338
10354
|
'info': data,
|
10339
10355
|
'symbol': market['symbol'],
|
10340
|
-
'type':
|
10341
|
-
'
|
10356
|
+
'type': 'add' if (rawType == 1) else 'reduce',
|
10357
|
+
'marginMode': 'isolated',
|
10358
|
+
'amount': self.safe_number(data, 'amount'),
|
10359
|
+
'code': self.safe_string(data, 'asset'),
|
10342
10360
|
'total': None,
|
10343
|
-
'
|
10344
|
-
'
|
10345
|
-
'
|
10346
|
-
'datetime': None,
|
10361
|
+
'status': 'ok' if (success or noErrorCode) else 'failed',
|
10362
|
+
'timestamp': timestamp,
|
10363
|
+
'datetime': self.iso8601(timestamp),
|
10347
10364
|
}
|
10348
10365
|
|
10349
10366
|
def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
|
@@ -11505,3 +11522,58 @@ class binance(Exchange, ImplicitAPI):
|
|
11505
11522
|
'baseVolume': self.safe_number(chain, 'volume'),
|
11506
11523
|
'quoteVolume': None,
|
11507
11524
|
}
|
11525
|
+
|
11526
|
+
def fetch_margin_adjustment_history(self, symbol: Str = None, type: Str = None, since: Num = None, limit: Num = None, params={}) -> List[MarginModification]:
|
11527
|
+
"""
|
11528
|
+
fetches the history of margin added or reduced from contract isolated positions
|
11529
|
+
:see: https://binance-docs.github.io/apidocs/futures/en/#get-position-margin-change-history-trade
|
11530
|
+
:see: https://binance-docs.github.io/apidocs/delivery/en/#get-position-margin-change-history-trade
|
11531
|
+
:param str symbol: unified market symbol
|
11532
|
+
:param str [type]: "add" or "reduce"
|
11533
|
+
:param int [since]: timestamp in ms of the earliest change to fetch
|
11534
|
+
:param int [limit]: the maximum amount of changes to fetch
|
11535
|
+
:param dict params: extra parameters specific to the exchange api endpoint
|
11536
|
+
:param int [params.until]: timestamp in ms of the latest change to fetch
|
11537
|
+
:returns dict[]: a list of `margin structures <https://docs.ccxt.com/#/?id=margin-loan-structure>`
|
11538
|
+
"""
|
11539
|
+
self.load_markets()
|
11540
|
+
if symbol is None:
|
11541
|
+
raise ArgumentsRequired(self.id + ' fetchMarginAdjustmentHistory() requires a symbol argument')
|
11542
|
+
market = self.market(symbol)
|
11543
|
+
until = self.safe_integer(params, 'until')
|
11544
|
+
params = self.omit(params, 'until')
|
11545
|
+
request = {
|
11546
|
+
'symbol': market['id'],
|
11547
|
+
}
|
11548
|
+
if type is not None:
|
11549
|
+
request['type'] = 1 if (type == 'add') else 2
|
11550
|
+
if since is not None:
|
11551
|
+
request['startTime'] = since
|
11552
|
+
if limit is not None:
|
11553
|
+
request['limit'] = limit
|
11554
|
+
if until is not None:
|
11555
|
+
request['endTime'] = until
|
11556
|
+
response = None
|
11557
|
+
if market['linear']:
|
11558
|
+
response = self.fapiPrivateGetPositionMarginHistory(self.extend(request, params))
|
11559
|
+
elif market['inverse']:
|
11560
|
+
response = self.dapiPrivateGetPositionMarginHistory(self.extend(request, params))
|
11561
|
+
else:
|
11562
|
+
raise BadRequest(self.id + 'fetchMarginAdjustmentHistory() is not supported for markets of type ' + market['type'])
|
11563
|
+
#
|
11564
|
+
# [
|
11565
|
+
# {
|
11566
|
+
# symbol: "XRPUSDT",
|
11567
|
+
# type: "1",
|
11568
|
+
# deltaType: "TRADE",
|
11569
|
+
# amount: "2.57148240",
|
11570
|
+
# asset: "USDT",
|
11571
|
+
# time: "1711046271555",
|
11572
|
+
# positionSide: "BOTH",
|
11573
|
+
# clientTranId: ""
|
11574
|
+
# }
|
11575
|
+
# ...
|
11576
|
+
# ]
|
11577
|
+
#
|
11578
|
+
modifications = self.parse_margin_modifications(response)
|
11579
|
+
return self.filter_by_symbol_since_limit(modifications, symbol, since, limit)
|
ccxt/bingx.py
CHANGED
@@ -73,6 +73,7 @@ class bingx(Exchange, ImplicitAPI):
|
|
73
73
|
'fetchFundingRates': True,
|
74
74
|
'fetchLeverage': True,
|
75
75
|
'fetchLiquidations': False,
|
76
|
+
'fetchMarginAdjustmentHistory': False,
|
76
77
|
'fetchMarginMode': True,
|
77
78
|
'fetchMarkets': True,
|
78
79
|
'fetchMarkOHLCV': True,
|
@@ -82,6 +83,7 @@ class bingx(Exchange, ImplicitAPI):
|
|
82
83
|
'fetchOpenOrders': True,
|
83
84
|
'fetchOrder': True,
|
84
85
|
'fetchOrderBook': True,
|
86
|
+
'fetchOrders': True,
|
85
87
|
'fetchPositionMode': True,
|
86
88
|
'fetchPositions': True,
|
87
89
|
'fetchTicker': True,
|
@@ -193,6 +195,7 @@ class bingx(Exchange, ImplicitAPI):
|
|
193
195
|
'positionSide/dual': 1,
|
194
196
|
'market/markPriceKlines': 1,
|
195
197
|
'trade/batchCancelReplace': 1,
|
198
|
+
'trade/fullOrder': 1,
|
196
199
|
},
|
197
200
|
'post': {
|
198
201
|
'trade/cancelReplace': 1,
|
@@ -340,6 +343,7 @@ class bingx(Exchange, ImplicitAPI):
|
|
340
343
|
'post': {
|
341
344
|
'swap/trace/closeTrackOrder': 1,
|
342
345
|
'swap/trace/setTPSL': 1,
|
346
|
+
'spot/trader/sellOrder': 1,
|
343
347
|
},
|
344
348
|
},
|
345
349
|
},
|
@@ -2586,7 +2590,7 @@ class bingx(Exchange, ImplicitAPI):
|
|
2586
2590
|
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
2587
2591
|
"""
|
2588
2592
|
if symbol is None:
|
2589
|
-
raise ArgumentsRequired(self.id + '
|
2593
|
+
raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
|
2590
2594
|
self.load_markets()
|
2591
2595
|
market = self.market(symbol)
|
2592
2596
|
request: dict = {
|
@@ -2654,6 +2658,94 @@ class bingx(Exchange, ImplicitAPI):
|
|
2654
2658
|
first = self.safe_dict(data, 'order', data)
|
2655
2659
|
return self.parse_order(first, market)
|
2656
2660
|
|
2661
|
+
def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
2662
|
+
"""
|
2663
|
+
fetches information on multiple orders made by the user
|
2664
|
+
:see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#User's%20All%20Orders
|
2665
|
+
:param str symbol: unified market symbol of the market orders were made in
|
2666
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
2667
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
2668
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2669
|
+
:param int [params.until]: the latest time in ms to fetch entries for
|
2670
|
+
:param int [params.orderId]: Only return subsequent orders, and return the latest order by default
|
2671
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
2672
|
+
"""
|
2673
|
+
self.load_markets()
|
2674
|
+
request = {}
|
2675
|
+
market = None
|
2676
|
+
if symbol is not None:
|
2677
|
+
market = self.market(symbol)
|
2678
|
+
request['symbol'] = market['id']
|
2679
|
+
type = None
|
2680
|
+
type, params = self.handle_market_type_and_params('fetchOrders', market, params)
|
2681
|
+
if type != 'swap':
|
2682
|
+
raise NotSupported(self.id + ' fetchOrders() is only supported for swap markets')
|
2683
|
+
if limit is not None:
|
2684
|
+
request['limit'] = limit
|
2685
|
+
if since is not None:
|
2686
|
+
request['startTime'] = since
|
2687
|
+
until = self.safe_integer_2(params, 'until', 'till') # unified in milliseconds
|
2688
|
+
endTime = self.safe_integer(params, 'endTime', until) # exchange-specific in milliseconds
|
2689
|
+
params = self.omit(params, ['endTime', 'till', 'until'])
|
2690
|
+
if endTime is not None:
|
2691
|
+
request['endTime'] = endTime
|
2692
|
+
response = self.swapV1PrivateGetTradeFullOrder(self.extend(request, params))
|
2693
|
+
#
|
2694
|
+
# {
|
2695
|
+
# "code": 0,
|
2696
|
+
# "msg": "",
|
2697
|
+
# "data": {
|
2698
|
+
# "orders": [
|
2699
|
+
# {
|
2700
|
+
# "symbol": "PYTH-USDT",
|
2701
|
+
# "orderId": 1736007506620112100,
|
2702
|
+
# "side": "SELL",
|
2703
|
+
# "positionSide": "SHORT",
|
2704
|
+
# "type": "LIMIT",
|
2705
|
+
# "origQty": "33",
|
2706
|
+
# "price": "0.3916",
|
2707
|
+
# "executedQty": "33",
|
2708
|
+
# "avgPrice": "0.3916",
|
2709
|
+
# "cumQuote": "13",
|
2710
|
+
# "stopPrice": "",
|
2711
|
+
# "profit": "0.0000",
|
2712
|
+
# "commission": "-0.002585",
|
2713
|
+
# "status": "FILLED",
|
2714
|
+
# "time": 1702731418000,
|
2715
|
+
# "updateTime": 1702731470000,
|
2716
|
+
# "clientOrderId": "",
|
2717
|
+
# "leverage": "15X",
|
2718
|
+
# "takeProfit": {
|
2719
|
+
# "type": "TAKE_PROFIT",
|
2720
|
+
# "quantity": 0,
|
2721
|
+
# "stopPrice": 0,
|
2722
|
+
# "price": 0,
|
2723
|
+
# "workingType": ""
|
2724
|
+
# },
|
2725
|
+
# "stopLoss": {
|
2726
|
+
# "type": "STOP",
|
2727
|
+
# "quantity": 0,
|
2728
|
+
# "stopPrice": 0,
|
2729
|
+
# "price": 0,
|
2730
|
+
# "workingType": ""
|
2731
|
+
# },
|
2732
|
+
# "advanceAttr": 0,
|
2733
|
+
# "positionID": 0,
|
2734
|
+
# "takeProfitEntrustPrice": 0,
|
2735
|
+
# "stopLossEntrustPrice": 0,
|
2736
|
+
# "orderType": "",
|
2737
|
+
# "workingType": "MARK_PRICE",
|
2738
|
+
# "stopGuaranteed": False,
|
2739
|
+
# "triggerOrderId": 1736012449498123500
|
2740
|
+
# }
|
2741
|
+
# ]
|
2742
|
+
# }
|
2743
|
+
# }
|
2744
|
+
#
|
2745
|
+
data = self.safe_dict(response, 'data', {})
|
2746
|
+
orders = self.safe_list(data, 'orders', [])
|
2747
|
+
return self.parse_orders(orders, market, since, limit)
|
2748
|
+
|
2657
2749
|
def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
2658
2750
|
"""
|
2659
2751
|
:see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Open%20Orders
|
@@ -3306,6 +3398,7 @@ class bingx(Exchange, ImplicitAPI):
|
|
3306
3398
|
'info': data,
|
3307
3399
|
'symbol': self.safe_string(market, 'symbol'),
|
3308
3400
|
'type': 'add' if (type == '1') else 'reduce',
|
3401
|
+
'marginMode': 'isolated',
|
3309
3402
|
'amount': self.safe_number(data, 'amount'),
|
3310
3403
|
'total': self.safe_number(data, 'margin'),
|
3311
3404
|
'code': self.safe_string(market, 'settle'),
|
ccxt/bitfinex2.py
CHANGED
ccxt/bitget.py
CHANGED
@@ -105,6 +105,7 @@ class bitget(Exchange, ImplicitAPI):
|
|
105
105
|
'fetchLeverage': True,
|
106
106
|
'fetchLeverageTiers': False,
|
107
107
|
'fetchLiquidations': False,
|
108
|
+
'fetchMarginAdjustmentHistory': False,
|
108
109
|
'fetchMarginMode': True,
|
109
110
|
'fetchMarketLeverageTiers': True,
|
110
111
|
'fetchMarkets': True,
|
@@ -6485,6 +6486,7 @@ class bitget(Exchange, ImplicitAPI):
|
|
6485
6486
|
'info': data,
|
6486
6487
|
'symbol': market['symbol'],
|
6487
6488
|
'type': None,
|
6489
|
+
'marginMode': 'isolated',
|
6488
6490
|
'amount': None,
|
6489
6491
|
'total': None,
|
6490
6492
|
'code': market['settle'],
|
ccxt/bitmex.py
CHANGED
ccxt/bitrue.py
CHANGED
ccxt/bybit.py
CHANGED
@@ -95,6 +95,7 @@ class bybit(Exchange, ImplicitAPI):
|
|
95
95
|
'fetchLedger': True,
|
96
96
|
'fetchLeverage': True,
|
97
97
|
'fetchLeverageTiers': True,
|
98
|
+
'fetchMarginAdjustmentHistory': False,
|
98
99
|
'fetchMarketLeverageTiers': True,
|
99
100
|
'fetchMarkets': True,
|
100
101
|
'fetchMarkOHLCV': True,
|
@@ -165,6 +166,13 @@ class bybit(Exchange, ImplicitAPI):
|
|
165
166
|
'public': 'https://api.{hostname}',
|
166
167
|
'private': 'https://api.{hostname}',
|
167
168
|
},
|
169
|
+
'demotrading': {
|
170
|
+
'spot': 'https://api-demo.{hostname}',
|
171
|
+
'futures': 'https://api-demo.{hostname}',
|
172
|
+
'v2': 'https://api-demo.{hostname}',
|
173
|
+
'public': 'https://api-demo.{hostname}',
|
174
|
+
'private': 'https://api-demo.{hostname}',
|
175
|
+
},
|
168
176
|
'www': 'https://www.bybit.com',
|
169
177
|
'doc': [
|
170
178
|
'https://bybit-exchange.github.io/docs/inverse/',
|
@@ -353,6 +361,7 @@ class bybit(Exchange, ImplicitAPI):
|
|
353
361
|
'v5/user/get-member-type': 5,
|
354
362
|
'v5/user/aff-customer-info': 5,
|
355
363
|
'v5/user/del-submember': 5,
|
364
|
+
'v5/user/submembers': 5,
|
356
365
|
# spot leverage token
|
357
366
|
'v5/spot-lever-token/order-record': 1, # 50/s => cost = 50 / 50 = 1
|
358
367
|
# spot margin trade
|
@@ -513,6 +522,8 @@ class bybit(Exchange, ImplicitAPI):
|
|
513
522
|
'v5/lending/redeem-cancel': 5,
|
514
523
|
'v5/account/set-collateral-switch': 5,
|
515
524
|
'v5/account/set-collateral-switch-batch': 5,
|
525
|
+
# demo trading
|
526
|
+
'v5/account/demo-apply-money': 5,
|
516
527
|
},
|
517
528
|
},
|
518
529
|
},
|
@@ -979,6 +990,8 @@ class bybit(Exchange, ImplicitAPI):
|
|
979
990
|
},
|
980
991
|
'precisionMode': TICK_SIZE,
|
981
992
|
'options': {
|
993
|
+
'sandboxMode': False,
|
994
|
+
'enableDemoTrading': False,
|
982
995
|
'fetchMarkets': ['spot', 'linear', 'inverse', 'option'],
|
983
996
|
'createOrder': {
|
984
997
|
'method': 'privatePostV5OrderCreate', # 'privatePostV5PositionTradingStop'
|
@@ -1062,6 +1075,32 @@ class bybit(Exchange, ImplicitAPI):
|
|
1062
1075
|
},
|
1063
1076
|
})
|
1064
1077
|
|
1078
|
+
def set_sandbox_mode(self, enable: bool):
|
1079
|
+
"""
|
1080
|
+
enables or disables sandbox mode
|
1081
|
+
:param boolean [enable]: True if demo trading should be enabled, False otherwise
|
1082
|
+
"""
|
1083
|
+
super(bybit, self).set_sandbox_mode(enable)
|
1084
|
+
self.options['sandboxMode'] = enable
|
1085
|
+
|
1086
|
+
def enable_demo_trading(self, enable: bool):
|
1087
|
+
"""
|
1088
|
+
enables or disables demo trading mode
|
1089
|
+
:see: https://bybit-exchange.github.io/docs/v5/demo
|
1090
|
+
:param boolean [enable]: True if demo trading should be enabled, False otherwise
|
1091
|
+
"""
|
1092
|
+
if self.options['sandboxMode']:
|
1093
|
+
raise NotSupported(self.id + ' demo trading does not support in sandbox environment')
|
1094
|
+
# enable demo trading in bybit, see: https://bybit-exchange.github.io/docs/v5/demo
|
1095
|
+
if enable:
|
1096
|
+
self.urls['apiBackupDemoTrading'] = self.urls['api']
|
1097
|
+
self.urls['api'] = self.urls['demotrading']
|
1098
|
+
elif 'apiBackupDemoTrading' in self.urls:
|
1099
|
+
self.urls['api'] = self.urls['apiBackupDemoTrading']
|
1100
|
+
newUrls = self.omit(self.urls, 'apiBackupDemoTrading')
|
1101
|
+
self.urls = newUrls
|
1102
|
+
self.options['enableDemoTrading'] = enable
|
1103
|
+
|
1065
1104
|
def nonce(self):
|
1066
1105
|
return self.milliseconds() - self.options['timeDifference']
|
1067
1106
|
|
@@ -1077,12 +1116,21 @@ class bybit(Exchange, ImplicitAPI):
|
|
1077
1116
|
return data
|
1078
1117
|
|
1079
1118
|
def is_unified_enabled(self, params={}):
|
1119
|
+
"""
|
1120
|
+
returns [enableUnifiedMargin, enableUnifiedAccount] so the user can check if unified account is enabled
|
1121
|
+
"""
|
1080
1122
|
# The API key of user id must own one of permissions will be allowed to call following API endpoints.
|
1081
1123
|
# SUB UID: "Account Transfer"
|
1082
1124
|
# MASTER UID: "Account Transfer", "Subaccount Transfer", "Withdrawal"
|
1083
1125
|
enableUnifiedMargin = self.safe_value(self.options, 'enableUnifiedMargin')
|
1084
1126
|
enableUnifiedAccount = self.safe_value(self.options, 'enableUnifiedAccount')
|
1085
1127
|
if enableUnifiedMargin is None or enableUnifiedAccount is None:
|
1128
|
+
if self.options['enableDemoTrading']:
|
1129
|
+
# info endpoint is not available in demo trading
|
1130
|
+
# so we're assuming UTA is enabled
|
1131
|
+
self.options['enableUnifiedMargin'] = False
|
1132
|
+
self.options['enableUnifiedAccount'] = True
|
1133
|
+
return [self.options['enableUnifiedMargin'], self.options['enableUnifiedAccount']]
|
1086
1134
|
response = self.privateGetV5UserQueryApi(params)
|
1087
1135
|
#
|
1088
1136
|
# {
|
@@ -1242,6 +1290,8 @@ class bybit(Exchange, ImplicitAPI):
|
|
1242
1290
|
"""
|
1243
1291
|
if not self.check_required_credentials(False):
|
1244
1292
|
return None
|
1293
|
+
if self.options['enableDemoTrading']:
|
1294
|
+
return None
|
1245
1295
|
response = self.privateGetV5AssetCoinQueryInfo(params)
|
1246
1296
|
#
|
1247
1297
|
# {
|
ccxt/coinbase.py
CHANGED
@@ -337,6 +337,7 @@ class coinbase(Exchange, ImplicitAPI):
|
|
337
337
|
'CGLD': 'CELO',
|
338
338
|
},
|
339
339
|
'options': {
|
340
|
+
'brokerId': 'ccxt',
|
340
341
|
'stablePairs': ['BUSD-USD', 'CBETH-ETH', 'DAI-USD', 'GUSD-USD', 'GYEN-USD', 'PAX-USD', 'PAX-USDT', 'USDC-EUR', 'USDC-GBP', 'USDT-EUR', 'USDT-GBP', 'USDT-USD', 'USDT-USDC', 'WBTC-BTC'],
|
341
342
|
'fetchCurrencies': {
|
342
343
|
'expires': 5000,
|
@@ -2251,8 +2252,9 @@ class coinbase(Exchange, ImplicitAPI):
|
|
2251
2252
|
"""
|
2252
2253
|
self.load_markets()
|
2253
2254
|
market = self.market(symbol)
|
2255
|
+
id = self.safe_string(self.options, 'brokerId', 'ccxt')
|
2254
2256
|
request = {
|
2255
|
-
'client_order_id': self.uuid(),
|
2257
|
+
'client_order_id': id + '-' + self.uuid(),
|
2256
2258
|
'product_id': market['id'],
|
2257
2259
|
'side': side.upper(),
|
2258
2260
|
}
|
@@ -3573,25 +3575,14 @@ class coinbase(Exchange, ImplicitAPI):
|
|
3573
3575
|
url = self.urls['api']['rest'] + fullPath
|
3574
3576
|
if signed:
|
3575
3577
|
authorization = self.safe_string(self.headers, 'Authorization')
|
3578
|
+
authorizationString = None
|
3576
3579
|
if authorization is not None:
|
3577
|
-
|
3578
|
-
'Authorization': authorization,
|
3579
|
-
'Content-Type': 'application/json',
|
3580
|
-
}
|
3581
|
-
if method != 'GET':
|
3582
|
-
if query:
|
3583
|
-
body = self.json(query)
|
3580
|
+
authorizationString = authorization
|
3584
3581
|
elif self.token and not self.check_required_credentials(False):
|
3585
|
-
|
3586
|
-
'Authorization': 'Bearer ' + self.token,
|
3587
|
-
'Content-Type': 'application/json',
|
3588
|
-
}
|
3589
|
-
if method != 'GET':
|
3590
|
-
if query:
|
3591
|
-
body = self.json(query)
|
3582
|
+
authorizationString = 'Bearer ' + self.token
|
3592
3583
|
else:
|
3593
3584
|
self.check_required_credentials()
|
3594
|
-
|
3585
|
+
seconds = self.seconds()
|
3595
3586
|
payload = ''
|
3596
3587
|
if method != 'GET':
|
3597
3588
|
if query:
|
@@ -3605,14 +3596,45 @@ class coinbase(Exchange, ImplicitAPI):
|
|
3605
3596
|
# https://docs.cloud.coinbase.com/advanced-trade-api/docs/auth#example-request
|
3606
3597
|
# v2: 'GET' require payload in the signature
|
3607
3598
|
# https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-key-authentication
|
3608
|
-
|
3609
|
-
|
3599
|
+
isCloudAPiKey = (self.apiKey.find('organizations/') >= 0) or (self.secret.startswith('-----BEGIN'))
|
3600
|
+
if isCloudAPiKey:
|
3601
|
+
if self.apiKey.startswith('-----BEGIN'):
|
3602
|
+
raise ArgumentsRequired(self.id + ' apiKey should contain the name(eg: organizations/3b910e93....) and not the public key')
|
3603
|
+
# it may not work for v2
|
3604
|
+
uri = method + ' ' + url.replace('https://', '')
|
3605
|
+
quesPos = uri.find('?')
|
3606
|
+
if quesPos >= 0:
|
3607
|
+
uri = uri[0:quesPos]
|
3608
|
+
nonce = self.random_bytes(16)
|
3609
|
+
request = {
|
3610
|
+
'aud': ['retail_rest_api_proxy'],
|
3611
|
+
'iss': 'coinbase-cloud',
|
3612
|
+
'nbf': seconds,
|
3613
|
+
'exp': seconds + 120,
|
3614
|
+
'sub': self.apiKey,
|
3615
|
+
'uri': uri,
|
3616
|
+
'iat': seconds,
|
3617
|
+
}
|
3618
|
+
token = self.jwt(request, self.encode(self.secret), 'sha256', False, {'kid': self.apiKey, 'nonce': nonce, 'alg': 'ES256'})
|
3619
|
+
authorizationString = 'Bearer ' + token
|
3620
|
+
else:
|
3621
|
+
timestampString = str(self.seconds())
|
3622
|
+
auth = timestampString + method + savedPath + payload
|
3623
|
+
signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
|
3624
|
+
headers = {
|
3625
|
+
'CB-ACCESS-KEY': self.apiKey,
|
3626
|
+
'CB-ACCESS-SIGN': signature,
|
3627
|
+
'CB-ACCESS-TIMESTAMP': timestampString,
|
3628
|
+
'Content-Type': 'application/json',
|
3629
|
+
}
|
3630
|
+
if authorizationString is not None:
|
3610
3631
|
headers = {
|
3611
|
-
'
|
3612
|
-
'CB-ACCESS-SIGN': signature,
|
3613
|
-
'CB-ACCESS-TIMESTAMP': timestampString,
|
3632
|
+
'Authorization': authorizationString,
|
3614
3633
|
'Content-Type': 'application/json',
|
3615
3634
|
}
|
3635
|
+
if method != 'GET':
|
3636
|
+
if query:
|
3637
|
+
body = self.json(query)
|
3616
3638
|
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
3617
3639
|
|
3618
3640
|
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
ccxt/coinbaseinternational.py
CHANGED
ccxt/coinex.py
CHANGED
@@ -92,6 +92,7 @@ class coinex(Exchange, ImplicitAPI):
|
|
92
92
|
'fetchLeverage': 'emulated',
|
93
93
|
'fetchLeverages': True,
|
94
94
|
'fetchLeverageTiers': True,
|
95
|
+
'fetchMarginAdjustmentHistory': True,
|
95
96
|
'fetchMarketLeverageTiers': 'emulated',
|
96
97
|
'fetchMarkets': True,
|
97
98
|
'fetchMarkOHLCV': False,
|
@@ -3966,11 +3967,10 @@ class coinex(Exchange, ImplicitAPI):
|
|
3966
3967
|
# "message":"OK"
|
3967
3968
|
# }
|
3968
3969
|
#
|
3970
|
+
data = self.safe_dict(response, 'data')
|
3969
3971
|
status = self.safe_string(response, 'message')
|
3970
|
-
|
3971
|
-
return self.extend(self.parse_margin_modification(response, market), {
|
3972
|
+
return self.extend(self.parse_margin_modification(data, market), {
|
3972
3973
|
'amount': self.parse_number(amount),
|
3973
|
-
'type': type,
|
3974
3974
|
'status': status,
|
3975
3975
|
})
|
3976
3976
|
|
@@ -4030,13 +4030,34 @@ class coinex(Exchange, ImplicitAPI):
|
|
4030
4030
|
# "user_id": 3620173
|
4031
4031
|
# }
|
4032
4032
|
#
|
4033
|
-
|
4033
|
+
# fetchMarginAdjustmentHistory
|
4034
|
+
#
|
4035
|
+
# {
|
4036
|
+
# bkr_price: '0',
|
4037
|
+
# leverage: '3',
|
4038
|
+
# liq_price: '0',
|
4039
|
+
# margin_amount: '5.33236666666666666666',
|
4040
|
+
# margin_change: '3',
|
4041
|
+
# market: 'XRPUSDT',
|
4042
|
+
# position_amount: '11',
|
4043
|
+
# position_id: '297155652',
|
4044
|
+
# position_type: '2',
|
4045
|
+
# settle_price: '0.6361',
|
4046
|
+
# time: '1711050906.382891',
|
4047
|
+
# type: '1',
|
4048
|
+
# user_id: '3685860'
|
4049
|
+
# }
|
4050
|
+
#
|
4051
|
+
marketId = self.safe_string(data, 'market')
|
4052
|
+
type = self.safe_string(data, 'type')
|
4053
|
+
timestamp = self.safe_integer_product_2(data, 'time', 'update_time', 1000)
|
4034
4054
|
return {
|
4035
4055
|
'info': data,
|
4036
|
-
'symbol': self.safe_symbol(None,
|
4037
|
-
'type':
|
4038
|
-
'
|
4039
|
-
'
|
4056
|
+
'symbol': self.safe_symbol(marketId, market, None, 'swap'),
|
4057
|
+
'type': 'add' if (type == '1') else 'reduce',
|
4058
|
+
'marginMode': 'isolated',
|
4059
|
+
'amount': self.safe_number(data, 'margin_change'),
|
4060
|
+
'total': self.safe_number(data, 'position_amount'),
|
4040
4061
|
'code': market['quote'],
|
4041
4062
|
'status': None,
|
4042
4063
|
'timestamp': timestamp,
|
@@ -4644,6 +4665,7 @@ class coinex(Exchange, ImplicitAPI):
|
|
4644
4665
|
currencyId = self.safe_string(transfer, 'asset')
|
4645
4666
|
currencyCode = self.safe_currency_code(currencyId, currency)
|
4646
4667
|
return {
|
4668
|
+
'info': transfer,
|
4647
4669
|
'id': self.safe_integer(transfer, 'id'),
|
4648
4670
|
'timestamp': timestamp,
|
4649
4671
|
'datetime': self.iso8601(timestamp),
|
@@ -5410,3 +5432,69 @@ class coinex(Exchange, ImplicitAPI):
|
|
5410
5432
|
self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
|
5411
5433
|
raise ExchangeError(feedback)
|
5412
5434
|
return None
|
5435
|
+
|
5436
|
+
def fetch_margin_adjustment_history(self, symbol: Str = None, type: Str = None, since: Num = None, limit: Num = None, params={}) -> List[MarginModification]:
|
5437
|
+
"""
|
5438
|
+
fetches the history of margin added or reduced from contract isolated positions
|
5439
|
+
:see: https://viabtc.github.io/coinex_api_en_doc/futures/#docsfutures001_http046_position_margin_history
|
5440
|
+
:param str [symbol]: unified market symbol
|
5441
|
+
:param str [type]: not used by coinex fetchMarginAdjustmentHistory
|
5442
|
+
:param int [since]: timestamp in ms of the earliest change to fetch
|
5443
|
+
:param int [limit]: the maximum amount of changes to fetch, default=100, max=100
|
5444
|
+
:param dict params: extra parameters specific to the exchange api endpoint
|
5445
|
+
:param int [params.until]: timestamp in ms of the latest change to fetch
|
5446
|
+
*
|
5447
|
+
* EXCHANGE SPECIFIC PARAMETERS
|
5448
|
+
:param int [params.offset]: offset
|
5449
|
+
:returns dict[]: a list of `margin structures <https://docs.ccxt.com/#/?id=margin-loan-structure>`
|
5450
|
+
"""
|
5451
|
+
self.load_markets()
|
5452
|
+
until = self.safe_integer(params, 'until')
|
5453
|
+
params = self.omit(params, 'until')
|
5454
|
+
if limit is None:
|
5455
|
+
limit = 100
|
5456
|
+
request = {
|
5457
|
+
'market': '',
|
5458
|
+
'position_id': 0,
|
5459
|
+
'offset': 0,
|
5460
|
+
'limit': limit,
|
5461
|
+
}
|
5462
|
+
if symbol is not None:
|
5463
|
+
market = self.market(symbol)
|
5464
|
+
request['market'] = market['id']
|
5465
|
+
if since is not None:
|
5466
|
+
request['start_time'] = since
|
5467
|
+
if until is not None:
|
5468
|
+
request['end_time'] = until
|
5469
|
+
response = self.v1PerpetualPrivateGetPositionMarginHistory(self.extend(request, params))
|
5470
|
+
#
|
5471
|
+
# {
|
5472
|
+
# code: '0',
|
5473
|
+
# data: {
|
5474
|
+
# limit: '100',
|
5475
|
+
# offset: '0',
|
5476
|
+
# records: [
|
5477
|
+
# {
|
5478
|
+
# bkr_price: '0',
|
5479
|
+
# leverage: '3',
|
5480
|
+
# liq_price: '0',
|
5481
|
+
# margin_amount: '5.33236666666666666666',
|
5482
|
+
# margin_change: '3',
|
5483
|
+
# market: 'XRPUSDT',
|
5484
|
+
# position_amount: '11',
|
5485
|
+
# position_id: '297155652',
|
5486
|
+
# position_type: '2',
|
5487
|
+
# settle_price: '0.6361',
|
5488
|
+
# time: '1711050906.382891',
|
5489
|
+
# type: '1',
|
5490
|
+
# user_id: '3685860'
|
5491
|
+
# }
|
5492
|
+
# ]
|
5493
|
+
# },
|
5494
|
+
# message: 'OK'
|
5495
|
+
# }
|
5496
|
+
#
|
5497
|
+
data = self.safe_dict(response, 'data', {})
|
5498
|
+
records = self.safe_list(data, 'records', [])
|
5499
|
+
modifications = self.parse_margin_modifications(records, None, 'market', 'swap')
|
5500
|
+
return self.filter_by_symbol_since_limit(modifications, symbol, since, limit)
|