#!/usr/bin/env python3 from abc import ABC, abstractmethod import logging import random from type.rate import Rate import data logger = logging.getLogger(__name__) class ReturnsAndExpenses(ABC): @abstractmethod def get_annual_inflation_rate(self, year: int) -> Rate: pass @abstractmethod def get_annual_social_security_increase_rate(self, year: int) -> Rate: pass @abstractmethod def get_annual_investment_return_rate(self, year: int) -> Rate: pass class ConstantValueRaE(ReturnsAndExpenses): def __init__( self, *, inflation_rate = Rate(0.0), social_security_increase_rate = Rate(0.0), investment_return_rate = Rate(0.0), ): super().__init__() self.inflation_rate = inflation_rate self.social_security_increase_rate = social_security_increase_rate self.investment_return_rate = investment_return_rate def get_annual_inflation_rate(self, year: int) -> Rate: return self.inflation_rate def get_annual_social_security_increase_rate(self, year: int) -> Rate: return self.social_security_increase_rate def get_annual_investment_return_rate(self, year: int) -> Rate: return self.investment_return_rate def __repr__(self): return f'Constant rates: inflation={self.inflation_rate}, ss={self.social_security_increase_rate}, roi={self.investment_return_rate}' class HistoricalRaE(ReturnsAndExpenses): def __init__(self): super().__init__() #self.years = range(1928, 2020) self.years = [1929, 1930, 1931, 1932, 1933, 1939, 1946, 1947, 1956, 1957, 1964, 1965, 1966, 1969, 1973, 1974, 1977, 1978, 1981, 1984, 1987, 1990, 2000, 2001, 2002, 2007, 2007] self.year = None def get_annual_inflation_rate(self, year: int) -> Rate: #self.year = random.randrange(1928, 2020) self.year = random.choice(self.years) rois_and_inflation = data.ROIs_AND_INFLATION[self.year] inflation = rois_and_inflation.inflation logger.debug(f'HistoricalRaE: inflation is {inflation} (replay={self.year})') return inflation def get_annual_social_security_increase_rate(self, year: int) -> Rate: rois_and_inflation = data.ROIs_AND_INFLATION[self.year] ss = rois_and_inflation.inflation if ss > 0: ss -= 1.0 ss /= 2 ss += 1.0 logger.debug(f'HistoricalRaE: social security increase rate is {ss} (replay={self.year})') return ss def get_annual_investment_return_rate(self, year: int) -> Rate: rois_and_inflation = data.ROIs_AND_INFLATION[self.year] roi = ( rois_and_inflation.snp_500_return * 0.50 + rois_and_inflation.us_10y_bond_return * 0.50 ) logger.debug(f'HistoricalRaE: investment return 50/50 is {roi} (replay={self.year})') return Rate(roi) def __repr__(self): return f'historical reply of inflation/returns in {self.years}' class GaussianRae(ReturnsAndExpenses): def __init__(self): self.inflation = None self.mean_inflation = 1.04 # Historical = 3.5% inflation self.stdev_inflation = 0.028 # Historical = 2.8% inflation stdev self.mean_roi = 1.060 # Historical = 8.5% 30s/70b; 9.1% 50s/50s; 9.7% 70s/30b self.stdev_roi = 0.093 # Historical = 6.7% 30s/70b; 9.3% 50s/50b; 12.2% 70s/30b self.ss_discount = 0.02 def get_annual_inflation_rate(self, year: int) -> Rate: self.inflation = random.gauss(self.mean_inflation, self.stdev_inflation) return Rate(multiplier=self.inflation) def get_annual_social_security_increase_rate(self, year: int) -> Rate: return Rate(multiplier=self.inflation - self.ss_discount) def get_annual_investment_return_rate(self, year: int) -> Rate: return Rate(multiplier=random.gauss(self.mean_roi, self.stdev_roi)) def __repr__(self): return f'Random Gaussian: (μinflation={Rate(self.mean_inflation).__repr__(relative=True)}, σ={Rate(self.stdev_inflation)}); (μroi={Rate(self.mean_roi).__repr__(relative=True)}, σ={Rate(self.stdev_roi)})'