Merge pull request #66 from rday/sortino_ratio

Add the Sortino ratio for downside risk
This commit is contained in:
Eddie Hebert
2013-01-28 11:14:59 -08:00
2 changed files with 90 additions and 0 deletions
+40
View File
@@ -327,6 +327,46 @@ class Risk(unittest.TestCase):
for x in self.metrics_06.year_periods],
[-0.066])
def test_algorithm_sortino_06(self):
self.assertEqual([round(x.sortino, 3)
for x in self.metrics_06.month_periods],
[4.491,
-2.842,
-2.052,
3.898,
7.023,
-8.532,
3.079,
-0.354,
-1.125,
3.009,
3.277,
-3.122])
self.assertEqual([round(x.sortino, 3)
for x in self.metrics_06.three_month_periods],
[-0.769,
-1.043,
6.677,
-2.77,
-3.209,
-6.769,
1.253,
1.085,
3.659,
1.674])
self.assertEqual([round(x.sortino, 3)
for x in self.metrics_06.six_month_periods],
[-2.728,
-3.258,
-1.84,
-1.366,
-1.845,
-3.415,
2.238])
self.assertEqual([round(x.sortino, 3)
for x in self.metrics_06.year_periods],
[-0.524])
def dtest_algorithm_beta_06(self):
self.assertEqual([round(x.beta, 3)
for x in self.metrics_06.month_periods],
+50
View File
@@ -144,6 +144,7 @@ class RiskMetricsBase(object):
self.algorithm_returns)
self.treasury_period_return = self.choose_treasury()
self.sharpe = self.calculate_sharpe()
self.sortino = self.calculate_sortino()
self.beta, self.algorithm_covariance, self.benchmark_variance, \
self.condition_number, self.eigen_values = self.calculate_beta()
self.alpha = self.calculate_alpha()
@@ -165,6 +166,7 @@ class RiskMetricsBase(object):
'algorithm_period_return': self.algorithm_period_returns,
'benchmark_period_return': self.benchmark_period_returns,
'sharpe': self.sharpe,
'sortino': self.sortino,
'beta': self.beta,
'alpha': self.alpha,
'excess_return': self.excess_return,
@@ -193,6 +195,7 @@ class RiskMetricsBase(object):
"benchmark_volatility",
"algorithm_volatility",
"sharpe",
"sortino",
"algorithm_covariance",
"benchmark_variance",
"beta",
@@ -241,6 +244,27 @@ class RiskMetricsBase(object):
return ((self.algorithm_period_returns - self.treasury_period_return) /
self.algorithm_volatility)
def calculate_sortino(self, mar=None):
"""
http://en.wikipedia.org/wiki/Sortino_ratio
"""
if len(self.algorithm_returns) == 0:
return 0.0
if mar is None:
mar = self.treasury_period_return
downside = [
(x - mar)**2
for x in self.algorithm_returns
if x < mar]
dr = float(math.sqrt(sum(downside) / len(self.algorithm_returns)))
if dr < 0.000001:
return 0.0
return ((self.algorithm_period_returns - mar) / dr)
def calculate_beta(self):
"""
@@ -425,6 +449,7 @@ class RiskMetricsIterative(RiskMetricsBase):
self.algorithm_period_returns = []
self.benchmark_period_returns = []
self.sharpe = []
self.sortino = []
self.beta = []
self.alpha = []
self.max_drawdown = 0
@@ -475,6 +500,7 @@ algorithm_returns ({algo_count}) in range {start} : {end}"
self.beta.append(self.calculate_beta()[0])
self.alpha.append(self.calculate_alpha())
self.sharpe.append(self.calculate_sharpe())
self.sortino.append(self.calculate_sortino())
self.max_drawdown = self.calculate_max_drawdown()
def to_dict(self):
@@ -491,6 +517,7 @@ algorithm_returns ({algo_count}) in range {start} : {end}"
'algorithm_period_return': self.algorithm_period_returns[-1],
'benchmark_period_return': self.benchmark_period_returns[-1],
'sharpe': self.sharpe[-1],
'sortino': self.sortino[-1],
'beta': self.beta[-1],
'alpha': self.alpha[-1],
'excess_return': self.excess_returns[-1],
@@ -520,6 +547,7 @@ algorithm_returns ({algo_count}) in range {start} : {end}"
"benchmark_volatility",
"algorithm_volatility",
"sharpe",
"sortino",
"algorithm_covariance",
"benchmark_variance",
"beta",
@@ -598,6 +626,28 @@ algorithm_returns ({algo_count}) in range {start} : {end}"
return (self.algorithm_period_returns[-1] -
self.treasury_period_return) / self.algorithm_volatility[-1]
def calculate_sortino(self, mar=None):
"""
http://en.wikipedia.org/wiki/Sortino_ratio
"""
if len(self.algorithm_returns) == 0:
return 0.0
if mar is None:
mar = self.treasury_period_return
downside = [
(x - mar)**2
for x in self.algorithm_returns
if x < mar]
dr = float(math.sqrt(sum(downside) / len(self.algorithm_returns)))
if dr < 0.000001:
return 0.0
return ((self.algorithm_period_returns[-1] - mar) /
dr)
def calculate_alpha(self):
"""
http://en.wikipedia.org/wiki/Alpha_(investment)