Position sizing and stop losses mess up trading strategy
-
Hi again,
Apologies in advance but I will likely be posting a lot of questions since I am just starting out. Thanks for the help so far.
Instead of simply buying 10 shares at a time I've added to my code a position sizing mechanism (where I risk 100 dollars per trade with a stop loss 5% below entry price). The strategy worked fine before I added this (buy when ema50 > ema200 when cci crosses up -100, sell when cci crosses down 100) but after I added in the position sizer/ stop loss, it turns weird.
Original working code:
class maCross(bt.Strategy):
'''
For an official backtrader blog on this topic please take a look at:https://www.backtrader.com/blog/posts/2017-04-09-multi-example/multi-example.html oneplot = Force all datas to plot on the same master. ''' params = ( ('ema50', 50), ('ema200', 200), ('cci20', 20), ('oneplot', True) ) def __init__(self): ''' Create an dictionary of indicators so that we can dynamically add the indicators to the strategy using a loop. This mean the strategy will work with any number of data feeds. ''' self.inds = dict() for i, d in enumerate(self.datas): self.inds[d] = dict() self.inds[d]['ema50'] = bt.indicators.ExponentialMovingAverage( d.close, period=self.params.ema50) self.inds[d]['ema200'] = bt.indicators.ExponentialMovingAverage( d.close, period=self.params.ema200) self.inds[d]['cci20'] = bt.indicators.CommodityChannelIndex( period=self.params.cci20) self.inds[d]['crossUp'] = bt.indicators.CrossOver(self.inds[d]['cci20'], -100) # crossup = 1 self.inds[d]['EMAcross'] = bt.indicators.CrossOver(self.inds[d]['ema50'], self.inds[d]['ema200']) self.inds[d]['crossDown'] = bt.indicators.CrossOver(self.inds[d]['cci20'], 100) # crossdown = -1 if i > 0: # Check we are not on the first loop of data feed: if self.p.oneplot == True: d.plotinfo.plotmaster = self.datas[0] def prenext(self): self.next() def next(self): for i, d in enumerate(self.datas): dt, dn = self.datetime.date(), d._name pos = self.getposition(d).size if not pos: # no market / no orders if self.inds[d]['ema50'] >= self.inds[d]['ema200']: if self.inds[d]['crossUp'][0] == 1: self.buy(data=d, size=10) else: pass else: pass else: if self.inds[d]['crossDown'][0] == -1: self.close(data=d)
I changed the next function to:
def next(self): for i, d in enumerate(self.datas): #calculate risk/ stop price risk = 100 #risk = 100 dollars stop = 0.05 #stop 5% below close stop_price = self.datas[i].close[0]*(1-stop) dt, dn = self.datetime.date(), d._name pos = self.getposition(d).size if not pos: # no market / no orders if self.inds[d]['ema50'] >= self.inds[d]['ema200']: if self.inds[d]['crossUp'][0] == 1: #if CCI crosses up -100 if self.datas[i].close[0] - stop_price > 0: #check if risk is acceptable/ valid qty = round(risk / (self.datas[i].close[0] - stop_price),0) #get no. of shares to trade self.buy_bracket(data=d, limitprice=self.datas[i].close[0], price=self.datas[i].close[0], stopprice=stop_price, exectype=bt.Order.Limit, size=qty) else: pass else: pass else: pass else: if self.inds[d]['crossDown'][0] == -1: #if cci crosses down 100 self.close(data=d)
I can't tell what I've done wrong but it seems like the trades are now buy when cci20 crosses down -100 and sell when it crosses back up.
Thanks heaps for any input.
-
@howardhh just a thoughts based on your
buy_bracket
order:- you send main order as
limit
on close price bt
opens it if possible, and- than
bt
closes it at bracket'slimitprice
on the same close
You may want to increase your
limitprice
to get the profit. - you send main order as
-
@ab_trader Ahhh I see. All fixed up. Thanks heaps.