Real return analyzer?
-
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 -
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?
-
@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
-
@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!