From e806e4a7961417ae485d03d4d34ecd5d08cb3f22 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 2 Sep 2023 12:06:16 +0200 Subject: [PATCH] Move stop helper functions to callbacks section --- docs/strategy-callbacks.md | 80 +++++++++++++++++++++++++++++++-- docs/strategy-customization.md | 82 ---------------------------------- 2 files changed, 77 insertions(+), 85 deletions(-) diff --git a/docs/strategy-callbacks.md b/docs/strategy-callbacks.md index f44e7ae0c..5ce898dbb 100644 --- a/docs/strategy-callbacks.md +++ b/docs/strategy-callbacks.md @@ -413,15 +413,89 @@ See [Dataframe access](strategy-advanced.md#dataframe-access) for more informati #### Stoploss relative to open price -Stoploss values returned from `custom_stoploss()` always specify a percentage relative to `current_rate`. In order to set a stoploss relative to the *open* price, we need to use `current_profit` to calculate what percentage relative to the `current_rate` will give you the same result as if the percentage was specified from the open price. +Stoploss values returned from `custom_stoploss()` must specify a percentage relative to `current_rate`, but sometimes you may want to specify a stoploss relative to the _entry_ price instead. +`stoploss_from_open()` is a helper function to calculate a stoploss value that can be returned from `custom_stoploss` which will be equivalent to the desired trade profit above the entry point. -The helper function [`stoploss_from_open()`](strategy-customization.md#stoploss_from_open) can be used to convert from an open price relative stop, to a current price relative stop which can be returned from `custom_stoploss()`. +??? Example "Returning a stoploss relative to the open price from the custom stoploss function" + + Say the open price was $100, and `current_price` is $121 (`current_profit` will be `0.21`). + + If we want a stop price at 7% above the open price we can call `stoploss_from_open(0.07, current_profit, False)` which will return `0.1157024793`. 11.57% below $121 is $107, which is the same as 7% above $100. + + This function will consider leverage - so at 10x leverage, the actual stoploss would be 0.7% above $100 (0.7% * 10x = 7%). + + + ``` python + + from datetime import datetime + from freqtrade.persistence import Trade + from freqtrade.strategy import IStrategy, stoploss_from_open + + class AwesomeStrategy(IStrategy): + + # ... populate_* methods + + use_custom_stoploss = True + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, after_fill: bool, + **kwargs) -> Optional[float]: + + # once the profit has risen above 10%, keep the stoploss at 7% above the open price + if current_profit > 0.10: + return stoploss_from_open(0.07, current_profit, is_short=trade.is_short, leverage=trade.leverage) + + return 1 + + ``` + + Full examples can be found in the [Custom stoploss](strategy-advanced.md#custom-stoploss) section of the Documentation. + +!!! Note + Providing invalid input to `stoploss_from_open()` may produce "CustomStoploss function did not return valid stoploss" warnings. + This may happen if `current_profit` parameter is below specified `open_relative_stop`. Such situations may arise when closing trade + is blocked by `confirm_trade_exit()` method. Warnings can be solved by never blocking stop loss sells by checking `exit_reason` in + `confirm_trade_exit()`, or by using `return stoploss_from_open(...) or 1` idiom, which will request to not change stop loss when + `current_profit < open_relative_stop`. #### Stoploss percentage from absolute price Stoploss values returned from `custom_stoploss()` always specify a percentage relative to `current_rate`. In order to set a stoploss at specified absolute price level, we need to use `stop_rate` to calculate what percentage relative to the `current_rate` will give you the same result as if the percentage was specified from the open price. -The helper function [`stoploss_from_absolute()`](strategy-customization.md#stoploss_from_absolute) can be used to convert from an absolute price, to a current price relative stop which can be returned from `custom_stoploss()`. +The helper function `stoploss_from_absolute()` can be used to convert from an absolute price, to a current price relative stop which can be returned from `custom_stoploss()`. + +??? Example "Returning a stoploss using absolute price from the custom stoploss function" + + If we want to trail a stop price at 2xATR below current price we can call `stoploss_from_absolute(current_rate + (side * candle['atr'] * 2), current_rate, is_short=trade.is_short, leverage=trade.leverage)`. + For futures, we need to adjust the direction (up or down), as well as adjust for leverage, since the [`custom_stoploss`](strategy-callbacks.md#custom-stoploss) callback returns the ["risk for this trade"](stoploss.md#stoploss-and-leverage) - not the relative price movement. + + ``` python + + from datetime import datetime + from freqtrade.persistence import Trade + from freqtrade.strategy import IStrategy, stoploss_from_absolute, timeframe_to_prev_date + + class AwesomeStrategy(IStrategy): + + use_custom_stoploss = True + + def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe['atr'] = ta.ATR(dataframe, timeperiod=14) + return dataframe + + def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, + current_rate: float, current_profit: float, after_fill: bool, + **kwargs) -> Optional[float]: + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc) + candle = dataframe.iloc[-1].squeeze() + sign = 1 if trade.is_short else -1 + return stoploss_from_absolute(current_rate + (side * candle['atr'] * 2), + current_rate, is_short=trade.is_short, + leverage=trade.leverage) + + ``` + --- diff --git a/docs/strategy-customization.md b/docs/strategy-customization.md index d4db1c737..cf47e81ce 100644 --- a/docs/strategy-customization.md +++ b/docs/strategy-customization.md @@ -875,88 +875,6 @@ All columns of the informative dataframe will be available on the returning data *** -### *stoploss_from_open()* - -Stoploss values returned from `custom_stoploss` must specify a percentage relative to `current_rate`, but sometimes you may want to specify a stoploss relative to the entry point instead. `stoploss_from_open()` is a helper function to calculate a stoploss value that can be returned from `custom_stoploss` which will be equivalent to the desired trade profit above the entry point. - -??? Example "Returning a stoploss relative to the open price from the custom stoploss function" - - Say the open price was $100, and `current_price` is $121 (`current_profit` will be `0.21`). - - If we want a stop price at 7% above the open price we can call `stoploss_from_open(0.07, current_profit, False)` which will return `0.1157024793`. 11.57% below $121 is $107, which is the same as 7% above $100. - - This function will consider leverage - so at 10x leverage, the actual stoploss would be 0.7% above $100 (0.7% * 10x = 7%). - - - ``` python - - from datetime import datetime - from freqtrade.persistence import Trade - from freqtrade.strategy import IStrategy, stoploss_from_open - - class AwesomeStrategy(IStrategy): - - # ... populate_* methods - - use_custom_stoploss = True - - def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, - current_rate: float, current_profit: float, after_fill: bool, - **kwargs) -> Optional[float]: - - # once the profit has risen above 10%, keep the stoploss at 7% above the open price - if current_profit > 0.10: - return stoploss_from_open(0.07, current_profit, is_short=trade.is_short, leverage=trade.leverage) - - return 1 - - ``` - - Full examples can be found in the [Custom stoploss](strategy-advanced.md#custom-stoploss) section of the Documentation. - -!!! Note - Providing invalid input to `stoploss_from_open()` may produce "CustomStoploss function did not return valid stoploss" warnings. - This may happen if `current_profit` parameter is below specified `open_relative_stop`. Such situations may arise when closing trade - is blocked by `confirm_trade_exit()` method. Warnings can be solved by never blocking stop loss sells by checking `exit_reason` in - `confirm_trade_exit()`, or by using `return stoploss_from_open(...) or 1` idiom, which will request to not change stop loss when - `current_profit < open_relative_stop`. - -### *stoploss_from_absolute()* - -In some situations it may be confusing to deal with stops relative to current rate. Instead, you may define a stoploss level using an absolute price. - -??? Example "Returning a stoploss using absolute price from the custom stoploss function" - - If we want to trail a stop price at 2xATR below current price we can call `stoploss_from_absolute(current_rate + (side * candle['atr'] * 2), current_rate, is_short=trade.is_short, leverage=trade.leverage)`. - For futures, we need to adjust the direction (up or down), as well as adjust for leverage, since the [`custom_stoploss`](strategy-callbacks.md#custom-stoploss) callback returns the ["risk for this trade"](stoploss.md#stoploss-and-leverage) - not the relative price movement. - - ``` python - - from datetime import datetime - from freqtrade.persistence import Trade - from freqtrade.strategy import IStrategy, stoploss_from_absolute, timeframe_to_prev_date - - class AwesomeStrategy(IStrategy): - - use_custom_stoploss = True - - def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - dataframe['atr'] = ta.ATR(dataframe, timeperiod=14) - return dataframe - - def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, - current_rate: float, current_profit: float, after_fill: bool, - **kwargs) -> Optional[float]: - dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) - trade_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc) - candle = dataframe.iloc[-1].squeeze() - sign = 1 if trade.is_short else -1 - return stoploss_from_absolute(current_rate + (side * candle['atr'] * 2), - current_rate, is_short=trade.is_short, - leverage=trade.leverage) - - ``` - ## Additional data (Wallets) The strategy provides access to the `wallets` object. This contains the current balances on the exchange.