diff --git a/freqtrade/exchange/binance.py b/freqtrade/exchange/binance.py index 027888fb1..3ef6be74c 100644 --- a/freqtrade/exchange/binance.py +++ b/freqtrade/exchange/binance.py @@ -144,6 +144,27 @@ class Binance(Exchange): """ 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( self, pair: str, @@ -191,19 +212,20 @@ class Binance(Exchange): if self.margin_mode == MarginMode.CROSS: mm_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: if trade["pair"] == pair: # Only "other" trades are considered continue + mark_price = funding_rates[trade["pair"]]["markPrice"] mm_ratio1, maint_amnt1 = self.get_maintenance_ratio_and_amt( 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 - upnl_ex_1 += ( - trade["amount"] * trade["mark_price"] - trade["amount"] * trade["open_rate"] - ) + upnl_ex_1 += trade["amount"] * mark_price - trade["amount"] * trade["open_rate"] cross_vars = upnl_ex_1 - mm_ex_1 side_1 = -1 if is_short else 1 diff --git a/tests/exchange/test_binance.py b/tests/exchange/test_binance.py index 269b616d3..63c7dfa00 100644 --- a/tests/exchange/test_binance.py +++ b/tests/exchange/test_binance.py @@ -172,7 +172,7 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side): @pytest.mark.parametrize( "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", [ ( @@ -184,7 +184,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side): 135365.00, 3683.979, 1456.84, - 1456.84, # mark price [], 0.10, 1114.78, @@ -198,7 +197,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side): 16300.000, 109.488, 32481.980, - 32481.980, [], 0.025, 18778.73, @@ -214,7 +212,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side): 135365.00, 3683.979, # amount 1456.84, # open_rate - 1335.18, # mark_price [ { # From calc example @@ -251,7 +248,6 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side): 16300.0, 109.488, # amount 32481.980, # open_rate - 31967.27, # mark_price [ { # From calc example @@ -290,7 +286,6 @@ def test_liquidation_price_binance( maintenance_amt, amount, open_rate, - mark_price, open_trades, mm_ratio, expected, @@ -306,7 +301,18 @@ def test_liquidation_price_binance( return oc["mm_ratio"], oc["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.fetch_funding_rates = fetch_funding_rates + assert ( pytest.approx( round(