Compare commits

...

3 Commits

Author SHA1 Message Date
a19f7e7b21 added max_drawdown function 2022-03-14 23:54:54 +05:30
2237692677 Added more volatility tests 2022-03-13 22:52:41 +05:30
1758df0124 Added average rolling return function 2022-03-13 22:52:23 +05:30
2 changed files with 72 additions and 1 deletions

View File

@ -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 = [

View File

@ -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