Merge pull request #8273 from freqtrade/stop_from_open_lev

Stop from open lev
This commit is contained in:
Matthias 2023-03-09 19:44:16 +01:00 committed by GitHub
commit 5b2a291109
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 30 additions and 20 deletions

View File

@ -316,11 +316,11 @@ class AwesomeStrategy(IStrategy):
# evaluate highest to lowest, so that highest possible stop is used # evaluate highest to lowest, so that highest possible stop is used
if current_profit > 0.40: if current_profit > 0.40:
return stoploss_from_open(0.25, current_profit, is_short=trade.is_short) return stoploss_from_open(0.25, current_profit, is_short=trade.is_short, leverage=trade.leverage)
elif current_profit > 0.25: elif current_profit > 0.25:
return stoploss_from_open(0.15, current_profit, is_short=trade.is_short) return stoploss_from_open(0.15, current_profit, is_short=trade.is_short, leverage=trade.leverage)
elif current_profit > 0.20: elif current_profit > 0.20:
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short) return stoploss_from_open(0.07, current_profit, is_short=trade.is_short, leverage=trade.leverage)
# return maximum stoploss value, keeping current stoploss price unchanged # return maximum stoploss value, keeping current stoploss price unchanged
return 1 return 1

View File

@ -881,7 +881,7 @@ All columns of the informative dataframe will be available on the returning data
### *stoploss_from_open()* ### *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 open 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 percentage above 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 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" ??? Example "Returning a stoploss relative to the open price from the custom stoploss function"
@ -889,6 +889,8 @@ Stoploss values returned from `custom_stoploss` must specify a percentage relati
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. 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 ``` python
@ -907,7 +909,7 @@ Stoploss values returned from `custom_stoploss` must specify a percentage relati
# once the profit has risen above 10%, keep the stoploss at 7% above the open price # once the profit has risen above 10%, keep the stoploss at 7% above the open price
if current_profit > 0.10: if current_profit > 0.10:
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short) return stoploss_from_open(0.07, current_profit, is_short=trade.is_short, leverage=trade.leverage)
return 1 return 1

View File

@ -86,37 +86,41 @@ def merge_informative_pair(dataframe: pd.DataFrame, informative: pd.DataFrame,
def stoploss_from_open( def stoploss_from_open(
open_relative_stop: float, open_relative_stop: float,
current_profit: float, current_profit: float,
is_short: bool = False is_short: bool = False,
leverage: float = 1.0
) -> float: ) -> float:
""" """
Given the current profit, and a desired stop loss value relative to the trade entry price,
Given the current profit, and a desired stop loss value relative to the open price,
return a stop loss value that is relative to the current price, and which can be return a stop loss value that is relative to the current price, and which can be
returned from `custom_stoploss`. returned from `custom_stoploss`.
The requested stop can be positive for a stop above the open price, or negative for The requested stop can be positive for a stop above the open price, or negative for
a stop below the open price. The return value is always >= 0. a stop below the open price. The return value is always >= 0.
`open_relative_stop` will be considered as adjusted for leverage if leverage is provided..
Returns 0 if the resulting stop price would be above/below (longs/shorts) the current price Returns 0 if the resulting stop price would be above/below (longs/shorts) the current price
:param open_relative_stop: Desired stop loss percentage relative to open price :param open_relative_stop: Desired stop loss percentage, relative to the open price,
adjusted for leverage
:param current_profit: The current profit percentage :param current_profit: The current profit percentage
:param is_short: When true, perform the calculation for short instead of long :param is_short: When true, perform the calculation for short instead of long
:param leverage: Leverage to use for the calculation
:return: Stop loss value relative to current price :return: Stop loss value relative to current price
""" """
# formula is undefined for current_profit -1 (longs) or 1 (shorts), return maximum value # formula is undefined for current_profit -1 (longs) or 1 (shorts), return maximum value
if (current_profit == -1 and not is_short) or (is_short and current_profit == 1): _current_profit = current_profit / leverage
if (_current_profit == -1 and not is_short) or (is_short and _current_profit == 1):
return 1 return 1
if is_short is True: if is_short is True:
stoploss = -1 + ((1 - open_relative_stop) / (1 - current_profit)) stoploss = -1 + ((1 - open_relative_stop / leverage) / (1 - _current_profit))
else: else:
stoploss = 1 - ((1 + open_relative_stop) / (1 + current_profit)) stoploss = 1 - ((1 + open_relative_stop / leverage) / (1 + _current_profit))
# negative stoploss values indicate the requested stop price is higher/lower # negative stoploss values indicate the requested stop price is higher/lower
# (long/short) than the current price # (long/short) than the current price
return max(stoploss, 0.0) return max(stoploss * leverage, 0.0)
def stoploss_from_absolute(stop_rate: float, current_rate: float, is_short: bool = False) -> float: def stoploss_from_absolute(stop_rate: float, current_rate: float, is_short: bool = False) -> float:

View File

@ -177,26 +177,30 @@ def test_stoploss_from_open(side, profitrange):
("long", 0.1, 0.2, 1, 0.08333333), ("long", 0.1, 0.2, 1, 0.08333333),
("long", 0.1, 0.5, 1, 0.266666666), ("long", 0.1, 0.5, 1, 0.266666666),
("long", 0.1, 5, 1, 0.816666666), # 500% profit, set stoploss to 10% above open price ("long", 0.1, 5, 1, 0.816666666), # 500% profit, set stoploss to 10% above open price
("long", 0, 5, 10, 3.3333333), # 500% profit, set stoploss break even
("long", 0.1, 5, 10, 3.26666666), # 500% profit, set stoploss to 10% above open price
("long", -0.1, 5, 10, 3.3999999), # 500% profit, set stoploss to 10% belowopen price
("short", 0, 0.1, 1, 0.1111111), ("short", 0, 0.1, 1, 0.1111111),
("short", -0.1, 0.1, 1, 0.2222222), ("short", -0.1, 0.1, 1, 0.2222222),
("short", 0.1, 0.2, 1, 0.125), ("short", 0.1, 0.2, 1, 0.125),
("short", 0.1, 1, 1, 1), ("short", 0.1, 1, 1, 1),
("short", -0.01, 5, 10, 10.01999999), # 500% profit at 10x
]) ])
def test_stoploss_from_open_leverage(side, rel_stop, curr_profit, leverage, expected): def test_stoploss_from_open_leverage(side, rel_stop, curr_profit, leverage, expected):
stoploss = stoploss_from_open(rel_stop, curr_profit, side == 'short') stoploss = stoploss_from_open(rel_stop, curr_profit, side == 'short', leverage)
assert pytest.approx(stoploss) == expected assert pytest.approx(stoploss) == expected
open_rate = 100 open_rate = 100
if stoploss != 1: if stoploss != 1:
if side == 'long': if side == 'long':
current_rate = open_rate * (1 + curr_profit) current_rate = open_rate * (1 + curr_profit / leverage)
stop = current_rate * (1 - stoploss) stop = current_rate * (1 - stoploss / leverage)
assert pytest.approx(stop) == open_rate * (1 + rel_stop) assert pytest.approx(stop) == open_rate * (1 + rel_stop / leverage)
else: else:
current_rate = open_rate * (1 - curr_profit) current_rate = open_rate * (1 - curr_profit / leverage)
stop = current_rate * (1 + stoploss) stop = current_rate * (1 + stoploss / leverage)
assert pytest.approx(stop) == open_rate * (1 - rel_stop) assert pytest.approx(stop) == open_rate * (1 - rel_stop / leverage)
def test_stoploss_from_absolute(): def test_stoploss_from_absolute():