Maintain existing order. Update functionality and documentation

This commit is contained in:
eSeR1805 2022-04-29 00:10:17 +03:00
parent eb23170c43
commit 17650d7e60
No known key found for this signature in database
GPG Key ID: BA53686259B46936
4 changed files with 53 additions and 37 deletions

View File

@ -698,6 +698,9 @@ Be aware that `custom_entry_price()` is still the one dictating initial entry li
!!! Note "Simple Order Cancelation" !!! Note "Simple Order Cancelation"
This also allows simple cancelation without an replacement order. This behavior occurs when `None` is returned. This also allows simple cancelation without an replacement order. This behavior occurs when `None` is returned.
!!! Note "Maintaining Order"
Maintaining existing order on exchange is facilitated. This behavior occurs when `order.price` is returned.
!!! Warning !!! Warning
Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy. Entry `unfilledtimeout` mechanism takes precedence over this. Be sure to update timeout values to match your expectancy.
@ -709,19 +712,24 @@ class AwesomeStrategy(IStrategy):
# ... populate_* methods # ... populate_* methods
def adjust_entry_price(self, trade: Trade, order: Order, pair: str, def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str,
current_time: datetime, proposed_rate: float, current_time: datetime, proposed_rate: float, current_order_rate: float,
entry_tag: Optional[str], side: str, **kwargs) -> float: entry_tag: Optional[str], side: str, **kwargs) -> float:
""" """
Entry price re-adjustment logic, returning the user desired limit price. Entry price re-adjustment logic, returning the user desired limit price.
This only executes when a order was already placed, still open(unfilled fully or partially) This only executes when a order was already placed, still open(unfilled fully or partially)
and not timed out on subsequent candles after entry trigger. and not timed out on subsequent candles after entry trigger.
When not implemented by a strategy, returns current_order_rate as default.
If current_order_rate is returned then the existing order is maintained.
If None is returned then order gets canceled but not replaced by a new one.
:param pair: Pair that's currently analyzed :param pair: Pair that's currently analyzed
:param trade: Trade object. :param trade: Trade object.
:param order: Order object :param order: Order object
:param current_time: datetime object, containing the current datetime :param current_time: datetime object, containing the current datetime
:param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing.
:param current_order_rate: Rate of the existing order in place.
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
:param side: 'long' or 'short' - indicating the direction of the proposed trade :param side: 'long' or 'short' - indicating the direction of the proposed trade
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy. :param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
@ -736,8 +744,10 @@ class AwesomeStrategy(IStrategy):
else: else:
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
current_candle = dataframe.iloc[-1].squeeze() current_candle = dataframe.iloc[-1].squeeze()
# desired price
return current_candle['sma_200'] return current_candle['sma_200']
return proposed_rate # default: maintain existing order
return current_order_rate
``` ```
## Leverage Callback ## Leverage Callback

View File

@ -1165,9 +1165,10 @@ class FreqtradeBot(LoggingMixin):
def replace_order(self, order: Dict, order_obj: Optional[Order], trade: Trade) -> None: def replace_order(self, order: Dict, order_obj: Optional[Order], trade: Trade) -> None:
""" """
Check if current analyzed entry order should be replaced. Analyzed order is canceled Check if current analyzed entry order should be replaced or simply cancelled.
if adjust_entry_price() returned price differs from proposed_rate. To simply cancel the existing order(no replacement) adjust_entry_price() should return None
New order is only placed if adjust_entry_price() returned price is not None. To maintain existing order adjust_entry_price() should return order_obj.price
To replace existing order adjust_entry_price() should return desired price for limit order
:param order: Order dict grabbed with exchange.fetch_order() :param order: Order dict grabbed with exchange.fetch_order()
:param order_obj: Order object. :param order_obj: Order object.
:param trade: Trade object. :param trade: Trade object.
@ -1184,17 +1185,18 @@ class FreqtradeBot(LoggingMixin):
proposed_rate = self.exchange.get_rate( proposed_rate = self.exchange.get_rate(
trade.pair, side='entry', is_short=trade.is_short, refresh=True) trade.pair, side='entry', is_short=trade.is_short, refresh=True)
adjusted_entry_price = strategy_safe_wrapper(self.strategy.adjust_entry_price, adjusted_entry_price = strategy_safe_wrapper(self.strategy.adjust_entry_price,
default_retval=proposed_rate)( default_retval=order_obj.price)(
trade=trade, order=order_obj, pair=trade.pair, trade=trade, order=order_obj, pair=trade.pair,
current_time=datetime.now(timezone.utc), proposed_rate=proposed_rate, current_time=datetime.now(timezone.utc), proposed_rate=proposed_rate,
entry_tag=trade.enter_tag, side=trade.entry_side) current_order_rate=order_obj.price, entry_tag=trade.enter_tag,
side=trade.entry_side)
full_cancel = False full_cancel = False
cancel_reason = constants.CANCEL_REASON['REPLACE'] cancel_reason = constants.CANCEL_REASON['REPLACE']
if not adjusted_entry_price: if not adjusted_entry_price:
full_cancel = True full_cancel = True
cancel_reason = constants.CANCEL_REASON['USER_CANCEL'] cancel_reason = constants.CANCEL_REASON['USER_CANCEL']
if proposed_rate != adjusted_entry_price: if order_obj.price != adjusted_entry_price:
# cancel existing order if new price is supplied or None # cancel existing order if new price is supplied or None
self.handle_cancel_enter(trade, order, cancel_reason, self.handle_cancel_enter(trade, order, cancel_reason,
allow_full_cancel=full_cancel) allow_full_cancel=full_cancel)

