Skip to content

Commit

Permalink
Merge pull request #18 from ricequant/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Zhou-JiaJun authored Mar 1, 2023
2 parents 0ae0a74 + 3139e1e commit cf04050
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 12 deletions.
36 changes: 27 additions & 9 deletions rqrisk/risk.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import numpy as np
from statsmodels.formula.api import ols

from .utils import indicator_property, IndicatorProperty, annual_factor, safe_div, DAILY
from .utils import indicator_property, IndicatorProperty, annual_factor, safe_div, DAILY, deprecate_property


class Risk(object):
Expand Down Expand Up @@ -54,6 +54,18 @@ def benchmark_return(self):
def benchmark_annual_return(self):
return (1 + self.benchmark_return) ** (self._annual_factor / self.period_count) - 1

@indicator_property()
def arithmetic_excess_return(self):
return self.return_rate - self.benchmark_return

@indicator_property()
def geometric_excess_return(self):
return (1 + self.return_rate) / (1 + self.benchmark_return) - 1

@indicator_property()
def geometric_excess_annual_return(self):
return (1 + self.annual_return) / (1 + self.benchmark_annual_return) - 1

@indicator_property(min_period_count=2)
def alpha(self):
# annualized Jensen's alpha:https://en.wikipedia.org/wiki/Jensen%27s_alpha
Expand Down Expand Up @@ -104,14 +116,14 @@ def _calc_cum(returns):
return df_cum

@classmethod
def _calc_max_drawdown(cls, returns):
df_cum = cls._calc_cum(returns)
max_return = np.maximum.accumulate(df_cum)
return abs(((df_cum - max_return) / max_return).min())
def _calc_max_drawdown(cls, cum_nav):
max_nav = np.maximum.accumulate(cum_nav)
return abs(((cum_nav - max_nav) / max_nav).min())

@indicator_property()
def max_drawdown(self):
return self._calc_max_drawdown(self._portfolio)
cum_returns = self._calc_cum(self._portfolio)
return self._calc_max_drawdown(cum_returns)

@indicator_property(min_period_count=2, value_when_pc_not_satisfied=0.)
def tracking_error(self):
Expand Down Expand Up @@ -167,12 +179,12 @@ def calmar(self):
else:
return self.annual_return / self.max_drawdown

@indicator_property()
@deprecate_property
def excess_return_rate(self):
# activate return rate
return np.expm1(np.log1p(self._active_returns).sum())

@indicator_property()
@deprecate_property
def excess_annual_return(self):
# active annual return
return (1 + self.excess_return_rate) ** (self._annual_factor / self.period_count) - 1
Expand All @@ -186,9 +198,15 @@ def excess_volatility(self):
def excess_annual_volatility(self):
return self.excess_volatility * (self._annual_factor ** 0.5)

@indicator_property(min_period_count=1)
def geometric_excess_drawdown(self):
excess = self._calc_cum(self._portfolio) / self._calc_cum(self._benchmark)
return self._calc_max_drawdown(excess)

@indicator_property(min_period_count=1)
def excess_max_drawdown(self):
return self._calc_max_drawdown(self._active_returns)
cum_returns = self._calc_cum(self._active_returns)
return self._calc_max_drawdown(cum_returns)

@indicator_property()
def var(self):
Expand Down
15 changes: 15 additions & 0 deletions rqrisk/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
# 详细的授权流程,请联系 [email protected] 获取。

import numpy as np
import logging


logger = logging.getLogger()


class IndicatorProperty:
Expand Down Expand Up @@ -78,3 +82,14 @@ def safe_div(dividend, divisor):
if divisor == 0:
return np.nan
return dividend / divisor


def deprecate_property(func):

@property
def inner(self):
logger.warning("\"{}\" is deprecate.".format(func.__name__))
return func(self)

return inner

2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[metadata]
name = rqrisk
version = 1.0.5
version = 1.0.6

[versioneer]
VCS = git
Expand Down
17 changes: 15 additions & 2 deletions test.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,19 @@ def _assert(returns, benchmark, ulcer_performance_index):
assert_almost_equal(r.ulcer_performance_index, ulcer_performance_index)

_assert(positive_returns, simple_benchmark, np.nan)
_assert(negative_returns, simple_benchmark, -0.019864148204580486)
_assert(weekly_returns, simple_weekly_benchamrk, -0.014606674809517502)
_assert(negative_returns, simple_benchmark, -0.017162734495347234)
_assert(weekly_returns, simple_weekly_benchamrk, 0.011223184970109419)


def test_excess_index():

def _assert(returns, benchmark, arithmetic_excess_return, geometric_excess_return, geometric_excess_annual_return):
r = _r(returns, benchmark, 0)
assert_almost_equal(r.arithmetic_excess_return, arithmetic_excess_return)
assert_almost_equal(r.geometric_excess_return, geometric_excess_return)
assert_almost_equal(r.geometric_excess_annual_return, geometric_excess_annual_return)

_assert(one_return, one_benchmark, 0, 0, 0)
_assert(simple_benchmark, zero_benchmark, 0.0936852726843609, 0.09368527268436089, 11.274002099240212)


0 comments on commit cf04050

Please sign in to comment.