Skip to content

Commit

Permalink
Merge pull request #2 from zlpatel/kernc#223
Browse files Browse the repository at this point in the history
Trailing pct instead of ATR kernc#223
  • Loading branch information
zlpatel authored Jun 13, 2021
2 parents 2cc6724 + d6fa851 commit d81ae85
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
34 changes: 34 additions & 0 deletions backtesting/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,40 @@ def next(self):
trade.sl = min(trade.sl or np.inf,
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_percent = 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_percent = percentage

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_percent/100)))
else:
trade.sl = min(trade.sl or np.inf,
self.data.Close[index]*(1+(self._sl_percent/100)))

# Prevent pdoc3 documenting __init__ signature of Strategy subclasses
for cls in list(globals().values()):
Expand Down
15 changes: 15 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,20 @@ 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 d81ae85

Please sign in to comment.