Sharpe ratio 和 Sortino ratio ,它们都用来衡量每获得一份收益面临着多大风险。下面是两者的计算公式:
Sharpe ratio: (Rp - Rf )/ σ
Sortino ratio: (Rp - Rf) / σd
可以看到,这两者的区别是:分母不同。 接下来会挨个解释一下公式中出现的 4 种变量,但在这之前,需要做一些假设,我需要数据来说明。 假设要统计过去半年内以月为周期的 Sharpe 和 Sortino ,以下是过去 6 个月的每月相对收益状况:
double pf = {0.02, 0.08, -0.01, 0.01, -0.02, 0.04};
Rp: 期望的收益值。就是字面上的意思。但是初次接触这个公式的人就会问,这个数该怎么填?我期望每月收益率 100%!抱歉,这里期望是指数学上的期望(百度一下,你将会温习到中学时代的数理统计方面的内容),这个数暂时我来定,因为指定了上面的 pf ,期望值就已经确定了。对,期望的意思是,按这种势头搞下去,你一年(或其它自定义的周期)能赚多少。
Rf: 抱歉上面的期望不是你的“期望”,但这个 Rf (无风险收益率)你可以自行决定。比如像我这种没什么门道的普通人,就 6%吧,存个长期的理财。如果你有别的门道,比如把钱放到你二大爷那,他每年都能搞出 20%的收益,那么这个值对你来说就是 20%。
σ:这个东西就是标准差,用来衡量数列的离散程度。比如你今天翻倍,明天又跌去八成,后天又翻倍,这就说明离散程度较大了,虽然你最后还是赚了,但中间的过程比较惊悚,也就是说,你承受的风险比较大。
σd :这个东西是下偏差。有学机械的提出疑问,这是搞装配么,怎么还有下偏差,确定这是统计学里面的?额,我学数理统计的时候确实没有这个东西。它的意思是,只统计基准以下的数据;基准以上的数据统统当作 0 处理。 Sortino ration 的发明者给出的理由是:我亏的才算风险,赚的再多我不怕,怎么能说是有风险呢!所以它的含意是,未超过基准收益部分的数据的离散程度。
Rp , Rf 我们可以简单理解为收益率。但要注意到,收益率是有周期单位的,年化收益和日收益、月收益不在一个维度上,没有可比性。不同周期的收益率不能代入上述公式直接计算,这就存在着收益率换算的问题。在知乎上看到有些量化平台给出的 N 日收益换算到年化收益的方法是(还是个高票回答):
不得不指出,这样的计算方法是不合适的。因为每天的收益会改变帐户的资产状况,不能简单的用算术平均来计算。不同周期收益率之间的换算要考虑到资产的变化,即复利,所以一些乘方和开方的运算是不可避免的。
下面给出了以七日收益来计算年化收益预期的实现代码,原始数据取自己余额宝:
public static void annualProfitTest() {
// 最近 7 天的万份收益,即存 1 万,收 1 块零几分钱
double[] pDailyIncome = {1.0213,1.0198,1.0197,1.0337,1.0354,1.0389,1.0399};
// 最近 7 天的总收入
double totalIncome = StatUtils.sum(pDailyIncome);
// 根据 7 日的收益计算日化收益率, 开 7 次方
double dailyProfitRatio = StrictMath.pow(1+totalIncome/10000.0, 1/7.0)-1;
// 根据日化收益率计算年化收益率, 365 次方
double annualProfitRatio = StrictMath.pow(1+dailyProfitRatio, 365)-1;
System.out.println("Daily: "+dailyProfitRatio+"\nAnnual: "+annualProfitRatio);
}
类似的,由月收益得到日收益或年收益的时候,可以相应的修改上面的代码。
接下来是代码 show time ,先算一下 Sharp:
// 根据单位周期相对收益率,计算总周期的收益率
public static double calcTotalProfitRatio(double[] profits) {
double totalProfitRatio = 1;
for(int i=0; i<profits.length; i++) {
totalProfitRatio = totalProfitRatio*(1+profits[i]);
}
return totalProfitRatio-1;
}
public static void main(String[] args) {
double[] pf = {0.022, 0.012, -0.016, 0.019, -0.026, 0.023};
// 6 个月的总收益率
double Rp = calcTotalProfitRatio(pf);
// 无风险收益率年化值 6%,存 6 个月能收益多少
double Rf = StrictMath.pow(StrictMath.pow(1.06, 1/12.0),6)-1;
// 计算 pf 的标准差
SummaryStatistics pointStats = new SummaryStatistics();
for(double val:pf) pointStats.addValue(val);
double theta = pointStats.getStandardDeviation();
// 代入 Sharp ratio 计算公式
double sharp = (Rp-Rf)/theta;
System.out.println("Rp:"+Rp+"\nRf:"+Rf+"\ntheta:"+theta+"\nsharp:"+sharp);
}
计算 Sortino ratio 与计算 Sharpe ratio 的唯一区别是,要用下偏差替代标准差。所谓下偏差,就是忽略掉上偏差的影响。我们可以这样处理,当某一个月的收益超过参考收益时,将其差值置为 0 :
但是,我们会发现,刚才我们使用的 SummaryStatistics 类,并没有计算下偏差的方法,那么,我们可以写一个:
public static double downDeviation(double[] src, double ref) {
double sum=0d;
for(double val:src) sum += (val>=ref) ? 0d : (val-ref);
return StrictMath.sqrt(sum/(src.length-1.0));
}