Compare commits

...

3 Commits

  1. 64
      fincal/fincal.py
  2. 9
      tests/test_fincal2.py

64
fincal/fincal.py

@ -407,7 +407,7 @@ class TimeSeries(TimeSeriesCore):
if_not_found: Literal["fail", "nan"] = "fail", if_not_found: Literal["fail", "nan"] = "fail",
annual_compounded_returns: bool = None, annual_compounded_returns: bool = None,
date_format: str = None, date_format: str = None,
): ) -> float:
"""Calculates the volatility of the time series.add() """Calculates the volatility of the time series.add()
The volatility is calculated as the standard deviaion of periodic returns. The volatility is calculated as the standard deviaion of periodic returns.
@ -431,6 +431,20 @@ class TimeSeries(TimeSeriesCore):
Number of traded days per year to be considered for annualizing volatility. Number of traded days per year to be considered for annualizing volatility.
Only used when annualizing volatility for a time series with daily frequency. Only used when annualizing volatility for a time series with daily frequency.
If not provided, will use the value in FincalOptions.traded_days. If not provided, will use the value in FincalOptions.traded_days.
Remaining options are passed on to rolling_return function.
Returns:
-------
Returns the volatility number as float
Raises:
-------
ValueError: If frequency string is outside valid values
Also see:
--------
TimeSeries.calculate_rolling_returns()
""" """
if frequency is None: if frequency is None:
@ -473,6 +487,54 @@ class TimeSeries(TimeSeriesCore):
return sd return sd
def average_rolling_return(self, **kwargs) -> float:
"""Calculates the average rolling return for a given period
Parameters
----------
kwargs: parameters to be passed to the calculate_rolling_returns() function
Returns
-------
float
returns the average rolling return for a given period
Also see:
---------
TimeSeries.calculate_rolling_returns()
"""
kwargs["return_period_unit"] = kwargs.get("return_period_unit", self.frequency.freq_type)
kwargs["return_period_value"] = kwargs.get("return_period_value", 1)
kwargs["to_date"] = kwargs.get("to_date", self.end_date)
if kwargs.get("from_date", None) is None:
start_date = self.start_date + relativedelta(
**{kwargs["return_period_unit"]: kwargs["return_period_value"]}
)
kwargs["from_date"] = start_date
rr = self.calculate_rolling_returns(**kwargs)
return statistics.mean(rr.values)
def max_drawdown(self):
max_val_dict = {}
prev_val = 0
prev_date = list(self.data)[0]
for dt, val in self.data.items():
if val > prev_val:
max_val_dict[dt] = (dt, val, 0)
prev_date, prev_val = dt, val
else:
max_val_dict[dt] = (prev_date, prev_val, val / prev_val - 1)
max_drawdown = min(max_val_dict.items(), key=lambda x: x[1][2])
max_drawdown = dict(start_date=max_drawdown[1][0], end_date=max_drawdown[0], drawdown=max_drawdown[1][2])
return max_drawdown
if __name__ == "__main__": if __name__ == "__main__":
date_series = [ date_series = [

9
tests/test_fincal2.py

@ -168,3 +168,12 @@ class TestVolatility:
assert round(sd, 6) == 0.023164 assert round(sd, 6) == 0.023164
sd = ts.volatility(from_date="2017-10-01", to_date="2019-08-31", annualize_volatility=True) sd = ts.volatility(from_date="2017-10-01", to_date="2019-08-31", annualize_volatility=True)
assert round(sd, 6) == 0.050559 assert round(sd, 6) == 0.050559
sd = ts.volatility(from_date="2017-02-01", frequency="M", return_period_unit="months")
assert round(sd, 6) == 0.050884
sd = ts.volatility(
frequency="M",
return_period_unit="months",
return_period_value=3,
annualize_volatility=False,
)
assert round(sd, 6) == 0.020547

Loading…
Cancel
Save