Like @dongbuluo I am also getting the same issue with YahooFinanceData. My strategy is below:
class Test_MA_Multi(bt.Strategy):
params = (
('hold', 7),
('MA1', 5),
('MA2', 20),
('oneplot', False),
)
def __init__(self):
self.inds = dict()
for i, d in enumerate(self.datas):
self.inds[d] = dict()
self.inds[d]['MA1'] = bt.indicators.SMA(
d.close, period=self.params.MA1)
self.inds[d]['MA2'] = bt.indicators.SMA(
d.close, period=self.params.MA2)
self.inds[d]['cross'] = bt.indicators.CrossOver(self.inds[d]
['MA1'],self.inds[d]['MA2'], plot = False)
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 notify_order(self, order):
dt, dn = self.datetime.date(), order.data._name
if order.status in [order.Completed]:
if order.isbuy():
print('{} BUY EXECUTED {} at {}, cost {}, com {}'.format(
dt, dn,
order.executed.price,
order.executed.value,
order.executed.comm))
else:
print('{} SELL EXECUTED {} at {}, cost {}, com
{}'.format(
dt, dn,
order.executed.price,
order.executed.value,
order.executed.comm))
self.bar_executed = len(self)
elif order.status in [order.Canceled, order.Margin,
order.Rejected]:
print('{} Order Canceled/Margin/Rejected {} {}'.format(dt,
dn, order.status))
if order.status in [order.Margin]:
print('MARGIN')
self.order = None
def prenext(self):
self.next()
def notify_trade(self, trade):
if trade.justopened:
self.trade_length = 0
if not trade.isclosed:
return
print('{} OPERATION PROFIT {}: {} days, GROSS {:.2f}, NET {:.2f}'.format(self.datetime.date(),trade.data._name,self.trade_length,trade.pnl, trade.pnlcomm))
self.trade_length = None
def next(self):
for i, d in enumerate(self.datas):
dt, dn = self.datetime.date(), d._name
pos = self.getposition(d).size
if pos > 0:
self.trade_length += 1
print('{} {} Position: SHARES: {}, PRICE: {:.2f}, VALUE: {:.2f}, {} days'.format(dt, dn, pos, d.close[0], self.broker.get_value(),self.trade_length))
if self.inds[d]['cross'] < 0:
self.close()
elif self.trade_length >= self.p.hold:
o = self.close(data = d)
print('{} {} Manual Close'.format(dt, dn))
else:
if pos != 0:
print('THIS IS WRONG')
print('CASH: {}'.format(self.broker.get_cash()))
self.order_target_percent(data = d, target = .99)
cerebro = bt.Cerebro(cheat_on_open = False)
for i in data['Assets']:
# sData = bt.feeds.Quandl(dataname= i, apikey='xxx', fromdate = start_date, todate = end_date)
sData = bt.feeds.YahooFinanceData(dataname = i, fromdate = start_date, todate = end_date)
# sData = bt.feeds.YahooFinanceCSVData(dataname =
# '/YahooCSVS/' + i + '.csv',
# fromdate = start_date, todate = end_date)
cerebro.adddata(sData, name = i)
cerebro.addstrategy(Test_MA_Multi)
pv = 1000
cerebro.broker.setcash(pv)
cerebro.broker.setcommission(commission = 0.01)
cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='mysharpe')
cerebro.addanalyzer(bt.analyzers.AnnualReturn, _name='myannual')
cerebro.addanalyzer(bt.analyzers.DrawDown, _name='mydrawdown')
# Run over everything
thestrats = cerebro.run(runonce = True)
thestrat = thestrats[0]
print('Sharpe Ratio:', thestrat.analyzers.mysharpe.get_analysis())
print('Annual Return:', thestrat.analyzers.myannual.get_analysis())
print('Drawdown Info:', thestrat.analyzers.mydrawdown.get_analysis())
print('Starting Portfolio Value: %.2f' % pv)
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
print('Return: {:.2f}%' .format((int(cerebro.broker.getvalue()) / int(pv) - 1) * 100))
b = Bokeh(style='bar', plot_mode='single', plot_width=800, plot_height=3000)
cerebro.plot(b)
plt.savefig('samplefig.png')
Basically buys and holds a position for a maximum for 14 days and trys to sell early if the two moving averages cross. I have other code that switches the active stock by using a dictionary of strings to ints for the ticker names to 0/1 if the stock is the active one, and use in if statement in the next to use the right ticker. However, this shouldn't affect the data feeds.
Also when adding the data feeds the:
for i in data['Assets']:
makes i
a string with the ticker.
Here is the output of my code:
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
<ipython-input-11-981141189bb6> in <module>
3 cerebro.addanalyzer(bt.analyzers.DrawDown, _name='mydrawdown')
4 # Run over everything
----> 5 thestrats = cerebro.run(runonce = True)
6
7 thestrat = thestrats[0]
~/opt/anaconda3/envs/IKF/lib/python3.9/site-packages/backtrader/cerebro.py in run(self, **kwargs)
1125 # let's skip process "spawning"
1126 for iterstrat in iterstrats:
-> 1127 runstrat = self.runstrategies(iterstrat)
1128 self.runstrats.append(runstrat)
1129 if self._dooptimize:
~/opt/anaconda3/envs/IKF/lib/python3.9/site-packages/backtrader/cerebro.py in runstrategies(self, iterstrat, predata)
1208 if self._exactbars < 1: # datas can be full length
1209 data.extend(size=self.params.lookahead)
-> 1210 data._start()
1211 if self._dopreload:
1212 data.preload()
~/opt/anaconda3/envs/IKF/lib/python3.9/site-packages/backtrader/feed.py in _start(self)
201
202 def _start(self):
--> 203 self.start()
204
205 if not self._started:
~/opt/anaconda3/envs/IKF/lib/python3.9/site-packages/backtrader/feeds/yahoo.py in start(self)
353
354 # Prepared a "path" file - CSV Parser can take over
--> 355 super(YahooFinanceData, self).start()
356
357
~/opt/anaconda3/envs/IKF/lib/python3.9/site-packages/backtrader/feeds/yahoo.py in start(self)
92
93 def start(self):
---> 94 super(YahooFinanceCSVData, self).start()
95
96 if not self.params.reverse:
~/opt/anaconda3/envs/IKF/lib/python3.9/site-packages/backtrader/feed.py in start(self)
672 else:
673 # Let an exception propagate to let the caller know
--> 674 self.f = io.open(self.p.dataname, 'r')
675
676 if self.p.headers:
FileNotFoundError: [Errno 2] No such file or directory: 'MRO'
If you need more info from me, ask. It most likely is an issue with YahooFinance becuase I haven't changed my yahoo.py (can send that too) and it was working two days ago. Thanks.