Updated.
[retire.git] / returns_and_expenses.py
1 #!/usr/bin/env python3
2
3 from abc import ABC, abstractmethod
4 import logging
5 import random
6
7 from type.rate import Rate
8
9 import data
10
11
12 logger = logging.getLogger(__name__)
13
14
15 class ReturnsAndExpenses(ABC):
16     @abstractmethod
17     def get_annual_inflation_rate(self, year: int) -> Rate:
18         pass
19
20     @abstractmethod
21     def get_annual_social_security_increase_rate(self, year: int) -> Rate:
22         pass
23
24     @abstractmethod
25     def get_annual_investment_return_rate(self, year: int) -> Rate:
26         pass
27
28
29 class ConstantValueRaE(ReturnsAndExpenses):
30     def __init__(
31             self,
32             *,
33             inflation_rate = Rate(0.0),
34             social_security_increase_rate = Rate(0.0),
35             investment_return_rate = Rate(0.0),
36     ):
37         super().__init__()
38         self.inflation_rate = inflation_rate
39         self.social_security_increase_rate = social_security_increase_rate
40         self.investment_return_rate = investment_return_rate
41
42     def get_annual_inflation_rate(self, year: int) -> Rate:
43         return self.inflation_rate
44
45     def get_annual_social_security_increase_rate(self, year: int) -> Rate:
46         return self.social_security_increase_rate
47
48     def get_annual_investment_return_rate(self, year: int) -> Rate:
49         return self.investment_return_rate
50
51     def __repr__(self):
52         return f'Constant rates: inflation={self.inflation_rate}, ss={self.social_security_increase_rate}, roi={self.investment_return_rate}'
53
54
55 class HistoricalRaE(ReturnsAndExpenses):
56     def __init__(self):
57         super().__init__()
58         #self.years = range(1928, 2020)
59         self.years = [1929, 1930, 1931, 1932, 1933,
60                       1939,
61                       1946, 1947,
62                       1956, 1957,
63                       1964, 1965, 1966, 1969,
64                       1973, 1974, 1977, 1978,
65                       1981, 1984, 1987, 1990,
66                       2000, 2001, 2002, 2007, 2007]
67         self.year = None
68
69     def get_annual_inflation_rate(self, year: int) -> Rate:
70         #self.year = random.randrange(1928, 2020)
71         self.year = random.choice(self.years)
72         rois_and_inflation = data.ROIs_AND_INFLATION[self.year]
73         inflation = rois_and_inflation.inflation
74         logger.debug(f'HistoricalRaE: inflation is {inflation} (replay={self.year})')
75         return inflation
76
77     def get_annual_social_security_increase_rate(self, year: int) -> Rate:
78         rois_and_inflation = data.ROIs_AND_INFLATION[self.year]
79         ss = rois_and_inflation.inflation
80         if ss > 0:
81             ss -= 1.0
82             ss /= 2
83             ss += 1.0
84         logger.debug(f'HistoricalRaE: social security increase rate is {ss} (replay={self.year})')
85         return ss
86
87     def get_annual_investment_return_rate(self, year: int) -> Rate:
88         rois_and_inflation = data.ROIs_AND_INFLATION[self.year]
89         roi = (
90             rois_and_inflation.snp_500_return * 0.50 +
91             rois_and_inflation.us_10y_bond_return * 0.50
92         )
93         logger.debug(f'HistoricalRaE: investment return 50/50 is {roi} (replay={self.year})')
94         return Rate(roi)
95
96     def __repr__(self):
97         return f'historical reply of inflation/returns in {self.years}'
98
99
100 class GaussianRae(ReturnsAndExpenses):
101     def __init__(self):
102         self.inflation = None
103         self.mean_inflation = 1.04         # Historical = 3.5% inflation
104         self.stdev_inflation = 0.028       # Historical = 2.8% inflation stdev
105         self.mean_roi = 1.060              # Historical = 8.5% 30s/70b; 9.1% 50s/50s; 9.7% 70s/30b
106         self.stdev_roi = 0.093             # Historical = 6.7% 30s/70b; 9.3% 50s/50b; 12.2% 70s/30b
107         self.ss_discount = 0.02
108
109     def get_annual_inflation_rate(self, year: int) -> Rate:
110         self.inflation = random.gauss(self.mean_inflation, self.stdev_inflation)
111         return Rate(multiplier=self.inflation)
112
113     def get_annual_social_security_increase_rate(self, year: int) -> Rate:
114         return Rate(multiplier=self.inflation - self.ss_discount)
115
116     def get_annual_investment_return_rate(self, year: int) -> Rate:
117         return Rate(multiplier=random.gauss(self.mean_roi, self.stdev_roi))
118
119     def __repr__(self):
120         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)})'