Update funding_fee freqtradebot test

This commit is contained in:
Matthias 2021-12-11 09:49:48 +01:00
parent 6948414e47
commit 17bd990053
3 changed files with 72 additions and 67 deletions

View File

@ -1851,7 +1851,9 @@ class Exchange:
mark_comb: PairWithTimeframe = ( mark_comb: PairWithTimeframe = (
pair, '1h', CandleType.from_string(self._ft_has["mark_ohlcv_price"])) pair, '1h', CandleType.from_string(self._ft_has["mark_ohlcv_price"]))
# TODO-lev: funding_rate downloading this way is not yet possible.
# TODO-lev: 1h seems arbitrary and generates a lot of "empty" lines
# TODO-lev: probably a exchange-adjusted parameter would make more sense
funding_comb: PairWithTimeframe = (pair, '1h', CandleType.FUNDING_RATE) funding_comb: PairWithTimeframe = (pair, '1h', CandleType.FUNDING_RATE)
candle_histories = self.refresh_latest_ohlcv( candle_histories = self.refresh_latest_ohlcv(
[mark_comb, funding_comb], [mark_comb, funding_comb],
@ -1863,7 +1865,7 @@ class Exchange:
mark_rates = candle_histories[mark_comb] mark_rates = candle_histories[mark_comb]
df = funding_rates.merge(mark_rates, on='date', how="inner", suffixes=["_fund", "_mark"]) df = funding_rates.merge(mark_rates, on='date', how="inner", suffixes=["_fund", "_mark"])
# TODO-lev: filter for relevant timeperiod? 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 return fees

View File

@ -3498,7 +3498,7 @@ def test__calculate_funding_fees(
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._calculate_funding_fees('ADA/USDT', amount, d1, d2) funding_fees = exchange._calculate_funding_fees('ADA/USDT', amount, d1, d2)
assert pytest.approx(funding_fees, expected_fees) assert pytest.approx(funding_fees) == expected_fees
@ pytest.mark.parametrize('exchange,expected_fees', [ @ pytest.mark.parametrize('exchange,expected_fees', [

View File

@ -9,6 +9,7 @@ from unittest.mock import ANY, MagicMock, PropertyMock
import arrow import arrow
import pytest import pytest
from pandas import DataFrame
from freqtrade.constants import CANCEL_REASON, MATH_CLOSE_PREC, UNLIMITED_STAKE_AMOUNT from freqtrade.constants import CANCEL_REASON, MATH_CLOSE_PREC, UNLIMITED_STAKE_AMOUNT
from freqtrade.enums import CandleType, RPCMessageType, RunMode, SellType, SignalDirection, State from freqtrade.enums import CandleType, RPCMessageType, RunMode, SellType, SignalDirection, State
@ -4802,60 +4803,67 @@ def test_update_funding_fees(
patch_exchange(mocker) patch_exchange(mocker)
default_conf['trading_mode'] = 'futures' default_conf['trading_mode'] = 'futures'
default_conf['collateral'] = 'isolated' default_conf['collateral'] = 'isolated'
default_conf['dry_run'] = True
timestamp_midnight = 1630454400000
timestamp_eight = 1630483200000
funding_rates_midnight = {
"LTC/BTC": {
timestamp_midnight: 0.00032583,
},
"ETH/BTC": {
timestamp_midnight: 0.0001,
},
"XRP/BTC": {
timestamp_midnight: 0.00049426,
}
}
funding_rates_eight = { date_midnight = arrow.get('2021-09-01 00:00:00')
"LTC/BTC": { date_eight = arrow.get('2021-09-01 08:00:00')
timestamp_midnight: 0.00032583, date_sixteen = arrow.get('2021-09-01 16:00:00')
timestamp_eight: 0.00024472, columns = ['date', 'open', 'high', 'low', 'close', 'volume']
}, # 16:00 entry is actually never used
"ETH/BTC": { # But should be kept in the test to ensure we're filtering correctly.
timestamp_midnight: 0.0001, funding_rates = {
timestamp_eight: 0.0001, "LTC/BTC":
}, DataFrame([
"XRP/BTC": { [date_midnight, 0.00032583, 0, 0, 0, 0],
timestamp_midnight: 0.00049426, [date_eight, 0.00024472, 0, 0, 0, 0],
timestamp_eight: 0.00032715, [date_sixteen, 0.00024472, 0, 0, 0, 0],
} ], columns=columns),
"ETH/BTC":
DataFrame([
[date_midnight, 0.0001, 0, 0, 0, 0],
[date_eight, 0.0001, 0, 0, 0, 0],
[date_sixteen, 0.0001, 0, 0, 0, 0],
], columns=columns),
"XRP/BTC":
DataFrame([
[date_midnight, 0.00049426, 0, 0, 0, 0],
[date_eight, 0.00032715, 0, 0, 0, 0],
[date_sixteen, 0.00032715, 0, 0, 0, 0],
], columns=columns)
} }
mark_prices = { mark_prices = {
"LTC/BTC": { "LTC/BTC":
timestamp_midnight: 3.3, DataFrame([
timestamp_eight: 3.2, [date_midnight, 3.3, 0, 0, 0, 0],
}, [date_eight, 3.2, 0, 0, 0, 0],
"ETH/BTC": { [date_sixteen, 3.2, 0, 0, 0, 0],
timestamp_midnight: 2.4, ], columns=columns),
timestamp_eight: 2.5, "ETH/BTC":
}, DataFrame([
"XRP/BTC": { [date_midnight, 2.4, 0, 0, 0, 0],
timestamp_midnight: 1.2, [date_eight, 2.5, 0, 0, 0, 0],
timestamp_eight: 1.2, [date_sixteen, 2.5, 0, 0, 0, 0],
} ], columns=columns),
"XRP/BTC":
DataFrame([
[date_midnight, 1.2, 0, 0, 0, 0],
[date_eight, 1.2, 0, 0, 0, 0],
[date_sixteen, 1.2, 0, 0, 0, 0],
], columns=columns)
} }
mocker.patch( def refresh_latest_ohlcv_mock(pairlist, **kwargs):
'freqtrade.exchange.Exchange._get_mark_price_history', ret = {}
side_effect=lambda pair, since: mark_prices[pair] for p, tf, ct in pairlist:
) if ct == CandleType.MARK:
ret[(p, tf, ct)] = mark_prices[p]
else:
ret[(p, tf, ct)] = funding_rates[p]
mocker.patch( return ret
'freqtrade.exchange.Exchange.get_funding_rate_history',
side_effect=lambda pair, since: funding_rates_midnight[pair] mocker.patch('freqtrade.exchange.Exchange.refresh_latest_ohlcv',
) side_effect=refresh_latest_ohlcv_mock)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
@ -4880,38 +4888,33 @@ def test_update_funding_fees(
trades = Trade.get_open_trades() trades = Trade.get_open_trades()
assert len(trades) == 3 assert len(trades) == 3
for trade in trades: for trade in trades:
assert trade.funding_fees == ( assert pytest.approx(trade.funding_fees) == (
trade.amount * trade.amount *
mark_prices[trade.pair][timestamp_midnight] * mark_prices[trade.pair].iloc[0]['open'] *
funding_rates_midnight[trade.pair][timestamp_midnight] funding_rates[trade.pair].iloc[0]['open']
) )
mocker.patch('freqtrade.exchange.Exchange.create_order', return_value=open_exit_order) mocker.patch('freqtrade.exchange.Exchange.create_order', return_value=open_exit_order)
# create_mock_trades(fee, False)
time_machine.move_to("2021-09-01 08:00:00 +00:00") time_machine.move_to("2021-09-01 08:00:00 +00:00")
mocker.patch(
'freqtrade.exchange.Exchange.get_funding_rate_history',
side_effect=lambda pair, since: funding_rates_eight[pair]
)
if schedule_off: if schedule_off:
for trade in trades: for trade in trades:
assert trade.funding_fees == (
trade.amount *
mark_prices[trade.pair][timestamp_midnight] *
funding_rates_eight[trade.pair][timestamp_midnight]
)
freqtrade.execute_trade_exit( freqtrade.execute_trade_exit(
trade=trade, trade=trade,
# The values of the next 2 params are irrelevant for this test # The values of the next 2 params are irrelevant for this test
limit=ticker_usdt_sell_up()['bid'], limit=ticker_usdt_sell_up()['bid'],
sell_reason=SellCheckTuple(sell_type=SellType.ROI) sell_reason=SellCheckTuple(sell_type=SellType.ROI)
) )
assert trade.funding_fees == pytest.approx(sum(
trade.amount *
mark_prices[trade.pair].iloc[0:2]['open'] *
funding_rates[trade.pair].iloc[0:2]['open']
))
else: else:
freqtrade._schedule.run_pending() freqtrade._schedule.run_pending()
# Funding fees for 00:00 and 08:00 # Funding fees for 00:00 and 08:00
for trade in trades: for trade in trades:
assert trade.funding_fees == sum([ assert trade.funding_fees == pytest.approx(sum(
trade.amount * trade.amount *
mark_prices[trade.pair][time] * mark_prices[trade.pair].iloc[0:2]['open'] * funding_rates[trade.pair].iloc[0:2]['open']
funding_rates_eight[trade.pair][time] for time in mark_prices[trade.pair].keys() ))
])