0

I am able to make a strategy in backtrader which equally invest in stocks based on a yearly constituent list. But if I change the code to monthly constituent lists the portfolio value remains the same. I cannot find what the problem is and how there is no match between the dates of the data and the dates of the constituent lists.

Here you can find the code for a yearly strategy

`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())`

Here you can find the code for a monthly strategy.

`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())
jondej
  • 1

0 Answers0