feat: add method to fetch binance funding fees
which is necessary to calculate accurate liquidation prices
This commit is contained in:
@@ -144,6 +144,27 @@ class Binance(Exchange):
|
|||||||
"""
|
"""
|
||||||
return open_date.minute == 0 and open_date.second < 15
|
return open_date.minute == 0 and open_date.second < 15
|
||||||
|
|
||||||
|
def fetch_funding_rates(self, symbols: Optional[List[str]] = None) -> Dict[str, float]:
|
||||||
|
"""
|
||||||
|
Fetch funding rates for the given symbols.
|
||||||
|
:param symbols: List of symbols to fetch funding rates for
|
||||||
|
:return: Dict of funding rates for the given symbols
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if self.trading_mode == TradingMode.FUTURES:
|
||||||
|
rates = self._api.fetch_funding_rates(symbols)
|
||||||
|
return rates
|
||||||
|
return {}
|
||||||
|
except ccxt.DDoSProtection as e:
|
||||||
|
raise DDosProtection(e) from e
|
||||||
|
except (ccxt.OperationFailed, ccxt.ExchangeError) as e:
|
||||||
|
raise TemporaryError(
|
||||||
|
f"Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}"
|
||||||
|
) from e
|
||||||
|
|
||||||
|
except ccxt.BaseError as e:
|
||||||
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
def dry_run_liquidation_price(
|
def dry_run_liquidation_price(
|
||||||
self,
|
self,
|
||||||
pair: str,
|
pair: str,
|
||||||
@@ -191,19 +212,20 @@ class Binance(Exchange):
|
|||||||
if self.margin_mode == MarginMode.CROSS:
|
if self.margin_mode == MarginMode.CROSS:
|
||||||
mm_ex_1: float = 0.0
|
mm_ex_1: float = 0.0
|
||||||
upnl_ex_1: float = 0.0
|
upnl_ex_1: float = 0.0
|
||||||
|
pairs = [trade["pair"] for trade in open_trades]
|
||||||
|
funding_rates = self.fetch_funding_rates(pairs)
|
||||||
for trade in open_trades:
|
for trade in open_trades:
|
||||||
if trade["pair"] == pair:
|
if trade["pair"] == pair:
|
||||||
# Only "other" trades are considered
|
# Only "other" trades are considered
|
||||||
continue
|
continue
|
||||||
|
mark_price = funding_rates[trade["pair"]]["markPrice"]
|
||||||
mm_ratio1, maint_amnt1 = self.get_maintenance_ratio_and_amt(
|
mm_ratio1, maint_amnt1 = self.get_maintenance_ratio_and_amt(
|
||||||
trade["pair"], trade["stake_amount"]
|
trade["pair"], trade["stake_amount"]
|
||||||
)
|
)
|
||||||
maint_margin = trade["amount"] * trade["mark_price"] * mm_ratio1 - maint_amnt1
|
maint_margin = trade["amount"] * mark_price * mm_ratio1 - maint_amnt1
|
||||||
mm_ex_1 += maint_margin
|
mm_ex_1 += maint_margin
|
||||||
|
|
||||||
upnl_ex_1 += (
|
upnl_ex_1 += trade["amount"] * mark_price - trade["amount"] * trade["open_rate"]
|
||||||
trade["amount"] * trade["mark_price"] - trade["amount"] * trade["open_rate"]
|
|
||||||
)
|
|
||||||
cross_vars = upnl_ex_1 - mm_ex_1
|
cross_vars = upnl_ex_1 - mm_ex_1
|
||||||
|
|
||||||
side_1 = -1 if is_short else 1
|
side_1 = -1 if is_short else 1
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
|
|||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"pair, is_short, trading_mode, margin_mode, wallet_balance, "
|
"pair, is_short, trading_mode, margin_mode, wallet_balance, "
|
||||||
"maintenance_amt, amount, open_rate, mark_price, open_trades,"
|
"maintenance_amt, amount, open_rate, open_trades,"
|
||||||
"mm_ratio, expected",
|
"mm_ratio, expected",
|
||||||
[
|
[
|
||||||
(
|
(
|
||||||
@@ -184,7 +184,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
|
|||||||
135365.00,
|
135365.00,
|
||||||
3683.979,
|
3683.979,
|
||||||
1456.84,
|
1456.84,
|
||||||
1456.84, # mark price
|
|
||||||
[],
|
[],
|
||||||
0.10,
|
0.10,
|
||||||
1114.78,
|
1114.78,
|
||||||
@@ -198,7 +197,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
|
|||||||
16300.000,
|
16300.000,
|
||||||
109.488,
|
109.488,
|
||||||
32481.980,
|
32481.980,
|
||||||
32481.980,
|
|
||||||
[],
|
[],
|
||||||
0.025,
|
0.025,
|
||||||
18778.73,
|
18778.73,
|
||||||
@@ -214,7 +212,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
|
|||||||
135365.00,
|
135365.00,
|
||||||
3683.979, # amount
|
3683.979, # amount
|
||||||
1456.84, # open_rate
|
1456.84, # open_rate
|
||||||
1335.18, # mark_price
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
# From calc example
|
# From calc example
|
||||||
@@ -251,7 +248,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
|
|||||||
16300.0,
|
16300.0,
|
||||||
109.488, # amount
|
109.488, # amount
|
||||||
32481.980, # open_rate
|
32481.980, # open_rate
|
||||||
31967.27, # mark_price
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
# From calc example
|
# From calc example
|
||||||
@@ -290,7 +286,6 @@ def test_liquidation_price_binance(
|
|||||||
maintenance_amt,
|
maintenance_amt,
|
||||||
amount,
|
amount,
|
||||||
open_rate,
|
open_rate,
|
||||||
mark_price,
|
|
||||||
open_trades,
|
open_trades,
|
||||||
mm_ratio,
|
mm_ratio,
|
||||||
expected,
|
expected,
|
||||||
@@ -306,7 +301,18 @@ def test_liquidation_price_binance(
|
|||||||
return oc["mm_ratio"], oc["maintenance_amt"]
|
return oc["mm_ratio"], oc["maintenance_amt"]
|
||||||
return mm_ratio, maintenance_amt
|
return mm_ratio, maintenance_amt
|
||||||
|
|
||||||
|
def fetch_funding_rates(*args, **kwargs):
|
||||||
|
return {
|
||||||
|
t["pair"]: {
|
||||||
|
"symbol": t["pair"],
|
||||||
|
"markPrice": t["mark_price"],
|
||||||
|
}
|
||||||
|
for t in open_trades
|
||||||
|
}
|
||||||
|
|
||||||
exchange.get_maintenance_ratio_and_amt = get_maint_ratio
|
exchange.get_maintenance_ratio_and_amt = get_maint_ratio
|
||||||
|
exchange.fetch_funding_rates = fetch_funding_rates
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
pytest.approx(
|
pytest.approx(
|
||||||
round(
|
round(
|
||||||
|
|||||||
Reference in New Issue
Block a user