def big_drop(after=10): # 20 years of ZIRP to exhaust bonds under Prime Harvesting for i in range(after): yield AnnualChange(year=0, stocks=Decimal('.04'), bonds=Decimal('0'), inflation=Decimal('.02')) # big drop of stocks to allow rebalacing to "buy stocks cheap" yield AnnualChange(year=0, stocks=Decimal('-.25'), bonds=Decimal('0'), inflation=Decimal('.02')) # now we just have normal (but not amazing) returns..... while True: yield AnnualChange(year=0, stocks=Decimal('.08'), bonds=Decimal('.04'), inflation=Decimal('.03'))
def fmt(self, row): (stocks, bonds, inflation) = (Decimal(row[x]) / 100 for x in ("VFINX", "IT Bonds", "CPI-U")) return AnnualChange(year=row['Year'], stocks=stocks, bonds=bonds, inflation=inflation)
def fmt(self, row): return AnnualChange( year=row.name, stocks=row['NIKKEI225'], bonds=row['Spliced Bond'], inflation=row['CPI Japan'] )
def fmt(self, row): return AnnualChange( year=row.name, stocks=row['Equities'], bonds=row['IT Bond'], inflation=row['CPI'] )
def fmt(self, row): # the database only provides the consumer price index level, not the # annual change. I don't feel like going back and calculating it. return AnnualChange(year=row.year, stocks=Decimal(row.eq_tr), bonds=Decimal(row.bond_tr), inflation=Decimal(row.cpi))
def fmt(self, row): return AnnualChange( year=row.name.year, stocks=Decimal(row['S&P %']), bonds=Decimal(row['Bond %']), inflation=0 # it is already reported in real terms )
def random_year(self): s = random.lognormvariate(self.stocks_mean, self.stocks_stddev) - 1 s = Decimal(s) b = random.lognormvariate(self.bonds_mean, self.bonds_stddev) - 1 b = Decimal(b) return AnnualChange(year=self.year, stocks=s, bonds=b, inflation=Decimal(0))
def fmt(self, row): stock_performance = [row[x] * self.weights._asdict()[x] for x in self.asset_classes] stock_performance = sum(stock_performance) return AnnualChange( year=row['Year'], stocks=Decimal(stock_performance) / 100, bonds=Decimal(row['IT Bonds']) / 100, inflation=Decimal(row['CPI-U']) / 100 )
def random_year(self): if random.randint(1, 100) < 75: stddev = .08 else: stddev = .30 r = random.lognormvariate(self.mean, stddev) - 1 r = Decimal(r) return AnnualChange(year=0, stocks=r, bonds=r, inflation=Decimal(0))
def fmt(self, row): (stocks, bonds, inflation) = (Decimal(row[x]) for x in ("Real Equity", "Real Gilt", "Inflation")) return AnnualChange(year=row.name.year, stocks=stocks + inflation, bonds=bonds + inflation, inflation=inflation)
def fmt(self, row): (stocks, bonds, inflation) = (Decimal(row[x]) for x in ("Real Equity", "Real Gilt", "Inflation")) if stocks < -1: print(row) import pdb;pdb.set_trace() return AnnualChange( year=row.name.year, stocks=stocks, bonds=bonds, inflation=0 # always 0 since the others are 'real' )
def random_year(self): y_prev = self.y_prev # first determine bond yields based on previous year ey = random.normalvariate(0, .009) y_new = self.ay + (self.by * y_prev) y_new += ey y_new = clip(y_new, .01, .10) delta_y = (y_new - y_prev) # now determine total returns for cash ec = random.normalvariate(0, .01) rc = self.ac + (self.bc * y_new) + (self.byc * delta_y) rc += ec rc = clip(rc, 0, .10) # now determine return for bonds, stocks, and inflation def calc_returns(ai, byi, bc, by_delta_i, e_stddev, min, max): ei = random.normalvariate(0, e_stddev) n = ( ai + (bc * rc) + (byi * y_new) + (by_delta_i * delta_y) ) n += ei return clip(n, min, max) rs = {} for k in self.coeffs: # Does this generate real or nominal returns for the stocks & bonds? rs[k] = calc_returns(*self.coeffs[k]) if self.logging: self.log.loc[self.year] = (y_prev, y_new, rc, rs['stocks'], rs['bonds'], rs['inflation']) self.y_prev = y_new self.year += 1 return AnnualChange( year=self.year, stocks=Decimal(rs['stocks']), bonds=Decimal(rs['bonds']), inflation=Decimal(rs['inflation']) )
def random_year(self): y_prev = self.y_prev ey = random.normalvariate(0, .0125) y_new = 0.225/100 + (0.95 * y_prev) + ey y_new = clip(y_new, .01, .10) ebond = random.normalvariate(0, .015) r_bonds = 0 + (1.0 * y_new) + (-8.0 * (y_new - y_prev)) + ebond # Blanchett doesn't provide min/max for r_bonds # I'll reuse the min/max from LowYieldsAutoRegression r_bonds = clip(r_bonds, -.15, .40) ebill = random.normalvariate(0, .01) r_bill = -.02 + y_new + 0.75 * (y_new - y_prev) + ebill r_bill = clip(r_bill, .01, .10) # the tables max out at 15 years... lookup_year = min(15, self.year) estocks = random.normalvariate(0, self.estocks_stdev[lookup_year]) r_stocks = self.a_cape[lookup_year] + self.b_cape[lookup_year] * self.initial_cape + estocks # Blanchett doesn't provide min/max for r_stocks # I'll reuse the min/max from LowYieldsAutoRegression r_stocks = clip(r_stocks, -1, 2) einflation = random.normalvariate(0, .01) r_inflation = 0.0125 + (y_new - y_prev) + 0.5 * r_bill + einflation r_inflation = clip(r_inflation, -.05, .10) self.y_prev = y_new self.year += 1 return AnnualChange( year=self.year, stocks=Decimal(r_stocks), bonds=Decimal(r_bonds), inflation=Decimal(r_inflation) )
def constant_returns(stocks=Decimal('.04'), bonds=Decimal('.02'), inflation=Decimal('.02')): return itertools.repeat( AnnualChange(year=0, stocks=stocks, bonds=bonds, inflation=inflation))
def random_year(self): r = random.lognormvariate(self.mean, self.stddev) - 1 r = Decimal(r) return AnnualChange(year=self.year, stocks=r, bonds=r, inflation=Decimal(0))
def random_year(self): ''' This is the same method name as in market.US_1871_Returns...which allows this to be a drop-in replacement for that when simulating data ''' r = lognormal(self.mean, self.sigma) - 1 r = Decimal(r) return AnnualChange(year=0, stocks=r, bonds=r, inflation=Decimal(0))