Update funding_fee formula to correctly calculate fees for long trades
This commit is contained in:
parent
f26cd19146
commit
a0c0c4dcbe
@ -1885,6 +1885,7 @@ class Exchange:
|
|||||||
self,
|
self,
|
||||||
pair: str,
|
pair: str,
|
||||||
amount: float,
|
amount: float,
|
||||||
|
is_short: bool,
|
||||||
open_date: datetime,
|
open_date: datetime,
|
||||||
close_date: Optional[datetime] = None
|
close_date: Optional[datetime] = None
|
||||||
) -> float:
|
) -> float:
|
||||||
@ -1894,6 +1895,7 @@ class Exchange:
|
|||||||
Only used during dry-run or if the exchange does not provide a funding_rates endpoint.
|
Only used during dry-run or if the exchange does not provide a funding_rates endpoint.
|
||||||
:param pair: The quote/base pair of the trade
|
:param pair: The quote/base pair of the trade
|
||||||
:param amount: The quantity of the trade
|
:param amount: The quantity of the trade
|
||||||
|
:param is_short: trade direction
|
||||||
:param open_date: The date and time that the trade started
|
:param open_date: The date and time that the trade started
|
||||||
:param close_date: The date and time that the trade ended
|
:param close_date: The date and time that the trade ended
|
||||||
"""
|
"""
|
||||||
@ -1928,6 +1930,7 @@ class Exchange:
|
|||||||
return self.calculate_funding_fees(
|
return self.calculate_funding_fees(
|
||||||
funding_mark_rates,
|
funding_mark_rates,
|
||||||
amount=amount,
|
amount=amount,
|
||||||
|
is_short=is_short,
|
||||||
open_date=open_date,
|
open_date=open_date,
|
||||||
close_date=close_date
|
close_date=close_date
|
||||||
)
|
)
|
||||||
@ -1946,6 +1949,7 @@ class Exchange:
|
|||||||
self,
|
self,
|
||||||
df: DataFrame,
|
df: DataFrame,
|
||||||
amount: float,
|
amount: float,
|
||||||
|
is_short: bool,
|
||||||
open_date: datetime,
|
open_date: datetime,
|
||||||
close_date: Optional[datetime] = None,
|
close_date: Optional[datetime] = None,
|
||||||
time_in_ratio: Optional[float] = None
|
time_in_ratio: Optional[float] = None
|
||||||
@ -1955,6 +1959,7 @@ class Exchange:
|
|||||||
:param df: Dataframe containing combined funding and mark rates
|
:param df: Dataframe containing combined funding and mark rates
|
||||||
as `open_fund` and `open_mark`.
|
as `open_fund` and `open_mark`.
|
||||||
:param amount: The quantity of the trade
|
:param amount: The quantity of the trade
|
||||||
|
:param is_short: trade direction
|
||||||
:param open_date: The date and time that the trade started
|
:param open_date: The date and time that the trade started
|
||||||
:param close_date: The date and time that the trade ended
|
:param close_date: The date and time that the trade ended
|
||||||
:param time_in_ratio: Not used by most exchange classes
|
:param time_in_ratio: Not used by most exchange classes
|
||||||
@ -1965,19 +1970,23 @@ class Exchange:
|
|||||||
df = df[(df['date'] >= open_date) & (df['date'] <= close_date)]
|
df = df[(df['date'] >= open_date) & (df['date'] <= close_date)]
|
||||||
fees = sum(df['open_fund'] * df['open_mark'] * amount)
|
fees = sum(df['open_fund'] * df['open_mark'] * amount)
|
||||||
|
|
||||||
return fees
|
# Negate fees for longs as funding_fees expects it this way based on live endpoints.
|
||||||
|
return fees if is_short else -fees
|
||||||
|
|
||||||
def get_funding_fees(self, pair: str, amount: float, open_date: datetime) -> float:
|
def get_funding_fees(
|
||||||
|
self, pair: str, amount: float, is_short: bool, open_date: datetime) -> float:
|
||||||
"""
|
"""
|
||||||
Fetch funding fees, either from the exchange (live) or calculates them
|
Fetch funding fees, either from the exchange (live) or calculates them
|
||||||
based on funding rate/mark price history
|
based on funding rate/mark price history
|
||||||
:param pair: The quote/base pair of the trade
|
:param pair: The quote/base pair of the trade
|
||||||
|
:param is_short: trade direction
|
||||||
:param amount: Trade amount
|
:param amount: Trade amount
|
||||||
:param open_date: Open date of the trade
|
:param open_date: Open date of the trade
|
||||||
"""
|
"""
|
||||||
if self.trading_mode == TradingMode.FUTURES:
|
if self.trading_mode == TradingMode.FUTURES:
|
||||||
if self._config['dry_run']:
|
if self._config['dry_run']:
|
||||||
funding_fees = self._fetch_and_calculate_funding_fees(pair, amount, open_date)
|
funding_fees = self._fetch_and_calculate_funding_fees(
|
||||||
|
pair, amount, is_short, open_date)
|
||||||
else:
|
else:
|
||||||
funding_fees = self._get_funding_fees_from_exchange(pair, open_date)
|
funding_fees = self._get_funding_fees_from_exchange(pair, open_date)
|
||||||
return funding_fees
|
return funding_fees
|
||||||
|
@ -163,6 +163,7 @@ class Kraken(Exchange):
|
|||||||
self,
|
self,
|
||||||
df: DataFrame,
|
df: DataFrame,
|
||||||
amount: float,
|
amount: float,
|
||||||
|
is_short: bool,
|
||||||
open_date: datetime,
|
open_date: datetime,
|
||||||
close_date: Optional[datetime] = None,
|
close_date: Optional[datetime] = None,
|
||||||
time_in_ratio: Optional[float] = None
|
time_in_ratio: Optional[float] = None
|
||||||
@ -176,6 +177,7 @@ class Kraken(Exchange):
|
|||||||
:param df: Dataframe containing combined funding and mark rates
|
:param df: Dataframe containing combined funding and mark rates
|
||||||
as `open_fund` and `open_mark`.
|
as `open_fund` and `open_mark`.
|
||||||
:param amount: The quantity of the trade
|
:param amount: The quantity of the trade
|
||||||
|
:param is_short: trade direction
|
||||||
:param open_date: The date and time that the trade started
|
:param open_date: The date and time that the trade started
|
||||||
:param close_date: The date and time that the trade ended
|
:param close_date: The date and time that the trade ended
|
||||||
:param time_in_ratio: Not used by most exchange classes
|
:param time_in_ratio: Not used by most exchange classes
|
||||||
|
@ -273,9 +273,10 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
trades = Trade.get_open_trades()
|
trades = Trade.get_open_trades()
|
||||||
for trade in trades:
|
for trade in trades:
|
||||||
funding_fees = self.exchange.get_funding_fees(
|
funding_fees = self.exchange.get_funding_fees(
|
||||||
trade.pair,
|
pair=trade.pair,
|
||||||
trade.amount,
|
amount=trade.amount,
|
||||||
trade.open_date
|
is_short=trade.is_short,
|
||||||
|
open_date=trade.open_date
|
||||||
)
|
)
|
||||||
trade.funding_fees = funding_fees
|
trade.funding_fees = funding_fees
|
||||||
else:
|
else:
|
||||||
@ -741,7 +742,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
|
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
|
||||||
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
|
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
|
||||||
open_date = datetime.now(timezone.utc)
|
open_date = datetime.now(timezone.utc)
|
||||||
funding_fees = self.exchange.get_funding_fees(pair, amount, open_date)
|
funding_fees = self.exchange.get_funding_fees(
|
||||||
|
pair=pair, amount=amount, is_short=is_short, open_date=open_date)
|
||||||
# This is a new trade
|
# This is a new trade
|
||||||
if trade is None:
|
if trade is None:
|
||||||
trade = Trade(
|
trade = Trade(
|
||||||
@ -1379,9 +1381,10 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
:return: True if it succeeds (supported) False (not supported)
|
:return: True if it succeeds (supported) False (not supported)
|
||||||
"""
|
"""
|
||||||
trade.funding_fees = self.exchange.get_funding_fees(
|
trade.funding_fees = self.exchange.get_funding_fees(
|
||||||
trade.pair,
|
pair=trade.pair,
|
||||||
trade.amount,
|
amount=trade.amount,
|
||||||
trade.open_date
|
is_short=trade.is_short,
|
||||||
|
open_date=trade.open_date,
|
||||||
)
|
)
|
||||||
exit_type = 'sell'
|
exit_type = 'sell'
|
||||||
if sell_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
|
if sell_reason.sell_type in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS):
|
||||||
|
@ -495,6 +495,7 @@ class Backtesting:
|
|||||||
trade.funding_fees = self.exchange.calculate_funding_fees(
|
trade.funding_fees = self.exchange.calculate_funding_fees(
|
||||||
self.futures_data[trade.pair],
|
self.futures_data[trade.pair],
|
||||||
amount=trade.amount,
|
amount=trade.amount,
|
||||||
|
is_short=trade.is_short,
|
||||||
open_date=trade.open_date_utc,
|
open_date=trade.open_date_utc,
|
||||||
close_date=sell_candle_time,
|
close_date=sell_candle_time,
|
||||||
)
|
)
|
||||||
|
@ -3567,6 +3567,7 @@ def test_calculate_funding_fees(
|
|||||||
assert exchange.calculate_funding_fees(
|
assert exchange.calculate_funding_fees(
|
||||||
df,
|
df,
|
||||||
amount=size,
|
amount=size,
|
||||||
|
is_short=True,
|
||||||
open_date=trade_date,
|
open_date=trade_date,
|
||||||
close_date=trade_date,
|
close_date=trade_date,
|
||||||
time_in_ratio=time_in_ratio,
|
time_in_ratio=time_in_ratio,
|
||||||
@ -3577,6 +3578,7 @@ def test_calculate_funding_fees(
|
|||||||
kraken.calculate_funding_fees(
|
kraken.calculate_funding_fees(
|
||||||
df,
|
df,
|
||||||
amount=size,
|
amount=size,
|
||||||
|
is_short=True,
|
||||||
open_date=trade_date,
|
open_date=trade_date,
|
||||||
close_date=trade_date,
|
close_date=trade_date,
|
||||||
time_in_ratio=time_in_ratio,
|
time_in_ratio=time_in_ratio,
|
||||||
@ -3586,6 +3588,7 @@ def test_calculate_funding_fees(
|
|||||||
assert kraken.calculate_funding_fees(
|
assert kraken.calculate_funding_fees(
|
||||||
df,
|
df,
|
||||||
amount=size,
|
amount=size,
|
||||||
|
is_short=True,
|
||||||
open_date=trade_date,
|
open_date=trade_date,
|
||||||
close_date=trade_date,
|
close_date=trade_date,
|
||||||
time_in_ratio=time_in_ratio,
|
time_in_ratio=time_in_ratio,
|
||||||
@ -3681,7 +3684,8 @@ def test__fetch_and_calculate_funding_fees(
|
|||||||
type(api_mock).has = PropertyMock(return_value={'fetchFundingRateHistory': True})
|
type(api_mock).has = PropertyMock(return_value={'fetchFundingRateHistory': True})
|
||||||
|
|
||||||
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange)
|
||||||
funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', amount, d1, d2)
|
# TODO-lev: test this for longs
|
||||||
|
funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', amount, True, d1, d2)
|
||||||
assert pytest.approx(funding_fees) == expected_fees
|
assert pytest.approx(funding_fees) == expected_fees
|
||||||
|
|
||||||
|
|
||||||
@ -3709,7 +3713,8 @@ def test__fetch_and_calculate_funding_fees_datetime_called(
|
|||||||
d1 = datetime.strptime("2021-09-01 00:00:00 +0000", '%Y-%m-%d %H:%M:%S %z')
|
d1 = datetime.strptime("2021-09-01 00:00:00 +0000", '%Y-%m-%d %H:%M:%S %z')
|
||||||
|
|
||||||
time_machine.move_to("2021-09-01 08:00:00 +00:00")
|
time_machine.move_to("2021-09-01 08:00:00 +00:00")
|
||||||
funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', 30.0, d1)
|
# TODO-lev: test this for longs
|
||||||
|
funding_fees = exchange._fetch_and_calculate_funding_fees('ADA/USDT', 30.0, True, d1)
|
||||||
assert funding_fees == expected_fees
|
assert funding_fees == expected_fees
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user