mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-09-20 17:41:12 +00:00
Merge pull request #9522 from freqtrade/bt/improve_futures_speed
Improve funding fee calculation
This commit is contained in:
commit
55efaec83d
|
@ -283,11 +283,13 @@ class Backtesting:
|
||||||
else:
|
else:
|
||||||
self.detail_data = {}
|
self.detail_data = {}
|
||||||
if self.trading_mode == TradingMode.FUTURES:
|
if self.trading_mode == TradingMode.FUTURES:
|
||||||
|
self.funding_fee_timeframe: str = self.exchange.get_option('mark_ohlcv_timeframe')
|
||||||
|
self.funding_fee_timeframe_secs: int = timeframe_to_seconds(self.funding_fee_timeframe)
|
||||||
# Load additional futures data.
|
# Load additional futures data.
|
||||||
funding_rates_dict = history.load_data(
|
funding_rates_dict = history.load_data(
|
||||||
datadir=self.config['datadir'],
|
datadir=self.config['datadir'],
|
||||||
pairs=self.pairlists.whitelist,
|
pairs=self.pairlists.whitelist,
|
||||||
timeframe=self.exchange.get_option('mark_ohlcv_timeframe'),
|
timeframe=self.funding_fee_timeframe,
|
||||||
timerange=self.timerange,
|
timerange=self.timerange,
|
||||||
startup_candles=0,
|
startup_candles=0,
|
||||||
fail_without_data=True,
|
fail_without_data=True,
|
||||||
|
@ -299,7 +301,7 @@ class Backtesting:
|
||||||
mark_rates_dict = history.load_data(
|
mark_rates_dict = history.load_data(
|
||||||
datadir=self.config['datadir'],
|
datadir=self.config['datadir'],
|
||||||
pairs=self.pairlists.whitelist,
|
pairs=self.pairlists.whitelist,
|
||||||
timeframe=self.exchange.get_option('mark_ohlcv_timeframe'),
|
timeframe=self.funding_fee_timeframe,
|
||||||
timerange=self.timerange,
|
timerange=self.timerange,
|
||||||
startup_candles=0,
|
startup_candles=0,
|
||||||
fail_without_data=True,
|
fail_without_data=True,
|
||||||
|
@ -604,6 +606,8 @@ class Backtesting:
|
||||||
"""
|
"""
|
||||||
if order and self._get_order_filled(order.ft_price, row):
|
if order and self._get_order_filled(order.ft_price, row):
|
||||||
order.close_bt_order(current_date, trade)
|
order.close_bt_order(current_date, trade)
|
||||||
|
self._run_funding_fees(trade, current_date, force=True)
|
||||||
|
|
||||||
if not (order.ft_order_side == trade.exit_side and order.safe_amount == trade.amount):
|
if not (order.ft_order_side == trade.exit_side and order.safe_amount == trade.amount):
|
||||||
# trade is still open
|
# trade is still open
|
||||||
trade.set_liquidation_price(self.exchange.get_liquidation_price(
|
trade.set_liquidation_price(self.exchange.get_liquidation_price(
|
||||||
|
@ -725,16 +729,7 @@ class Backtesting:
|
||||||
self, trade: LocalTrade, row: Tuple, current_time: datetime
|
self, trade: LocalTrade, row: Tuple, current_time: datetime
|
||||||
) -> Optional[LocalTrade]:
|
) -> Optional[LocalTrade]:
|
||||||
|
|
||||||
if self.trading_mode == TradingMode.FUTURES:
|
self._run_funding_fees(trade, current_time)
|
||||||
trade.set_funding_fees(
|
|
||||||
self.exchange.calculate_funding_fees(
|
|
||||||
self.futures_data[trade.pair],
|
|
||||||
amount=trade.amount,
|
|
||||||
is_short=trade.is_short,
|
|
||||||
open_date=trade.date_last_filled_utc,
|
|
||||||
close_date=current_time
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check if we need to adjust our current positions
|
# Check if we need to adjust our current positions
|
||||||
if self.strategy.position_adjustment_enable:
|
if self.strategy.position_adjustment_enable:
|
||||||
|
@ -753,6 +748,27 @@ class Backtesting:
|
||||||
return t
|
return t
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _run_funding_fees(self, trade: LocalTrade, current_time: datetime, force: bool = False):
|
||||||
|
"""
|
||||||
|
Calculate funding fees if necessary and add them to the trade.
|
||||||
|
"""
|
||||||
|
if self.trading_mode == TradingMode.FUTURES:
|
||||||
|
|
||||||
|
if (
|
||||||
|
force
|
||||||
|
or (current_time.timestamp() % self.funding_fee_timeframe_secs) == 0
|
||||||
|
):
|
||||||
|
# Funding fee interval.
|
||||||
|
trade.set_funding_fees(
|
||||||
|
self.exchange.calculate_funding_fees(
|
||||||
|
self.futures_data[trade.pair],
|
||||||
|
amount=trade.amount,
|
||||||
|
is_short=trade.is_short,
|
||||||
|
open_date=trade.date_last_filled_utc,
|
||||||
|
close_date=current_time
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def get_valid_price_and_stake(
|
def get_valid_price_and_stake(
|
||||||
self, pair: str, row: Tuple, propose_rate: float, stake_amount: float,
|
self, pair: str, row: Tuple, propose_rate: float, stake_amount: float,
|
||||||
direction: LongShort, current_time: datetime, entry_tag: Optional[str],
|
direction: LongShort, current_time: datetime, entry_tag: Optional[str],
|
||||||
|
|
|
@ -549,6 +549,7 @@ def test_backtest__enter_trade_futures(default_conf_usdt, fee, mocker) -> None:
|
||||||
default_conf_usdt['exchange']['pair_whitelist'] = ['.*']
|
default_conf_usdt['exchange']['pair_whitelist'] = ['.*']
|
||||||
backtesting = Backtesting(default_conf_usdt)
|
backtesting = Backtesting(default_conf_usdt)
|
||||||
backtesting._set_strategy(backtesting.strategylist[0])
|
backtesting._set_strategy(backtesting.strategylist[0])
|
||||||
|
mocker.patch('freqtrade.optimize.backtesting.Backtesting._run_funding_fees')
|
||||||
pair = 'ETH/USDT:USDT'
|
pair = 'ETH/USDT:USDT'
|
||||||
row = [
|
row = [
|
||||||
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0),
|
pd.Timestamp(year=2020, month=1, day=1, hour=5, minute=0),
|
||||||
|
@ -852,8 +853,8 @@ def test_backtest_one_detail(default_conf_usdt, fee, mocker, testdatadir, use_de
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('use_detail,exp_funding_fee, exp_ff_updates', [
|
@pytest.mark.parametrize('use_detail,exp_funding_fee, exp_ff_updates', [
|
||||||
(True, -0.018054162, 44),
|
(True, -0.018054162, 11),
|
||||||
(False, -0.01780296, 8),
|
(False, -0.01780296, 5),
|
||||||
])
|
])
|
||||||
def test_backtest_one_detail_futures(
|
def test_backtest_one_detail_futures(
|
||||||
default_conf_usdt, fee, mocker, testdatadir, use_detail, exp_funding_fee,
|
default_conf_usdt, fee, mocker, testdatadir, use_detail, exp_funding_fee,
|
||||||
|
@ -947,12 +948,13 @@ def test_backtest_one_detail_futures(
|
||||||
# assert late_entry > 0
|
# assert late_entry > 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('use_detail,entries,max_stake,expected_ff', [
|
@pytest.mark.parametrize('use_detail,entries,max_stake,ff_updates,expected_ff', [
|
||||||
(True, 50, 3000, -1.18038144),
|
(True, 50, 3000, 54, -1.18038144),
|
||||||
(False, 6, 360, -0.14679994)])
|
(False, 6, 360, 10, -0.14679994),
|
||||||
|
])
|
||||||
def test_backtest_one_detail_futures_funding_fees(
|
def test_backtest_one_detail_futures_funding_fees(
|
||||||
default_conf_usdt, fee, mocker, testdatadir, use_detail, entries, max_stake,
|
default_conf_usdt, fee, mocker, testdatadir, use_detail, entries, max_stake,
|
||||||
expected_ff,
|
ff_updates, expected_ff,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Funding fees are expected to differ, as the maximum position size differs.
|
Funding fees are expected to differ, as the maximum position size differs.
|
||||||
|
@ -1015,8 +1017,10 @@ def test_backtest_one_detail_futures_funding_fees(
|
||||||
assert len(results) == 1
|
assert len(results) == 1
|
||||||
|
|
||||||
assert 'orders' in results.columns
|
assert 'orders' in results.columns
|
||||||
# funding_fees have been calculated for each candle
|
# funding_fees have been calculated for each funding-fee candle
|
||||||
assert ff_spy.call_count == (324 if use_detail else 27)
|
# the trade is open for 26 hours - hence we expect the 8h fee to apply 4 times.
|
||||||
|
# Additional counts will happen due each successful entry, which needs to call this, too.
|
||||||
|
assert ff_spy.call_count == ff_updates
|
||||||
|
|
||||||
for t in Trade.trades:
|
for t in Trade.trades:
|
||||||
# At least 6 adjustment orders
|
# At least 6 adjustment orders
|
||||||
|
|
|
@ -104,6 +104,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker, levera
|
||||||
mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float('inf'))
|
mocker.patch(f"{EXMS}.get_max_pair_stake_amount", return_value=float('inf'))
|
||||||
mocker.patch(f"{EXMS}.get_max_leverage", return_value=10)
|
mocker.patch(f"{EXMS}.get_max_leverage", return_value=10)
|
||||||
mocker.patch(f"{EXMS}.get_maintenance_ratio_and_amt", return_value=(0.1, 0.1))
|
mocker.patch(f"{EXMS}.get_maintenance_ratio_and_amt", return_value=(0.1, 0.1))
|
||||||
|
mocker.patch('freqtrade.optimize.backtesting.Backtesting._run_funding_fees')
|
||||||
|
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
default_conf.update({
|
default_conf.update({
|
||||||
|
|
Loading…
Reference in New Issue
Block a user