Skip to content

Commit

Permalink
Trailing pct instead of ATR kernc#223
Browse files Browse the repository at this point in the history
  • Loading branch information
zlpatel committed Jun 15, 2021
1 parent 0a76e96 commit baeeb5e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
37 changes: 37 additions & 0 deletions backtesting/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,43 @@ def next(self):
self.data.Close[index] + self.__atr[index] * self.__n_atr)


class PercentageTrailingStrategy(Strategy):
"""
A strategy with automatic trailing stop-loss, trailing the current
price at distance of some percentage. Call
`PercentageTrailingStrategy.set_trailing_sl()` to set said percentage
(`5` by default). See [tutorials] for usage examples.
[tutorials]: index.html#tutorials
Remember to call `super().init()` and `super().next()` in your
overridden methods.
"""
_sl_pct = 5.

def init(self):
super().init()

def set_trailing_sl(self, percentage: float = 5):
assert percentage > 0, "percentage must be greater than 0"
"""
Sets the future trailing stop-loss as some (`percentage`)
percentage away from the current price.
"""
self._sl_pct = percentage/100

def next(self):
super().next()
index = len(self.data)-1
for trade in self.trades:
if trade.is_long:
trade.sl = max(trade.sl or -np.inf,
self.data.Close[index]*(1-self._sl_pct))
else:
trade.sl = min(trade.sl or np.inf,
self.data.Close[index]*(1+self._sl_pct))


# Prevent pdoc3 documenting __init__ signature of Strategy subclasses
for cls in list(globals().values()):
if isinstance(cls, type) and issubclass(cls, Strategy):
Expand Down
16 changes: 16 additions & 0 deletions backtesting/test/_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
quantile,
SignalStrategy,
TrailingStrategy,
PercentageTrailingStrategy,
resample_apply,
plot_heatmaps,
random_ohlc_data,
Expand Down Expand Up @@ -862,6 +863,21 @@ def next(self):
stats = Backtest(GOOG, S).run()
self.assertEqual(stats['# Trades'], 57)

def test_PercentageTrailingStrategy(self):
class S(PercentageTrailingStrategy):
def init(self):
super().init()
self.set_trailing_sl(5)
self.sma = self.I(lambda: self.data.Close.s.rolling(10).mean())

def next(self):
super().next()
if not self.position and self.data.Close > self.sma:
self.buy()

stats = Backtest(GOOG, S).run()
self.assertEqual(stats['# Trades'], 91)


class TestUtil(TestCase):
def test_as_str(self):
Expand Down

0 comments on commit baeeb5e

Please sign in to comment.