diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 77bf3d8ad..8f6b6b332 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -686,7 +686,7 @@ class Backtesting: self.futures_data[trade.pair], amount=trade.amount, is_short=trade.is_short, - open_date=trade.open_date_utc, + open_date=trade.date_last_filled_utc, close_date=exit_candle_time, ) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 1f14f110e..9c9c7f381 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -65,6 +65,8 @@ class Order(_DECL_BASE): order_filled_date = Column(DateTime, nullable=True) order_update_date = Column(DateTime, nullable=True) + funding_fee = Column(Float, nullable=True) + ft_fee_base = Column(Float, nullable=True) @property @@ -72,6 +74,13 @@ class Order(_DECL_BASE): """ Order-date with UTC timezoneinfo""" return self.order_date.replace(tzinfo=timezone.utc) + @property + def order_filled_utc(self) -> Optional[datetime]: + """ last order-date with UTC timezoneinfo""" + return ( + self.order_filled_date.replace(tzinfo=timezone.utc) if self.order_filled_date else None + ) + @property def safe_price(self) -> float: return self.average or self.price @@ -179,6 +188,10 @@ class Order(_DECL_BASE): self.remaining = 0 self.status = 'closed' self.ft_is_open = False + # Assign funding fees to Order. + # Assumes backtesting will use date_last_filled_utc to calculate future funding fees. + self.funding_fee = trade.funding_fees + if (self.ft_order_side == trade.entry_side): trade.open_rate = self.price trade.recalc_trade_from_orders() @@ -346,6 +359,12 @@ class LocalTrade(): else: return self.amount + @property + def date_last_filled_utc(self): + """ Date of the last filled order""" + return max([self.open_date_utc, + max(o.order_filled_utc for o in self.orders if o.filled and not o.ft_is_open)]) + @property def open_date_utc(self): return self.open_date.replace(tzinfo=timezone.utc) @@ -843,10 +862,14 @@ class LocalTrade(): close_profit = 0.0 close_profit_abs = 0.0 profit = None - for o in self.orders: + # Reset funding fees + self.funding_fees = 0.0 + funding_fees = 0.0 + ordercount = len(self.orders) - 1 + for i, o in enumerate(self.orders): if o.ft_is_open or not o.filled: continue - + funding_fees += (o.funding_fee or 0.0) tmp_amount = FtPrecise(o.safe_amount_after_fee) tmp_price = FtPrecise(o.safe_price) @@ -861,7 +884,11 @@ class LocalTrade(): avg_price = current_stake / current_amount if is_exit: - # Process partial exits + # Process exits + if i == ordercount and is_closing: + # Apply funding fees only to the last order + self.funding_fees = funding_fees + exit_rate = o.safe_price exit_amount = o.safe_amount_after_fee profit = self.calc_profit(rate=exit_rate, amount=exit_amount, @@ -871,6 +898,7 @@ class LocalTrade(): exit_rate, amount=exit_amount, open_rate=avg_price) else: total_stake = total_stake + self._calc_open_trade_value(tmp_amount, price) + self.funding_fees = funding_fees if close_profit: self.close_profit = close_profit