diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index 6c86595d3..e42aa39d2 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -510,6 +510,9 @@ Each of these methods are called right before placing an order on the exchange. !!! Note If your custom pricing function return None or an invalid value, price will fall back to `proposed_rate`, which is based on the regular pricing configuration. +!!! Note + Using custom_entry_price, the Trade object will be available as soon as the first entry order associated with the trade is created, for the first entry, `trade` parameter value will be `None`. + ### Custom order entry and exit price example ``` python @@ -520,7 +523,7 @@ class AwesomeStrategy(IStrategy): # ... populate_* methods - def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, + def custom_entry_price(self, pair: str, trade: Optional['Trade'], current_time: datetime, proposed_rate: float, entry_tag: Optional[str], side: str, **kwargs) -> float: dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair, diff --git a/docs/strategy_migration.md b/docs/strategy_migration.md index d4d5f0068..9e6f56e49 100644 --- a/docs/strategy_migration.md +++ b/docs/strategy_migration.md @@ -280,7 +280,7 @@ After: ``` python hl_lines="3" class AwesomeStrategy(IStrategy): - def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, + def custom_entry_price(self, pair: str, trade: Optional[Trade], current_time: datetime, proposed_rate: float, entry_tag: Optional[str], side: str, **kwargs) -> float: return proposed_rate ``` diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index bd6353016..3033a9daa 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -938,7 +938,8 @@ class FreqtradeBot(LoggingMixin): # Don't call custom_entry_price in order-adjust scenario custom_entry_price = strategy_safe_wrapper(self.strategy.custom_entry_price, default_retval=enter_limit_requested)( - pair=pair, current_time=datetime.now(timezone.utc), + pair=pair, trade=trade, + current_time=datetime.now(timezone.utc), proposed_rate=enter_limit_requested, entry_tag=entry_tag, side=trade_side, ) diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 4b267b315..6db996589 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -738,7 +738,9 @@ class Backtesting: if order_type == 'limit': new_rate = strategy_safe_wrapper(self.strategy.custom_entry_price, default_retval=propose_rate)( - pair=pair, current_time=current_time, + pair=pair, + trade=trade, # type: ignore[arg-type] + current_time=current_time, proposed_rate=propose_rate, entry_tag=entry_tag, side=direction, ) # default value is the open rate diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 94c78f3c7..5cdbb6bf6 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -395,7 +395,8 @@ class IStrategy(ABC, HyperStrategyMixin): """ return self.stoploss - def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, + def custom_entry_price(self, pair: str, trade: Optional[Trade], + current_time: datetime, proposed_rate: float, entry_tag: Optional[str], side: str, **kwargs) -> float: """ Custom entry price logic, returning the new entry price. @@ -405,6 +406,7 @@ class IStrategy(ABC, HyperStrategyMixin): When not implemented by a strategy, returns None, orderbook is used to set entry price :param pair: Pair that's currently analyzed + :param trade: trade object (None for initial entries). :param current_time: datetime object, containing the current datetime :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. diff --git a/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 b/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 index 4e1875084..6fad129c7 100644 --- a/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 +++ b/freqtrade/templates/strategy_subtemplates/strategy_methods_advanced.j2 @@ -13,7 +13,8 @@ def bot_loop_start(self, current_time: datetime, **kwargs) -> None: """ pass -def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: float, +def custom_entry_price(self, pair: str, trade: Optional['Trade'], + current_time: 'datetime', proposed_rate: float, entry_tag: 'Optional[str]', side: str, **kwargs) -> float: """ Custom entry price logic, returning the new entry price. @@ -23,6 +24,7 @@ def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate: When not implemented by a strategy, returns None, orderbook is used to set entry price :param pair: Pair that's currently analyzed + :param trade: trade object (None for initial entries). :param current_time: datetime object, containing the current datetime :param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. diff --git a/tests/strategy/strats/strategy_test_v3_custom_entry_price.py b/tests/strategy/strats/strategy_test_v3_custom_entry_price.py index 872984156..607ff6e1e 100644 --- a/tests/strategy/strats/strategy_test_v3_custom_entry_price.py +++ b/tests/strategy/strats/strategy_test_v3_custom_entry_price.py @@ -6,6 +6,8 @@ from typing import Optional from pandas import DataFrame from strategy_test_v3 import StrategyTestV3 +from freqtrade.persistence import Trade + class StrategyTestV3CustomEntryPrice(StrategyTestV3): """ @@ -31,7 +33,8 @@ class StrategyTestV3CustomEntryPrice(StrategyTestV3): def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: return dataframe - def custom_entry_price(self, pair: str, current_time: datetime, proposed_rate: float, + def custom_entry_price(self, pair: str, trade: Optional[Trade], current_time: datetime, + proposed_rate: float, entry_tag: Optional[str], side: str, **kwargs) -> float: return self.new_entry_price