The strategy I'm trying to do is quite simple: Buy at -50% from a rolling 5-year peak, and sell after 2 years. Each trade will be allotted a size of 20% of the portfolio total value. Below is the code I wrote.
My problem is that it enters into trades many more times than my intention. But this issue only happens with a part of the trades. I think the problem is mainly with the sizer, because I tried my code with the built-in percent sizer (20% of cash), and that worked perfectly fine.
class dss(bt.Strategy):
params = (
('look_back_weeks', 260),
('drawdown_threshold', 0.5),
('hold_weeks', 104)
)
def __init__(self):
pass
def start(self):
self.eq_progression = []
self.trade_dates = []
self.bought_bars={d:0 for d in self.getdatanames()}
self.cash_start = self.broker.get_cash()
print("Date;Security;Size;Entry_Price;Exit_price")
def next(self):
self.trade_dates += [self.datetime.date()]
self.eq_progression += [cerebro.broker.getvalue()]
for i, d in enumerate(self.datas):
if not self.getposition(d).size:
if len(self) < self.params.look_back_weeks:
drawdown = d[0]/max(d.get(size = len(self)).tolist())
else:
drawdown = d[0]/max(d.get(size = self.params.look_back_weeks).tolist())
if drawdown < self.params.drawdown_threshold:
self.buy(data = d)
self.bought_bars[self.getdatanames()[i]] = len(self)
elif (len(self) - self.bought_bars[self.getdatanames()[i]]) >= self.params.hold_weeks:
print(self.datetime.date(),";",
self.getdatanames()[i],";",
self.broker.getposition(d).size,";",
self.broker.getposition(d).price,";",
d[0]
)
self.sell(data = d)
class ValuePercentSizer(bt.Sizer):
params = (
('percents', 20),
('retint', True),# return an int size or rather the float value
)
def __init__(self):
pass
def _getsizing(self, comminfo, cash, data, isbuy):
position = self.broker.getposition(data)
accvalue = self.broker.getvalue()
if not position:
size = accvalue / data.close[0] * (self.params.percents / 100)
else:
size = position.size
if self.p.retint:
size = int(size)
return size