Merge pull request #6276 from clover-es/feat/short
Add support for shorts in strategy.stoploss_from_absolute()
This commit is contained in:
commit
13978e9893
@ -284,11 +284,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)
|
return stoploss_from_open(0.25, current_profit, is_short=trade.is_short)
|
||||||
elif current_profit > 0.25:
|
elif current_profit > 0.25:
|
||||||
return stoploss_from_open(0.15, current_profit)
|
return stoploss_from_open(0.15, current_profit, is_short=trade.is_short)
|
||||||
elif current_profit > 0.20:
|
elif current_profit > 0.20:
|
||||||
return stoploss_from_open(0.07, current_profit)
|
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short)
|
||||||
|
|
||||||
# return maximum stoploss value, keeping current stoploss price unchanged
|
# return maximum stoploss value, keeping current stoploss price unchanged
|
||||||
return 1
|
return 1
|
||||||
|
@ -791,7 +791,7 @@ Stoploss values returned from `custom_stoploss` must specify a percentage relati
|
|||||||
|
|
||||||
Say the open price was $100, and `current_price` is $121 (`current_profit` will be `0.21`).
|
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)` 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.
|
||||||
|
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
@ -811,7 +811,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)
|
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short)
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@ -832,7 +832,7 @@ In some situations it may be confusing to deal with stops relative to current ra
|
|||||||
|
|
||||||
??? Example "Returning a stoploss using absolute price from the custom stoploss function"
|
??? Example "Returning a stoploss using absolute price from the custom stoploss function"
|
||||||
|
|
||||||
If we want to trail a stop price at 2xATR below current proce we can call `stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate)`.
|
If we want to trail a stop price at 2xATR below current proce we can call `stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate, is_short=trade.is_short)`.
|
||||||
|
|
||||||
``` python
|
``` python
|
||||||
|
|
||||||
@ -852,7 +852,7 @@ In some situations it may be confusing to deal with stops relative to current ra
|
|||||||
current_rate: float, current_profit: float, **kwargs) -> float:
|
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||||
candle = dataframe.iloc[-1].squeeze()
|
candle = dataframe.iloc[-1].squeeze()
|
||||||
return stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate)
|
return stoploss_from_absolute(current_rate - (candle['atr'] * 2, is_short=trade.is_short), current_rate)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ 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,
|
||||||
for_short: bool = False
|
is_short: bool = False
|
||||||
) -> float:
|
) -> float:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -84,15 +84,15 @@ def stoploss_from_open(
|
|||||||
|
|
||||||
:param open_relative_stop: Desired stop loss percentage relative to open price
|
:param open_relative_stop: Desired stop loss percentage relative to open price
|
||||||
:param current_profit: The current profit percentage
|
:param current_profit: The current profit percentage
|
||||||
:param for_short: When true, perform the calculation for short instead of long
|
:param is_short: When true, perform the calculation for short instead of long
|
||||||
: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 for_short) or (for_short and current_profit == 1):
|
if (current_profit == -1 and not is_short) or (is_short and current_profit == 1):
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if for_short is True:
|
if is_short is True:
|
||||||
stoploss = -1+((1-open_relative_stop)/(1-current_profit))
|
stoploss = -1+((1-open_relative_stop)/(1-current_profit))
|
||||||
else:
|
else:
|
||||||
stoploss = 1-((1+open_relative_stop)/(1+current_profit))
|
stoploss = 1-((1+open_relative_stop)/(1+current_profit))
|
||||||
@ -102,9 +102,8 @@ def stoploss_from_open(
|
|||||||
return max(stoploss, 0.0)
|
return max(stoploss, 0.0)
|
||||||
|
|
||||||
|
|
||||||
def stoploss_from_absolute(stop_rate: float, current_rate: float) -> float:
|
def stoploss_from_absolute(stop_rate: float, current_rate: float, is_short: bool = False) -> float:
|
||||||
"""
|
"""
|
||||||
TODO-lev: Update this method with "is_short" formula
|
|
||||||
Given current price and desired stop price, return a stop loss value that is relative to current
|
Given current price and desired stop price, return a stop loss value that is relative to current
|
||||||
price.
|
price.
|
||||||
|
|
||||||
@ -115,6 +114,7 @@ def stoploss_from_absolute(stop_rate: float, current_rate: float) -> float:
|
|||||||
|
|
||||||
:param stop_rate: Stop loss price.
|
:param stop_rate: Stop loss price.
|
||||||
:param current_rate: Current asset price.
|
:param current_rate: Current asset price.
|
||||||
|
:param is_short: When true, perform the calculation for short instead of long
|
||||||
:return: Positive stop loss value relative to current price
|
:return: Positive stop loss value relative to current price
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -123,6 +123,10 @@ def stoploss_from_absolute(stop_rate: float, current_rate: float) -> float:
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
stoploss = 1 - (stop_rate / current_rate)
|
stoploss = 1 - (stop_rate / current_rate)
|
||||||
|
if is_short:
|
||||||
|
stoploss = -stoploss
|
||||||
|
|
||||||
# negative stoploss values indicate the requested stop price is higher than the current price
|
# negative stoploss values indicate the requested stop price is higher/lower
|
||||||
return max(stoploss, 0.0)
|
# (long/short) than the current price
|
||||||
|
# shorts can yield stoploss values higher than 1, so limit that as well
|
||||||
|
return max(min(stoploss, 1.0), 0.0)
|
||||||
|
@ -153,11 +153,22 @@ def test_stoploss_from_open():
|
|||||||
|
|
||||||
|
|
||||||
def test_stoploss_from_absolute():
|
def test_stoploss_from_absolute():
|
||||||
assert stoploss_from_absolute(90, 100) == 1 - (90 / 100)
|
assert pytest.approx(stoploss_from_absolute(90, 100)) == 1 - (90 / 100)
|
||||||
assert stoploss_from_absolute(100, 100) == 0
|
assert pytest.approx(stoploss_from_absolute(90, 100)) == 0.1
|
||||||
assert stoploss_from_absolute(110, 100) == 0
|
assert pytest.approx(stoploss_from_absolute(95, 100)) == 0.05
|
||||||
assert stoploss_from_absolute(100, 0) == 1
|
assert pytest.approx(stoploss_from_absolute(100, 100)) == 0
|
||||||
assert stoploss_from_absolute(0, 100) == 1
|
assert pytest.approx(stoploss_from_absolute(110, 100)) == 0
|
||||||
|
assert pytest.approx(stoploss_from_absolute(100, 0)) == 1
|
||||||
|
assert pytest.approx(stoploss_from_absolute(0, 100)) == 1
|
||||||
|
|
||||||
|
assert pytest.approx(stoploss_from_absolute(90, 100, True)) == 0
|
||||||
|
assert pytest.approx(stoploss_from_absolute(100, 100, True)) == 0
|
||||||
|
assert pytest.approx(stoploss_from_absolute(110, 100, True)) == -(1 - (110/100))
|
||||||
|
assert pytest.approx(stoploss_from_absolute(110, 100, True)) == 0.1
|
||||||
|
assert pytest.approx(stoploss_from_absolute(105, 100, True)) == 0.05
|
||||||
|
assert pytest.approx(stoploss_from_absolute(100, 0, True)) == 1
|
||||||
|
assert pytest.approx(stoploss_from_absolute(0, 100, True)) == 0
|
||||||
|
assert pytest.approx(stoploss_from_absolute(100, 1, True)) == 1
|
||||||
|
|
||||||
|
|
||||||
# TODO-lev: @pytest.mark.parametrize('candle_type', ['mark', ''])
|
# TODO-lev: @pytest.mark.parametrize('candle_type', ['mark', ''])
|
||||||
|
Loading…
Reference in New Issue
Block a user