Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

    Real return analyzer?

    Indicators/Strategies/Analyzers
    2
    4
    500
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      brettelliot last edited by

      Hi everyone,

      I'm grateful for this tool and community and hope I can contribute something meaningful soon! In the meantime, I was wondering if anyone has built a "real return" analyzer?

      Im using this for asset allocation research and I have monthly data going back decades. I already use the Returns analyzer for getting the CAGR and I was hoping get a similar "real returns" metric that takes inflation into account. I have the monthly CPI data so I was wondering how I would do that?

      Thanks!
      Brett

      1 Reply Last reply Reply Quote 0
      • B
        brettelliot last edited by

        Hi guys,

        Let me change my question a bit.... What I want at the end is the total compound return adjust for inflation.

        I guess at a high level, I could do this two ways....

        Method 1: adjust the prices before adding to feeds and then just use the Returns analyze as is.

        Method 2: Leave the feeds alone, use then with annual returns from the annualReturn analyzer, adjust the those by annual inflation rate and then recompute the compound annual return.

        Would either of those work? Is there a preferred method?

        run-out 1 Reply Last reply Reply Quote 0
        • run-out
          run-out @brettelliot last edited by

          @brettelliot Perhaps easiest to just capture the value in the account at the end of each bar. I would probably choose to export this to a dataframe. There you can calculate the nominal period returns and divide by the inflation returns to get real returns.

          Here is a custom analyzer you can use to capture the value in the account at the end of each bar.

          class CashMarket(bt.analyzers.Analyzer):
              """
              Analyzer returning cash and market values
              """
              def create_analysis(self):
                  self.rets = {}
                  self.vals = 0.0
          
              def notify_cashvalue(self, cash, value):
                  self.vals = (cash, value)
                  self.rets[self.strategy.datetime.datetime()] = self.vals
          
              def get_analysis(self):
                  return self.rets
          

          RunBacktest.com

          1 Reply Last reply Reply Quote 1
          • B
            brettelliot last edited by

            @run-out Cool. Took your advice! Here's what I ended up with.

            First, I wrote a simple CAGR analyzer that anyone can use:

            class CAGRAnalyzer(bt.analyzers.Analyzer):
                """
                Analyzer returning CAGR of the portfolio
                """
            
                def nextstart(self):
                    self.rets = AutoOrderedDict()
                    self.rets.start_value = self.strategy.broker.getvalue()
                    self.rets.start_date = self.strategy.datetime.datetime().date()
            
                def stop(self):
                    self.rets.end_value = self.strategy.broker.getvalue()
                    self.rets.end_date = self.strategy.datetime.datetime().date()
                    self.rets.num_years = (self.rets.end_date - self.rets.start_date).days / 365.25
                    self.rets.cagr = self.calculate_cagr(self.rets.start_value, self.rets.end_value, self.rets.num_years)
            
                def calculate_cagr(self, start_value, end_value, num_years):
                    """
                    The CAGR formula is: 
                        EV / BV ^ (1/n) – 1. 
                    EV and BV are the ending and beginning values, while n is the number of time periods (usually months or years) 
                    for which you are calculating an average. The ^ character means “to the power of”; we take the ratio of EV / BV 
                    and raise it to the power of 1/n. Subtracting one (one = 100%)
                    """
                    return ((end_value / start_value) ** (1 / num_years)) - 1
            

            Next, I derived a real CAGR analyzer from it which pulls in a csv file of CPI data and calculates the annualized inflation rate and finally the real CAGR:

            
            class RealCAGRAnalyzer(CAGRAnalyzer):
                params = (('cpi_data_file_path', None),)
                """
                Analyzer returning the real CAGR (adjusted for inflation using values from a csv passed in with 
                a "date" column and a "us_cpi" column
                """
            
                def __init__(self):
                    self.cpi_data_file_path = self.params.cpi_data_file_path
                    self.cpi_data = pd.read_csv(self.cpi_data_file_path, parse_dates=['date'], index_col=0)
            
                def nextstart(self):
                    super(RealCAGRAnalyzer, self).nextstart()
                    self.rets.start_cpi = self.cpi_data.loc[pd.to_datetime(self.rets.start_date)]['us_cpi']
            
                def stop(self):
                    super(RealCAGRAnalyzer, self).stop()
                    self.rets.end_cpi = self.cpi_data.loc[pd.to_datetime(self.rets.end_date)]['us_cpi']
                    self.rets.cagr = self.calculate_cagr(self.rets.start_value, self.rets.end_value, self.rets.num_years)
                    self.rets.annualized_inflation_rate = self.calculate_cagr(self.rets.start_cpi, self.rets.end_cpi, self.rets.num_years)
                    self.rets.real_cagr = self.annualized_real_return(self.rets.cagr, self.rets.annualized_inflation_rate)
            
                def annualized_real_return(self, nominal_cagr, annualized_inflation_rate):
                    """
                    Annualized Real Return = ((1 + CAGR / 1 + annualized inflation rate) – 1) X 100
                    """
                    return (1 + nominal_cagr) / (1 + annualized_inflation_rate) - 1
            

            Though im not an expert in finance, everything looks reasonable:

            start_date: 1913-01-31
            end_date: 2020-11-30
            start_value: $100,000.00
            end_value: $38,158,746.88
            num_years: 107.83
            start_cpi: $9.8
            end_cpi: $260.23
            cagr: 5.67%
            annualized_inflation_rate: 3.09%
            real_cagr: 2.50%
            

            Thanks for the help!

            1 Reply Last reply Reply Quote 1
            • 1 / 1
            • First post
              Last post
            Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors