For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

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's limitprice on the same close

    You may want to increase your limitprice to get the profit.



  • @ab_trader Ahhh I see. All fixed up. Thanks heaps.


Log in to reply
 

});