When I try to make a portfolio strategy based on yearly constituent lists, my code works. But when I try it for monthly constituent lists, it does not work. You can find my code for the yearly strategy below:
class EquallyWeighted(bt.Strategy):
params = (
('constituent_companies', {}), # a dictionary mapping year to list of consistent companies
)
def __init__(self):
self.current_year = self.datas[0].datetime.date().year
self.constituent_companies = self.params.constituent_companies.get(self.current_year, [])
self.weights = {} # Dictionary to store the weights for each company
def next(self):
if self.datas[0].datetime.date().year != self.current_year:
self.current_year = self.datas[0].datetime.date().year
self.close_all_positions() # close all positions
self.constituent_companies = self.params.constituent_companies.get(self.current_year, [])
self.calculate_weights() # calculate new weights for the constituent companies
for i, d in enumerate(self.datas):
if not self.getposition(d).size:
if d._name in self.constituent_companies:
size = self.broker.get_cash() * self.weights[d._name] # calculate position size based on weight
self.buy(data=d, size=size)
def close_all_positions(self):
for i, d in enumerate(self.datas):
position = self.getposition(d).size
if position > 0:
self.close(data=d)
def calculate_weights(self):
num_companies = len(self.constituent_companies)
if num_companies > 0:
weight = 1.0 / num_companies
for company in self.constituent_companies:
self.weights[company] = weight
if name == 'main':
# Create a cerebro entity
cerebro = bt.Cerebro()
# Define the path to the CSV file
base_path = '/Users/jonat/Documents/Documenten/data/Test/Constituents/'
# Read constituent companies for each year
constituent_companies = {}
years = [2000, 2001, 2002, 2003, 2004] # Update with your desired years
for year in years:
csv_path = base_path + f'constituent_companies_{year}.csv'
with open(csv_path, 'r', encoding='utf-8-sig') as csvfile:
reader = csv.reader(csvfile)
next(reader) # Skip the header row
companies = [row[0] for row in reader if row[0]] # Read company names from column A
constituent_companies[year] = companies
cerebro.addstrategy(EquallyWeighted, constituent_companies=constituent_companies)
datalist = ['AAPL.csv', 'DIS.csv', 'IBM.csv', 'BA.csv', 'F.csv', 'GE.csv', 'KO.csv', 'MMM.csv', 'PG.csv', 'XOM.csv']
datapath= "/Users/jonat/Documents/Documenten/data/Test/"
for i in range(len(datalist)):
data= bt.feeds.YahooFinanceCSVData(
dataname=datapath+datalist[i],
# Do not pass values before this date
fromdate=datetime(2000, 1, 1),
# Do not pass values after this date
todate=datetime(2004, 12, 31),
reverse=False)
cerebro.adddata(data, name=datalist[i])
# Set our desired cash start
cerebro.broker.setcash(1000.0)
# Add a FixedSize sizer according to the stake
cerebro.addsizer(bt.sizers.PercentSizer, percents=10)
# Set the commission
cerebro.broker.setcommission(commission=0.0)
# Print out the starting conditions
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Run over everything
cerebro.run()
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
You can find my code for the monthly strategy below:
class EquallyWeightedM(bt.Strategy):
params = (
('constituent_companies', {}), # a dictionary mapping year to list of consistent companies
)
def __init__(self):
self.constituent_companies = constituent_companies
self.weights = {} # Dictionary to store the weights for each company
def start(self):
self.calculate_weights()
def next(self):
for i, d in enumerate(self.datas):
if not self.getposition(d).size:
if d._name in self.weights:
size = self.broker.get_cash() * self.weights[d._name] # calculate position size based on weight
self.buy(data=d, size=size)
def calculate_weights(self):
num_companies = len(self.constituent_companies)
if num_companies > 0:
weight = 1.0 / num_companies
for company in self.constituent_companies:
self.weights[company] = weight
if name == 'main':
cerebro = bt.Cerebro()
cerebro.addstrategy(EquallyWeightedM, constituent_companies=constituent_companies)
base_path = '/Users/jonat/Documents/Documenten/data/Test/Constituents/'
dates = [datetime(2000, 1, 1), datetime(2000, 2, 1), datetime(2000, 3, 1), datetime(2000, 4, 1), datetime(2000, 5, 1)]
for date in dates:
csv_path = base_path + f'constituent_companies_{date.strftime("%Y-%m-%d")}.csv'
with open(csv_path, 'r', encoding='utf-8-sig') as csvfile:
reader = csv.reader(csvfile)
next(reader) # Skip the header row
companies = [row[0] for row in reader if row[0]] # Read company names from column A
datalist = ['AAPL.csv', 'DIS.csv', 'IBM.csv', 'BA.csv', 'F.csv', 'GE.csv', 'KO.csv', 'MMM.csv', 'PG.csv', 'XOM.csv']
datapath= "/Users/jonat/Documents/Documenten/data/Test/"
for i in range(len(datalist)):
data = bt.feeds.YahooFinanceCSVData(
dataname=datapath+datalist[i],
fromdate=datetime(2000, 1, 1),
todate=datetime(2004, 12, 31),
reverse=False
)
cerebro.adddata(data, name=datalist[i])
cerebro.broker.setcash(1000.0)
cerebro.addsizer(bt.sizers.PercentSizer, percents=10)
cerebro.broker.setcommission(commission=0.0)
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
cerebro.run()
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
Can someone help me out?