View File

@ -465,30 +465,32 @@ class IStrategy(ABC, HyperStrategyMixin):
return None return None
def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str, def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str,
current_time: datetime, proposed_rate: float, current_time: datetime, proposed_rate: float, current_order_rate: float,
entry_tag: Optional[str], side: str, **kwargs) -> float: entry_tag: Optional[str], side: str, **kwargs) -> float:
""" """
Entry price re-adjustment logic, returning the user desired limit price. Entry price re-adjustment logic, returning the user desired limit price.
This only executes when a order was already placed, still open(unfilled fully or partially) This only executes when a order was already placed, still open(unfilled fully or partially)
and not timed out on subsequent candles after entry trigger. and not timed out on subsequent candles after entry trigger.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/ For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/
When not implemented by a strategy, returns proposed_stake. When not implemented by a strategy, returns current_order_rate as default.
If current_order_rate is returned then the existing order is maintained.
If None is returned then order gets canceled but not replaced by a new one. If None is returned then order gets canceled but not replaced by a new one.
:param pair: Pair that's currently analyzed :param pair: Pair that's currently analyzed
:param trade: Trade object. :param trade: Trade object.
:param order: Order object :param order: Order object
:param current_time: datetime object, containing the current datetime :param current_time: datetime object, containing the current datetime
:param proposed_rate: Rate, calculated based on pricing settings in exit_pricing. :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing.
:param current_order_rate: Rate of the existing order in place.
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
:param side: 'long' or 'short' - indicating the direction of the proposed trade :param side: 'long' or 'short' - indicating the direction of the proposed trade
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy. :param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New entry price value if provided :return float: New entry price value if provided
""" """
return proposed_rate return current_order_rate
def leverage(self, pair: str, current_time: datetime, current_rate: float, def leverage(self, pair: str, current_time: datetime, current_rate: float,
proposed_leverage: float, max_leverage: float, side: str, proposed_leverage: float, max_leverage: float, side: str,

View File

@ -30,31 +30,33 @@ def custom_entry_price(self, pair: str, current_time: 'datetime', proposed_rate:
""" """
return proposed_rate return proposed_rate
def adjust_entry_price(self, trade: Trade, order: Order, pair: str, def adjust_entry_price(self, trade: Trade, order: Optional[Order], pair: str,
current_time: datetime, proposed_rate: float, current_time: datetime, proposed_rate: float, current_order_rate: float,
entry_tag: Optional[str], side: str, **kwargs) -> float: entry_tag: Optional[str], side: str, **kwargs) -> float:
""" """
Entry price re-adjustment logic, returning the user desired limit price. Entry price re-adjustment logic, returning the user desired limit price.
This only executes when a order was already placed, still open(unfilled fully or partially) This only executes when a order was already placed, still open(unfilled fully or partially)
and not timed out on subsequent candles after entry trigger. and not timed out on subsequent candles after entry trigger.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/ For full documentation please go to https://www.freqtrade.io/en/latest/strategy-callbacks/
When not implemented by a strategy, returns proposed_stake. When not implemented by a strategy, returns current_order_rate as default.
If None is returned then order gets canceled but not replaced by a new one. If current_order_rate is returned then the existing order is maintained.
If None is returned then order gets canceled but not replaced by a new one.
:param pair: Pair that's currently analyzed :param pair: Pair that's currently analyzed
:param trade: Trade object. :param trade: Trade object.
:param order: Order object :param order: Order object
:param current_time: datetime object, containing the current datetime :param current_time: datetime object, containing the current datetime
:param proposed_rate: Rate, calculated based on pricing settings in entry_pricing. :param proposed_rate: Rate, calculated based on pricing settings in entry_pricing.
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal. :param current_order_rate: Rate of the existing order in place.
:param side: 'long' or 'short' - indicating the direction of the proposed trade :param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy. :param side: 'long' or 'short' - indicating the direction of the proposed trade
:return float: New entry price value if provided :param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New entry price value if provided
""" """
return proposed_rate return current_order_rate
def custom_exit_price(self, pair: str, trade: 'Trade', def custom_exit_price(self, pair: str, trade: 'Trade',
current_time: 'datetime', proposed_rate: float, current_time: 'datetime', proposed_rate: float,