Skip to content

Commit ec9f87f

Browse files
committed
fix: DCF discount rate for a short history (<12 months)
1 parent 36cb6c7 commit ec9f87f

File tree

2 files changed

+13
-9
lines changed

2 files changed

+13
-9
lines changed

okama/common/helpers/helpers.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ def get_cagr(ror: Union[pd.DataFrame, pd.Series]) -> Union[pd.Series, float]:
189189
Return Compound Annual Rate of Return (CAGR) for each asset given returns time series DataFrame.
190190
"""
191191
if ror.shape[0] < 12:
192-
return pd.Series({x: None for x in ror.columns}) # CAGR is not defined for periods < 1 year
192+
# CAGR is not defined for periods < 1 year. Return None or Series with NaNs.
193+
return pd.Series({x: None for x in ror.columns}) if isinstance(ror, pd.DataFrame) else None
193194
return ((ror + 1.0).prod()) ** (settings._MONTHS_PER_YEAR / ror.shape[0]) - 1.0
194195

195196
@staticmethod
@@ -360,13 +361,14 @@ def condition(y):
360361
return df
361362

362363
@staticmethod
363-
def skewness(ror: Union[pd.DataFrame, pd.Series]) -> Union[pd.Series, float]:
364+
def skewness(ror: Union[pd.DataFrame, pd.Series]) -> Union[pd.DataFrame, pd.Series]:
364365
"""
365366
Calculate expanding skewness.
366367
The shape of time series should be at least 12. In the opposite case empty time series is returned.
367368
"""
368-
sk = ror.expanding(min_periods=1).skew()
369-
return sk.iloc[settings._MONTHS_PER_YEAR :]
369+
sk = ror.expanding(min_periods=12).skew()
370+
sk.dropna(inplace=True)
371+
return sk
370372

371373
@staticmethod
372374
def skewness_rolling(ror: Union[pd.DataFrame, pd.Series], window: int = 60) -> Union[pd.Series, float]:
@@ -385,8 +387,9 @@ def kurtosis(ror: Union[pd.Series, pd.DataFrame]):
385387
Calculate expanding Fisher (normalized) kurtosis time series.
386388
Kurtosis should be close to zero for normal distribution.
387389
"""
388-
kt = ror.expanding(min_periods=1).kurt()
389-
return kt.iloc[settings._MONTHS_PER_YEAR :]
390+
kt = ror.expanding(min_periods=12).kurt()
391+
kt.dropna(inplace=True)
392+
return kt
390393

391394
@staticmethod
392395
def kurtosis_rolling(ror: Union[pd.Series, pd.DataFrame], window: int = 60):

okama/portfolios/dcf.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ def discount_rate(self, discount_rate: Optional[float]):
7474
self._monte_carlo_wealth_fv = pd.DataFrame()
7575
if discount_rate is None and hasattr(self.parent, "inflation"):
7676
self._discount_rate = helpers.Frame.get_cagr(self.parent.inflation_ts)
77+
if self._discount_rate is None:
78+
# if time series is too short (<12 month) CAGR is not defined
79+
self._discount_rate = settings.DEFAULT_DISCOUNT_RATE
7780
elif discount_rate is None and not hasattr(self.parent, "inflation"):
7881
self._discount_rate = settings.DEFAULT_DISCOUNT_RATE
7982
else:
@@ -493,9 +496,7 @@ def monte_carlo_wealth(
493496
if self.cashflow_parameters is None:
494497
raise AttributeError("'cashflow_parameters' is not defined.")
495498
if self._monte_carlo_wealth_fv.empty:
496-
return_ts = self.parent.monte_carlo_returns_ts(
497-
distr=self.mc.distribution, parameters = self.mc.distribution_parameters, years=self.mc.period, n=self.mc.number
498-
)
499+
return_ts = self.parent.mc.monte_carlo_returns_ts()
499500
self._monte_carlo_wealth_fv = return_ts.apply(
500501
dcf_calculations.get_wealth_indexes_fv_with_cashflow,
501502
axis=0,

0 commit comments

Comments
 (0)