ccxt 4.4.92__py2.py3-none-any.whl → 4.4.94__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/lbank.py +1 -1
- ccxt/ascendex.py +9 -8
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/ascendex.py +9 -8
- ccxt/async_support/base/exchange.py +4 -1
- ccxt/async_support/base/ws/client.py +3 -0
- ccxt/async_support/binance.py +42 -1
- ccxt/async_support/bitmex.py +3 -3
- ccxt/async_support/bybit.py +83 -10
- ccxt/async_support/coinbase.py +4 -1
- ccxt/async_support/coinbaseexchange.py +53 -0
- ccxt/async_support/coincheck.py +45 -4
- ccxt/async_support/coinex.py +16 -12
- ccxt/async_support/coinmetro.py +15 -3
- ccxt/async_support/cryptomus.py +30 -52
- ccxt/async_support/deribit.py +6 -6
- ccxt/async_support/exmo.py +64 -52
- ccxt/async_support/htx.py +5 -1
- ccxt/async_support/hyperliquid.py +126 -33
- ccxt/async_support/kucoin.py +12 -14
- ccxt/async_support/latoken.py +19 -71
- ccxt/async_support/lbank.py +2 -2
- ccxt/async_support/okx.py +159 -3
- ccxt/async_support/paradex.py +54 -0
- ccxt/async_support/phemex.py +3 -3
- ccxt/async_support/wavesexchange.py +12 -2
- ccxt/base/exchange.py +96 -31
- ccxt/binance.py +42 -1
- ccxt/bitmex.py +3 -3
- ccxt/bybit.py +83 -10
- ccxt/coinbase.py +4 -1
- ccxt/coinbaseexchange.py +53 -0
- ccxt/coincheck.py +45 -4
- ccxt/coinex.py +16 -12
- ccxt/coinmetro.py +14 -3
- ccxt/cryptomus.py +30 -52
- ccxt/deribit.py +6 -6
- ccxt/exmo.py +64 -52
- ccxt/htx.py +5 -1
- ccxt/hyperliquid.py +126 -33
- ccxt/kucoin.py +12 -14
- ccxt/latoken.py +19 -71
- ccxt/lbank.py +2 -2
- ccxt/okx.py +159 -3
- ccxt/paradex.py +54 -0
- ccxt/phemex.py +3 -3
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/bitstamp.py +48 -16
- ccxt/pro/bybit.py +2 -1
- ccxt/test/tests_async.py +17 -15
- ccxt/test/tests_sync.py +17 -15
- ccxt/wavesexchange.py +12 -2
- {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/METADATA +4 -4
- {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/RECORD +58 -58
- {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/WHEEL +0 -0
- {ccxt-4.4.92.dist-info → ccxt-4.4.94.dist-info}/top_level.txt +0 -0
ccxt/async_support/lbank.py
CHANGED
@@ -138,7 +138,7 @@ class lbank(Exchange, ImplicitAPI):
|
|
138
138
|
'accuracy': 2.5,
|
139
139
|
'usdToCny': 2.5,
|
140
140
|
'assetConfigs': 2.5,
|
141
|
-
'withdrawConfigs': 2.5,
|
141
|
+
'withdrawConfigs': 2.5 * 1.5, # frequently rate-limits, so increase self endpoint RL
|
142
142
|
'timestamp': 2.5,
|
143
143
|
'ticker/24hr': 2.5,
|
144
144
|
'ticker': 2.5,
|
@@ -675,7 +675,7 @@ class lbank(Exchange, ImplicitAPI):
|
|
675
675
|
'active': True,
|
676
676
|
'contract': True,
|
677
677
|
'linear': True,
|
678
|
-
'inverse':
|
678
|
+
'inverse': False,
|
679
679
|
'contractSize': self.safe_number(market, 'volumeMultiple'),
|
680
680
|
'expiry': None,
|
681
681
|
'expiryDatetime': None,
|
ccxt/async_support/okx.py
CHANGED
@@ -81,6 +81,7 @@ class okx(Exchange, ImplicitAPI):
|
|
81
81
|
'createTriggerOrder': True,
|
82
82
|
'editOrder': True,
|
83
83
|
'fetchAccounts': True,
|
84
|
+
'fetchAllGreeks': True,
|
84
85
|
'fetchBalance': True,
|
85
86
|
'fetchBidsAsks': None,
|
86
87
|
'fetchBorrowInterest': True,
|
@@ -2556,11 +2557,11 @@ class okx(Exchange, ImplicitAPI):
|
|
2556
2557
|
# it may be incorrect to use total, free and used for swap accounts
|
2557
2558
|
eq = self.safe_string(balance, 'eq')
|
2558
2559
|
availEq = self.safe_string(balance, 'availEq')
|
2559
|
-
|
2560
|
+
account['total'] = eq
|
2561
|
+
if availEq is None:
|
2560
2562
|
account['free'] = self.safe_string(balance, 'availBal')
|
2561
2563
|
account['used'] = self.safe_string(balance, 'frozenBal')
|
2562
2564
|
else:
|
2563
|
-
account['total'] = eq
|
2564
2565
|
account['free'] = availEq
|
2565
2566
|
result[code] = account
|
2566
2567
|
result['timestamp'] = timestamp
|
@@ -2958,7 +2959,8 @@ class okx(Exchange, ImplicitAPI):
|
|
2958
2959
|
stopLossTriggerPrice = self.safe_value_n(stopLoss, ['triggerPrice', 'stopPrice', 'slTriggerPx'])
|
2959
2960
|
if stopLossTriggerPrice is None:
|
2960
2961
|
raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["stopLoss"]["triggerPrice"], or params["stopLoss"]["stopPrice"], or params["stopLoss"]["slTriggerPx"] for a stop loss order')
|
2961
|
-
|
2962
|
+
slTriggerPx = self.price_to_precision(symbol, stopLossTriggerPrice)
|
2963
|
+
request['slTriggerPx'] = slTriggerPx
|
2962
2964
|
stopLossLimitPrice = self.safe_value_n(stopLoss, ['price', 'stopLossPrice', 'slOrdPx'])
|
2963
2965
|
stopLossOrderType = self.safe_string(stopLoss, 'type')
|
2964
2966
|
if stopLossOrderType is not None:
|
@@ -3024,6 +3026,12 @@ class okx(Exchange, ImplicitAPI):
|
|
3024
3026
|
# tpOrdKind is 'condition' which is the default
|
3025
3027
|
if twoWayCondition:
|
3026
3028
|
request['ordType'] = 'oco'
|
3029
|
+
if side == 'sell':
|
3030
|
+
request = self.omit(request, 'tgtCcy')
|
3031
|
+
if self.safe_string(request, 'tdMode') == 'cash':
|
3032
|
+
# for some reason tdMode = cash throws
|
3033
|
+
# {"code":"1","data":[{"algoClOrdId":"","algoId":"","clOrdId":"","sCode":"51000","sMsg":"Parameter tdMode error ","tag":""}],"msg":""}
|
3034
|
+
request['tdMode'] = marginMode
|
3027
3035
|
if takeProfitPrice is not None:
|
3028
3036
|
request['tpTriggerPx'] = self.price_to_precision(symbol, takeProfitPrice)
|
3029
3037
|
tpOrdPxReq = '-1'
|
@@ -3614,6 +3622,84 @@ class okx(Exchange, ImplicitAPI):
|
|
3614
3622
|
# "uTime": "1621910749815"
|
3615
3623
|
# }
|
3616
3624
|
#
|
3625
|
+
# watchOrders & fetchClosedOrders
|
3626
|
+
#
|
3627
|
+
# {
|
3628
|
+
# "algoClOrdId": "",
|
3629
|
+
# "algoId": "",
|
3630
|
+
# "attachAlgoClOrdId": "",
|
3631
|
+
# "attachAlgoOrds": [],
|
3632
|
+
# "cancelSource": "",
|
3633
|
+
# "cancelSourceReason": "", # not present in WS, but present in fetchClosedOrders
|
3634
|
+
# "category": "normal",
|
3635
|
+
# "ccy": "", # empty in WS, but eg. `USDT` in fetchClosedOrders
|
3636
|
+
# "clOrdId": "",
|
3637
|
+
# "cTime": "1751705801423",
|
3638
|
+
# "feeCcy": "USDT",
|
3639
|
+
# "instId": "LINK-USDT-SWAP",
|
3640
|
+
# "instType": "SWAP",
|
3641
|
+
# "isTpLimit": "false",
|
3642
|
+
# "lever": "3",
|
3643
|
+
# "linkedAlgoOrd": {"algoId": ""},
|
3644
|
+
# "ordId": "2657625147249614848",
|
3645
|
+
# "ordType": "limit",
|
3646
|
+
# "posSide": "net",
|
3647
|
+
# "px": "13.142",
|
3648
|
+
# "pxType": "",
|
3649
|
+
# "pxUsd": "",
|
3650
|
+
# "pxVol": "",
|
3651
|
+
# "quickMgnType": "",
|
3652
|
+
# "rebate": "0",
|
3653
|
+
# "rebateCcy": "USDT",
|
3654
|
+
# "reduceOnly": "true",
|
3655
|
+
# "side": "sell",
|
3656
|
+
# "slOrdPx": "",
|
3657
|
+
# "slTriggerPx": "",
|
3658
|
+
# "slTriggerPxType": "",
|
3659
|
+
# "source": "",
|
3660
|
+
# "stpId": "",
|
3661
|
+
# "stpMode": "cancel_maker",
|
3662
|
+
# "sz": "0.1",
|
3663
|
+
# "tag": "",
|
3664
|
+
# "tdMode": "isolated",
|
3665
|
+
# "tgtCcy": "",
|
3666
|
+
# "tpOrdPx": "",
|
3667
|
+
# "tpTriggerPx": "",
|
3668
|
+
# "tpTriggerPxType": "",
|
3669
|
+
# "uTime": "1751705807467",
|
3670
|
+
# "reqId": "", # field present only in WS
|
3671
|
+
# "msg": "", # field present only in WS
|
3672
|
+
# "amendResult": "", # field present only in WS
|
3673
|
+
# "amendSource": "", # field present only in WS
|
3674
|
+
# "code": "0", # field present only in WS
|
3675
|
+
# "fillFwdPx": "", # field present only in WS
|
3676
|
+
# "fillMarkVol": "", # field present only in WS
|
3677
|
+
# "fillPxUsd": "", # field present only in WS
|
3678
|
+
# "fillPxVol": "", # field present only in WS
|
3679
|
+
# "lastPx": "13.142", # field present only in WS
|
3680
|
+
# "notionalUsd": "1.314515408", # field present only in WS
|
3681
|
+
#
|
3682
|
+
# #### these below fields are empty on first omit from websocket, because of "creation" event. however, if order is executed, it also immediately sends another update with these fields filled ###
|
3683
|
+
#
|
3684
|
+
# "pnl": "-0.0001",
|
3685
|
+
# "accFillSz": "0.1",
|
3686
|
+
# "avgPx": "13.142",
|
3687
|
+
# "state": "filled",
|
3688
|
+
# "fee": "-0.00026284",
|
3689
|
+
# "fillPx": "13.142",
|
3690
|
+
# "tradeId": "293429690",
|
3691
|
+
# "fillSz": "0.1",
|
3692
|
+
# "fillTime": "1751705807467",
|
3693
|
+
# "fillNotionalUsd": "1.314515408", # field present only in WS
|
3694
|
+
# "fillPnl": "-0.0001", # field present only in WS
|
3695
|
+
# "fillFee": "-0.00026284", # field present only in WS
|
3696
|
+
# "fillFeeCcy": "USDT", # field present only in WS
|
3697
|
+
# "execType": "M", # field present only in WS
|
3698
|
+
# "fillMarkPx": "13.141", # field present only in WS
|
3699
|
+
# "fillIdxPx": "13.147" # field present only in WS
|
3700
|
+
# }
|
3701
|
+
#
|
3702
|
+
#
|
3617
3703
|
# Algo Order fetchOpenOrders, fetchCanceledOrders, fetchClosedOrders
|
3618
3704
|
#
|
3619
3705
|
# {
|
@@ -7548,6 +7634,76 @@ class okx(Exchange, ImplicitAPI):
|
|
7548
7634
|
return self.parse_greeks(entry, market)
|
7549
7635
|
return None
|
7550
7636
|
|
7637
|
+
async def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
|
7638
|
+
"""
|
7639
|
+
fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
|
7640
|
+
|
7641
|
+
https://www.okx.com/docs-v5/en/#public-data-rest-api-get-option-market-data
|
7642
|
+
|
7643
|
+
:param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
|
7644
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
7645
|
+
:param str params['uly']: Underlying, either uly or instFamily is required
|
7646
|
+
:param str params['instFamily']: Instrument family, either uly or instFamily is required
|
7647
|
+
:returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
|
7648
|
+
"""
|
7649
|
+
await self.load_markets()
|
7650
|
+
request: dict = {}
|
7651
|
+
symbols = self.market_symbols(symbols, None, True, True, True)
|
7652
|
+
symbolsLength = None
|
7653
|
+
if symbols is not None:
|
7654
|
+
symbolsLength = len(symbols)
|
7655
|
+
if (symbols is None) or (symbolsLength != 1):
|
7656
|
+
uly = self.safe_string(params, 'uly')
|
7657
|
+
if uly is not None:
|
7658
|
+
request['uly'] = uly
|
7659
|
+
instFamily = self.safe_string(params, 'instFamily')
|
7660
|
+
if instFamily is not None:
|
7661
|
+
request['instFamily'] = instFamily
|
7662
|
+
if (uly is None) and (instFamily is None):
|
7663
|
+
raise BadRequest(self.id + ' fetchAllGreeks() requires either a uly or instFamily parameter')
|
7664
|
+
market = None
|
7665
|
+
if symbols is not None:
|
7666
|
+
if symbolsLength == 1:
|
7667
|
+
market = self.market(symbols[0])
|
7668
|
+
marketId = market['id']
|
7669
|
+
optionParts = marketId.split('-')
|
7670
|
+
request['uly'] = market['info']['uly']
|
7671
|
+
request['instFamily'] = market['info']['instFamily']
|
7672
|
+
request['expTime'] = self.safe_string(optionParts, 2)
|
7673
|
+
params = self.omit(params, ['uly', 'instFamily'])
|
7674
|
+
response = await self.publicGetPublicOptSummary(self.extend(request, params))
|
7675
|
+
#
|
7676
|
+
# {
|
7677
|
+
# "code": "0",
|
7678
|
+
# "data": [
|
7679
|
+
# {
|
7680
|
+
# "askVol": "0",
|
7681
|
+
# "bidVol": "0",
|
7682
|
+
# "delta": "0.5105464486882039",
|
7683
|
+
# "deltaBS": "0.7325502184143025",
|
7684
|
+
# "fwdPx": "37675.80158694987186",
|
7685
|
+
# "gamma": "-0.13183515090501083",
|
7686
|
+
# "gammaBS": "0.000024139685826358558",
|
7687
|
+
# "instId": "BTC-USD-240329-32000-C",
|
7688
|
+
# "instType": "OPTION",
|
7689
|
+
# "lever": "4.504428015946619",
|
7690
|
+
# "markVol": "0.5916253554539876",
|
7691
|
+
# "realVol": "0",
|
7692
|
+
# "theta": "-0.0004202992014012855",
|
7693
|
+
# "thetaBS": "-18.52354631567909",
|
7694
|
+
# "ts": "1699586421976",
|
7695
|
+
# "uly": "BTC-USD",
|
7696
|
+
# "vega": "0.0020207455080045846",
|
7697
|
+
# "vegaBS": "74.44022302387287",
|
7698
|
+
# "volLv": "0.5948549730405797"
|
7699
|
+
# },
|
7700
|
+
# ],
|
7701
|
+
# "msg": ""
|
7702
|
+
# }
|
7703
|
+
#
|
7704
|
+
data = self.safe_list(response, 'data', [])
|
7705
|
+
return self.parse_all_greeks(data, symbols)
|
7706
|
+
|
7551
7707
|
def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
|
7552
7708
|
#
|
7553
7709
|
# {
|
ccxt/async_support/paradex.py
CHANGED
@@ -57,6 +57,7 @@ class paradex(Exchange, ImplicitAPI):
|
|
57
57
|
'createTriggerOrder': True,
|
58
58
|
'editOrder': False,
|
59
59
|
'fetchAccounts': False,
|
60
|
+
'fetchAllGreeks': True,
|
60
61
|
'fetchBalance': True,
|
61
62
|
'fetchBorrowInterest': False,
|
62
63
|
'fetchBorrowRateHistories': False,
|
@@ -2346,6 +2347,59 @@ class paradex(Exchange, ImplicitAPI):
|
|
2346
2347
|
greeks = self.safe_dict(data, 0, {})
|
2347
2348
|
return self.parse_greeks(greeks, market)
|
2348
2349
|
|
2350
|
+
async def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
|
2351
|
+
"""
|
2352
|
+
fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
|
2353
|
+
|
2354
|
+
https://docs.api.testnet.paradex.trade/#list-available-markets-summary
|
2355
|
+
|
2356
|
+
:param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
|
2357
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2358
|
+
:returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
|
2359
|
+
"""
|
2360
|
+
await self.load_markets()
|
2361
|
+
symbols = self.market_symbols(symbols, None, True, True, True)
|
2362
|
+
request: dict = {
|
2363
|
+
'market': 'ALL',
|
2364
|
+
}
|
2365
|
+
response = await self.publicGetMarketsSummary(self.extend(request, params))
|
2366
|
+
#
|
2367
|
+
# {
|
2368
|
+
# "results": [
|
2369
|
+
# {
|
2370
|
+
# "symbol": "BTC-USD-114000-P",
|
2371
|
+
# "mark_price": "10835.66892602",
|
2372
|
+
# "mark_iv": "0.71781855",
|
2373
|
+
# "delta": "-0.98726024",
|
2374
|
+
# "greeks": {
|
2375
|
+
# "delta": "-0.9872602390817709",
|
2376
|
+
# "gamma": "0.000004560958862297231",
|
2377
|
+
# "vega": "227.11344863639806",
|
2378
|
+
# "rho": "-302.0617972461581",
|
2379
|
+
# "vanna": "0.06609830491614832",
|
2380
|
+
# "volga": "925.9501532805552"
|
2381
|
+
# },
|
2382
|
+
# "last_traded_price": "10551.5",
|
2383
|
+
# "bid": "10794.9",
|
2384
|
+
# "bid_iv": "0.05",
|
2385
|
+
# "ask": "10887.3",
|
2386
|
+
# "ask_iv": "0.8783283",
|
2387
|
+
# "last_iv": "0.05",
|
2388
|
+
# "volume_24h": "0",
|
2389
|
+
# "total_volume": "195240.72672261014",
|
2390
|
+
# "created_at": 1747644009995,
|
2391
|
+
# "underlying_price": "103164.79162649",
|
2392
|
+
# "open_interest": "0",
|
2393
|
+
# "funding_rate": "0.000004464241170536191",
|
2394
|
+
# "price_change_rate_24h": "0.074915",
|
2395
|
+
# "future_funding_rate": "0.0001"
|
2396
|
+
# }
|
2397
|
+
# ]
|
2398
|
+
# }
|
2399
|
+
#
|
2400
|
+
results = self.safe_list(response, 'results', [])
|
2401
|
+
return self.parse_all_greeks(results, symbols)
|
2402
|
+
|
2349
2403
|
def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
|
2350
2404
|
#
|
2351
2405
|
# {
|
ccxt/async_support/phemex.py
CHANGED
@@ -2659,14 +2659,14 @@ class phemex(Exchange, ImplicitAPI):
|
|
2659
2659
|
triggerDirection = None
|
2660
2660
|
triggerDirection, params = self.handle_param_string(params, 'triggerDirection')
|
2661
2661
|
if triggerDirection is None:
|
2662
|
-
raise ArgumentsRequired(self.id + " createOrder() also requires a 'triggerDirection' parameter with either '
|
2662
|
+
raise ArgumentsRequired(self.id + " createOrder() also requires a 'triggerDirection' parameter with either 'ascending' or 'descending' value")
|
2663
2663
|
# the flow defined per https://phemex-docs.github.io/#more-order-type-examples
|
2664
|
-
if triggerDirection == 'up':
|
2664
|
+
if triggerDirection == 'ascending' or triggerDirection == 'up':
|
2665
2665
|
if side == 'sell':
|
2666
2666
|
request['ordType'] = 'MarketIfTouched' if (type == 'Market') else 'LimitIfTouched'
|
2667
2667
|
elif side == 'buy':
|
2668
2668
|
request['ordType'] = 'Stop' if (type == 'Market') else 'StopLimit'
|
2669
|
-
elif triggerDirection == 'down':
|
2669
|
+
elif triggerDirection == 'descending' or triggerDirection == 'down':
|
2670
2670
|
if side == 'sell':
|
2671
2671
|
request['ordType'] = 'Stop' if (type == 'Market') else 'StopLimit'
|
2672
2672
|
elif side == 'buy':
|
@@ -2215,11 +2215,21 @@ class wavesexchange(Exchange, ImplicitAPI):
|
|
2215
2215
|
order1 = self.safe_value(data, 'order1')
|
2216
2216
|
order2 = self.safe_value(data, 'order2')
|
2217
2217
|
order = None
|
2218
|
-
#
|
2218
|
+
# at first, detect if response is from `fetch_my_trades`
|
2219
2219
|
if self.safe_string(order1, 'senderPublicKey') == self.apiKey:
|
2220
2220
|
order = order1
|
2221
|
-
|
2221
|
+
elif self.safe_string(order2, 'senderPublicKey') == self.apiKey:
|
2222
2222
|
order = order2
|
2223
|
+
else:
|
2224
|
+
# response is from `fetch_trades`, so find only taker order
|
2225
|
+
date1 = self.safe_string(order1, 'timestamp')
|
2226
|
+
date2 = self.safe_string(order2, 'timestamp')
|
2227
|
+
ts1 = self.parse8601(date1)
|
2228
|
+
ts2 = self.parse8601(date2)
|
2229
|
+
if ts1 > ts2:
|
2230
|
+
order = order1
|
2231
|
+
else:
|
2232
|
+
order = order2
|
2223
2233
|
symbol = None
|
2224
2234
|
assetPair = self.safe_value(order, 'assetPair')
|
2225
2235
|
if assetPair is not None:
|
ccxt/base/exchange.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
|
7
|
-
__version__ = '4.4.
|
7
|
+
__version__ = '4.4.94'
|
8
8
|
|
9
9
|
# -----------------------------------------------------------------------------
|
10
10
|
|
@@ -3808,8 +3808,7 @@ class Exchange(object):
|
|
3808
3808
|
|
3809
3809
|
def safe_ticker(self, ticker: dict, market: Market = None):
|
3810
3810
|
open = self.omit_zero(self.safe_string(ticker, 'open'))
|
3811
|
-
close = self.omit_zero(self.
|
3812
|
-
last = self.omit_zero(self.safe_string(ticker, 'last'))
|
3811
|
+
close = self.omit_zero(self.safe_string_2(ticker, 'close', 'last'))
|
3813
3812
|
change = self.omit_zero(self.safe_string(ticker, 'change'))
|
3814
3813
|
percentage = self.omit_zero(self.safe_string(ticker, 'percentage'))
|
3815
3814
|
average = self.omit_zero(self.safe_string(ticker, 'average'))
|
@@ -3818,29 +3817,52 @@ class Exchange(object):
|
|
3818
3817
|
quoteVolume = self.safe_string(ticker, 'quoteVolume')
|
3819
3818
|
if vwap is None:
|
3820
3819
|
vwap = Precise.string_div(self.omit_zero(quoteVolume), baseVolume)
|
3821
|
-
|
3822
|
-
|
3823
|
-
|
3824
|
-
|
3825
|
-
|
3826
|
-
|
3827
|
-
|
3828
|
-
if average is None:
|
3820
|
+
# calculate open
|
3821
|
+
if change is not None:
|
3822
|
+
if close is None and average is not None:
|
3823
|
+
close = Precise.string_add(average, Precise.string_div(change, '2'))
|
3824
|
+
if open is None and close is not None:
|
3825
|
+
open = Precise.string_sub(close, change)
|
3826
|
+
elif percentage is not None:
|
3827
|
+
if close is None and average is not None:
|
3828
|
+
openAddClose = Precise.string_mul(average, '2')
|
3829
|
+
# openAddClose = open * (1 + (100 + percentage)/100)
|
3830
|
+
denominator = Precise.string_add('2', Precise.string_div(percentage, '100'))
|
3831
|
+
calcOpen = open if (open is not None) else Precise.string_div(openAddClose, denominator)
|
3832
|
+
close = Precise.string_mul(calcOpen, Precise.string_add('1', Precise.string_div(percentage, '100')))
|
3833
|
+
if open is None and close is not None:
|
3834
|
+
open = Precise.string_div(close, Precise.string_add('1', Precise.string_div(percentage, '100')))
|
3835
|
+
# change
|
3836
|
+
if change is None:
|
3837
|
+
if close is not None and open is not None:
|
3838
|
+
change = Precise.string_sub(close, open)
|
3839
|
+
elif close is not None and percentage is not None:
|
3840
|
+
change = Precise.string_mul(Precise.string_div(percentage, '100'), Precise.string_div(close, '100'))
|
3841
|
+
elif open is not None and percentage is not None:
|
3842
|
+
change = Precise.string_mul(open, Precise.string_div(percentage, '100'))
|
3843
|
+
# calculate things according to "open"(similar can be done with "close")
|
3844
|
+
if open is not None:
|
3845
|
+
# percentage(using change)
|
3846
|
+
if percentage is None and change is not None:
|
3847
|
+
percentage = Precise.string_mul(Precise.string_div(change, open), '100')
|
3848
|
+
# close(using change)
|
3849
|
+
if close is None and change is not None:
|
3850
|
+
close = Precise.string_add(open, change)
|
3851
|
+
# close(using average)
|
3852
|
+
if close is None and average is not None:
|
3853
|
+
close = Precise.string_mul(average, '2')
|
3854
|
+
# average
|
3855
|
+
if average is None and close is not None:
|
3829
3856
|
precision = 18
|
3830
3857
|
if market is not None and self.is_tick_precision():
|
3831
3858
|
marketPrecision = self.safe_dict(market, 'precision')
|
3832
3859
|
precisionPrice = self.safe_string(marketPrecision, 'price')
|
3833
3860
|
if precisionPrice is not None:
|
3834
3861
|
precision = self.precision_from_string(precisionPrice)
|
3835
|
-
average = Precise.string_div(Precise.string_add(
|
3836
|
-
if (percentage is None) and (change is not None) and (open is not None) and Precise.string_gt(open, '0'):
|
3837
|
-
percentage = Precise.string_mul(Precise.string_div(change, open), '100')
|
3838
|
-
if (change is None) and (percentage is not None) and (open is not None):
|
3839
|
-
change = Precise.string_div(Precise.string_mul(percentage, open), '100')
|
3840
|
-
if (open is None) and (last is not None) and (change is not None):
|
3841
|
-
open = Precise.string_sub(last, change)
|
3862
|
+
average = Precise.string_div(Precise.string_add(open, close), '2', precision)
|
3842
3863
|
# timestamp and symbol operations don't belong in safeTicker
|
3843
3864
|
# they should be done in the derived classes
|
3865
|
+
closeParsed = self.parse_number(self.omit_zero(close))
|
3844
3866
|
return self.extend(ticker, {
|
3845
3867
|
'bid': self.parse_number(self.omit_zero(self.safe_string(ticker, 'bid'))),
|
3846
3868
|
'bidVolume': self.safe_number(ticker, 'bidVolume'),
|
@@ -3849,8 +3871,8 @@ class Exchange(object):
|
|
3849
3871
|
'high': self.parse_number(self.omit_zero(self.safe_string(ticker, 'high'))),
|
3850
3872
|
'low': self.parse_number(self.omit_zero(self.safe_string(ticker, 'low'))),
|
3851
3873
|
'open': self.parse_number(self.omit_zero(open)),
|
3852
|
-
'close':
|
3853
|
-
'last':
|
3874
|
+
'close': closeParsed,
|
3875
|
+
'last': closeParsed,
|
3854
3876
|
'change': self.parse_number(change),
|
3855
3877
|
'percentage': self.parse_number(percentage),
|
3856
3878
|
'average': self.parse_number(average),
|
@@ -4229,7 +4251,7 @@ class Exchange(object):
|
|
4229
4251
|
return self.filter_by_since_limit(sorted, since, limit, 0, tail)
|
4230
4252
|
|
4231
4253
|
def parse_leverage_tiers(self, response: Any, symbols: List[str] = None, marketIdKey=None):
|
4232
|
-
# marketIdKey should only be None when response is a dictionary
|
4254
|
+
# marketIdKey should only be None when response is a dictionary.
|
4233
4255
|
symbols = self.market_symbols(symbols)
|
4234
4256
|
tiers = {}
|
4235
4257
|
symbolsLength = 0
|
@@ -5450,6 +5472,9 @@ class Exchange(object):
|
|
5450
5472
|
def fetch_greeks(self, symbol: str, params={}):
|
5451
5473
|
raise NotSupported(self.id + ' fetchGreeks() is not supported yet')
|
5452
5474
|
|
5475
|
+
def fetch_all_greeks(self, symbols: Strings = None, params={}):
|
5476
|
+
raise NotSupported(self.id + ' fetchAllGreeks() is not supported yet')
|
5477
|
+
|
5453
5478
|
def fetch_option_chain(self, code: str, params={}):
|
5454
5479
|
raise NotSupported(self.id + ' fetchOptionChain() is not supported yet')
|
5455
5480
|
|
@@ -5703,10 +5728,16 @@ class Exchange(object):
|
|
5703
5728
|
precisionNumber = int(precision)
|
5704
5729
|
if precisionNumber == 0:
|
5705
5730
|
return '1'
|
5706
|
-
|
5707
|
-
|
5708
|
-
|
5709
|
-
|
5731
|
+
if precisionNumber > 0:
|
5732
|
+
parsedPrecision = '0.'
|
5733
|
+
for i in range(0, precisionNumber - 1):
|
5734
|
+
parsedPrecision = parsedPrecision + '0'
|
5735
|
+
return parsedPrecision + '1'
|
5736
|
+
else:
|
5737
|
+
parsedPrecision = '1'
|
5738
|
+
for i in range(0, precisionNumber * -1 - 1):
|
5739
|
+
parsedPrecision = parsedPrecision + '0'
|
5740
|
+
return parsedPrecision + '0'
|
5710
5741
|
|
5711
5742
|
def integer_precision_to_amount(self, precision: Str):
|
5712
5743
|
"""
|
@@ -6682,6 +6713,27 @@ class Exchange(object):
|
|
6682
6713
|
def parse_greeks(self, greeks: dict, market: Market = None):
|
6683
6714
|
raise NotSupported(self.id + ' parseGreeks() is not supported yet')
|
6684
6715
|
|
6716
|
+
def parse_all_greeks(self, greeks, symbols: Strings = None, params={}):
|
6717
|
+
#
|
6718
|
+
# the value of greeks is either a dict or a list
|
6719
|
+
#
|
6720
|
+
results = []
|
6721
|
+
if isinstance(greeks, list):
|
6722
|
+
for i in range(0, len(greeks)):
|
6723
|
+
parsedTicker = self.parse_greeks(greeks[i])
|
6724
|
+
greek = self.extend(parsedTicker, params)
|
6725
|
+
results.append(greek)
|
6726
|
+
else:
|
6727
|
+
marketIds = list(greeks.keys())
|
6728
|
+
for i in range(0, len(marketIds)):
|
6729
|
+
marketId = marketIds[i]
|
6730
|
+
market = self.safe_market(marketId)
|
6731
|
+
parsed = self.parse_greeks(greeks[marketId], market)
|
6732
|
+
greek = self.extend(parsed, params)
|
6733
|
+
results.append(greek)
|
6734
|
+
symbols = self.market_symbols(symbols)
|
6735
|
+
return self.filter_by_array(results, 'symbol', symbols)
|
6736
|
+
|
6685
6737
|
def parse_option(self, chain: dict, currency: Currency = None, market: Market = None):
|
6686
6738
|
raise NotSupported(self.id + ' parseOption() is not supported yet')
|
6687
6739
|
|
@@ -6883,14 +6935,27 @@ class Exchange(object):
|
|
6883
6935
|
"""
|
6884
6936
|
raise NotSupported(self.id + ' fetchTransfers() is not supported yet')
|
6885
6937
|
|
6886
|
-
def clean_unsubscription(self, client, subHash: str, unsubHash: str):
|
6938
|
+
def clean_unsubscription(self, client, subHash: str, unsubHash: str, subHashIsPrefix=False):
|
6887
6939
|
if unsubHash in client.subscriptions:
|
6888
6940
|
del client.subscriptions[unsubHash]
|
6889
|
-
if
|
6890
|
-
|
6891
|
-
|
6892
|
-
|
6893
|
-
|
6941
|
+
if not subHashIsPrefix:
|
6942
|
+
if subHash in client.subscriptions:
|
6943
|
+
del client.subscriptions[subHash]
|
6944
|
+
if subHash in client.futures:
|
6945
|
+
error = UnsubscribeError(self.id + ' ' + subHash)
|
6946
|
+
client.reject(error, subHash)
|
6947
|
+
else:
|
6948
|
+
clientSubscriptions = list(client.subscriptions.keys())
|
6949
|
+
for i in range(0, len(clientSubscriptions)):
|
6950
|
+
sub = clientSubscriptions[i]
|
6951
|
+
if sub.startswith(subHash):
|
6952
|
+
del client.subscriptions[sub]
|
6953
|
+
clientFutures = list(client.futures.keys())
|
6954
|
+
for i in range(0, len(clientFutures)):
|
6955
|
+
future = clientFutures[i]
|
6956
|
+
if future.startswith(subHash):
|
6957
|
+
error = UnsubscribeError(self.id + ' ' + future)
|
6958
|
+
client.reject(error, future)
|
6894
6959
|
client.resolve(True, unsubHash)
|
6895
6960
|
|
6896
6961
|
def clean_cache(self, subscription: dict):
|
ccxt/binance.py
CHANGED
@@ -87,6 +87,7 @@ class binance(Exchange, ImplicitAPI):
|
|
87
87
|
'editOrder': True,
|
88
88
|
'editOrders': True,
|
89
89
|
'fetchAccounts': None,
|
90
|
+
'fetchAllGreeks': True,
|
90
91
|
'fetchBalance': True,
|
91
92
|
'fetchBidsAsks': True,
|
92
93
|
'fetchBorrowInterest': True,
|
@@ -10777,6 +10778,7 @@ class binance(Exchange, ImplicitAPI):
|
|
10777
10778
|
request: dict = {}
|
10778
10779
|
if symbol is not None:
|
10779
10780
|
request['symbol'] = market['id']
|
10781
|
+
symbol = market['symbol']
|
10780
10782
|
if since is not None:
|
10781
10783
|
request['startTime'] = since
|
10782
10784
|
if limit is not None:
|
@@ -10804,7 +10806,7 @@ class binance(Exchange, ImplicitAPI):
|
|
10804
10806
|
#
|
10805
10807
|
settlements = self.parse_settlements(response, market)
|
10806
10808
|
sorted = self.sort_by(settlements, 'timestamp')
|
10807
|
-
return self.filter_by_symbol_since_limit(sorted,
|
10809
|
+
return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
|
10808
10810
|
|
10809
10811
|
def parse_settlement(self, settlement, market):
|
10810
10812
|
#
|
@@ -12422,6 +12424,45 @@ class binance(Exchange, ImplicitAPI):
|
|
12422
12424
|
#
|
12423
12425
|
return self.parse_greeks(response[0], market)
|
12424
12426
|
|
12427
|
+
def fetch_all_greeks(self, symbols: Strings = None, params={}) -> List[Greeks]:
|
12428
|
+
"""
|
12429
|
+
fetches all option contracts greeks, financial metrics used to measure the factors that affect the price of an options contract
|
12430
|
+
|
12431
|
+
https://developers.binance.com/docs/derivatives/option/market-data/Option-Mark-Price
|
12432
|
+
|
12433
|
+
:param str[] [symbols]: unified symbols of the markets to fetch greeks for, all markets are returned if not assigned
|
12434
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
12435
|
+
:returns dict: a `greeks structure <https://docs.ccxt.com/#/?id=greeks-structure>`
|
12436
|
+
"""
|
12437
|
+
self.load_markets()
|
12438
|
+
symbols = self.market_symbols(symbols, None, True, True, True)
|
12439
|
+
request: dict = {}
|
12440
|
+
market = None
|
12441
|
+
if symbols is not None:
|
12442
|
+
symbolsLength = len(symbols)
|
12443
|
+
if symbolsLength == 1:
|
12444
|
+
market = self.market(symbols[0])
|
12445
|
+
request['symbol'] = market['id']
|
12446
|
+
response = self.eapiPublicGetMark(self.extend(request, params))
|
12447
|
+
#
|
12448
|
+
# [
|
12449
|
+
# {
|
12450
|
+
# "symbol": "BTC-231229-40000-C",
|
12451
|
+
# "markPrice": "2012",
|
12452
|
+
# "bidIV": "0.60236275",
|
12453
|
+
# "askIV": "0.62267244",
|
12454
|
+
# "markIV": "0.6125176",
|
12455
|
+
# "delta": "0.39111646",
|
12456
|
+
# "theta": "-32.13948531",
|
12457
|
+
# "gamma": "0.00004656",
|
12458
|
+
# "vega": "51.70062218",
|
12459
|
+
# "highPriceLimit": "6474",
|
12460
|
+
# "lowPriceLimit": "5"
|
12461
|
+
# }
|
12462
|
+
# ]
|
12463
|
+
#
|
12464
|
+
return self.parse_all_greeks(response, symbols)
|
12465
|
+
|
12425
12466
|
def parse_greeks(self, greeks: dict, market: Market = None) -> Greeks:
|
12426
12467
|
#
|
12427
12468
|
# {
|
ccxt/bitmex.py
CHANGED
@@ -1924,7 +1924,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1924
1924
|
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
1925
1925
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1926
1926
|
:param dict [params.triggerPrice]: the price at which a trigger order is triggered at
|
1927
|
-
:param dict [params.triggerDirection]: the direction whenever the trigger happens with relation to price - '
|
1927
|
+
:param dict [params.triggerDirection]: the direction whenever the trigger happens with relation to price - 'ascending' or 'descending'
|
1928
1928
|
:param float [params.trailingAmount]: the quote amount to trail away from the current market price
|
1929
1929
|
:returns dict: an `order structure <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
|
1930
1930
|
"""
|
@@ -1951,7 +1951,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1951
1951
|
isTrailingAmountOrder = trailingAmount is not None
|
1952
1952
|
if isTriggerOrder or isTrailingAmountOrder:
|
1953
1953
|
triggerDirection = self.safe_string(params, 'triggerDirection')
|
1954
|
-
triggerAbove = (triggerDirection == 'above')
|
1954
|
+
triggerAbove = ((triggerDirection == 'ascending') or (triggerDirection == 'above'))
|
1955
1955
|
if (type == 'limit') or (type == 'market'):
|
1956
1956
|
self.check_required_argument('createOrder', triggerDirection, 'triggerDirection', ['above', 'below'])
|
1957
1957
|
if type == 'limit':
|
@@ -1994,7 +1994,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1994
1994
|
isTrailingAmountOrder = trailingAmount is not None
|
1995
1995
|
if isTrailingAmountOrder:
|
1996
1996
|
triggerDirection = self.safe_string(params, 'triggerDirection')
|
1997
|
-
triggerAbove = (triggerDirection == 'above')
|
1997
|
+
triggerAbove = ((triggerDirection == 'ascending') or (triggerDirection == 'above'))
|
1998
1998
|
if (type == 'limit') or (type == 'market'):
|
1999
1999
|
self.check_required_argument('createOrder', triggerDirection, 'triggerDirection', ['above', 'below'])
|
2000
2000
|
orderType = None
|