Thanks for the replies, I'll double check the code and will see what happens.
Latest posts made by howardhh
-
RE: Multiple data feeds - different order gives different trades
-
RE: Multiple data feeds - different order gives different trades
Apologies, I wasn't aware of that. Will definitely use it next time.
Regarding the data feed order though, where do you think the problem is?
Thank you.
-
Multiple data feeds - different order gives different trades
Hi,
I have 3 different data feeds but when I change the order of those around, my strategy gives different trades/ results. I have been able to narrow this down to the Startegy Class itself, but am not sure why this is happening.
Can someone please help? Thanks in advance.
import backtrader as bt
from datetime import datetime
from datetime import timedeltaclass maCross(bt.Strategy):
'''
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): feeds_with_data = [(i, d) for i, d in enumerate(self.datas) if len(d)] for i, d in feeds_with_data: # 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 eofthisday = self.datas[i].datetime.date() #get current date expiry = eofthisday + timedelta(days=4) #keep order active for 4 days (over weekend + public hol) self.buy_bracket(data=d, limitprice=10000, price=self.datas[i].close[0], stopprice=stop_price, exectype=bt.Order.Limit, size=qty, valid=expiry) else: pass else: pass else: pass else: if self.inds[d]['crossDown'][0] == -1: # if cci crosses down 100 self.close(data=d) def notify_trade(self, trade): dt = self.data.datetime.date() if trade.isclosed: print('{} {} Closed: PnL Gross {}, Net {}'.format( dt, trade.data._name, round(trade.pnl, 2), round(trade.pnlcomm, 2)))
datalist = [
('data_adjusted/CBA.AX.csv', 'CBA.AX'),
('data_adjusted/CSL.AX.csv', 'CSL.AX'),
('data_adjusted/BSL.AX.csv', 'BSL.AX'),
]For example when I swap the order of CBA and BSL with each other, the trades taken are different and I get a different end result.
Thanks again, appreciate any help available.
-
Prenext - does something weird
Hi,
I'm trying to backtest over multiple stocks at once. One of the stocks was only listed after testing date and I found that adding prenext allowed the code to be run over the entire testing range. However, it does something odd regarding that stock:
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): # 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 eofthisday = self.datas[i].datetime.date() #get current date expiry = eofthisday + timedelta(days=4) #keep order active for 4 days (over weekend + public hol) self.buy_bracket(data=d, limitprice=10000, price=self.datas[i].close[0], stopprice=stop_price, exectype=bt.Order.Limit, size=qty, valid=expiry) else: pass else: pass else: pass else: if self.inds[d]['crossDown'][0] == -1: # if cci crosses down 100 self.close(data=d) def notify_trade(self, trade): dt = self.data.datetime.date() if trade.isclosed: print('{} {} Closed: PnL Gross {}, Net {}'.format( dt, trade.data._name, round(trade.pnl, 2), round(trade.pnlcomm, 2)))
The results I got seemed alright, except for the starred line (see below). It makes a very weird trade on the day of listing (data start) for A2M. I think this can be fixed using prenext but am not quite sure how to. Any help is greatly appreciated. Thank you.
results:
2014-08-29 BSL.AX Closed: PnL Gross -66.25, Net -79.45
2014-10-21 CSL.AX Closed: PnL Gross 37.16, Net 23.96
2015-02-03 CSL.AX Closed: PnL Gross 83.01, Net 69.81
2015-02-25 CSL.AX Closed: PnL Gross 106.62, Net 93.42
2015-03-30 A2M.AX Closed: PnL Gross -1894.41, Net -1907.61 ***********
2015-07-24 CSL.AX Closed: PnL Gross 60.94, Net 47.74
2015-10-12 CSL.AX Closed: PnL Gross 35.94, Net 22.74
2015-11-15 CSL.AX Closed: PnL Gross 117.94, Net 104.74
2016-04-29 CSL.AX Closed: PnL Gross 56.86, Net 43.66 -
RE: Position sizing and stop losses mess up trading strategy
@ab_trader Ahhh I see. All fixed up. Thanks heaps.
-
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.
-
RE: Not all available trades taken
@ab_trader That was actually it haha. Thanks for that. I'm literally just starting out and it's really tough.
But cheers for the assistance, very much appreciated.
-
Not all available trades taken
Hi there,
I'm a newbie to algo trading and am running into some problems. I've been trying to backtest a trend-following strategy where I enter if the EMA50 > EMA200 and when the CCI20 crosses the -100. Sell when EMA50 and EMA200 cross lower.
The problem is that backtrader is only taking some trades and not others for some reason. Can someone please help explain why this is the case and how I can solve this?
Thanks, Howard
Here is my code for the strategy:
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']) #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=1000) else: pass else: pass else: if self.inds[d]['EMAcross'][0] == -1: self.close(data=d) def notify_trade(self, trade): dt = self.data.datetime.date() if trade.isclosed: print('{} {} Closed: PnL Gross {}, Net {}'.format( dt, trade.data._name, round(trade.pnl, 2), round(trade.pnlcomm, 2)))