Example #1
0
/// <summary>
/// To calculate Burke ratio we take the difference between the portfolio
/// return and the risk free rate and we divide it by the square root of the
/// sum of the square of the drawdowns. To calculate the modified Burke ratio
/// we just multiply the Burke ratio by the square root of the number of datas.
/// (一种调整收益率的计算方式,调整是通过drawdown的平方和进行的)
/// </summary>
func BurkeRatio(Ra *utils.SlidingWindow, Rf float64, scale float64) (float64, error) {
	var len = Ra.Count()
	var in_drawdown = false
	var peak = 1
	var temp = 0.0
	drawdown, err := utils.NewSlidingWindow(len)
	if err != nil {
		return math.NaN(), err
	}
	for i := 1; i < len; i++ {
		if Ra.Data()[i] < 0 {
			if !in_drawdown {
				peak = i - 1
				in_drawdown = true
			}
		} else {
			if in_drawdown {
				temp = 1.0
				for j := peak + 1; j < i; j++ {
					temp = temp * (1.0 + Ra.Data()[j])
				}
				drawdown.Add(temp - 1.0) //Source
				in_drawdown = false
			}
		}
	}

	if in_drawdown {
		temp = 1.0
		for j := peak + 1; j < len; j++ {
			temp = temp * (1.0 + Ra.Data()[j])
		}
		drawdown.Add(temp - 1.0) //Source
		//drawdown.Add((temp - 1.0) * 100.0)
		in_drawdown = false
	}
	//var Rp = Annualized(Ra, scale, true) - 1.0--->Source
	Rp, err := Annualized(Ra, scale, true)
	if err != nil {
		return math.NaN(), err
	}
	var result float64

	if drawdown.Count() != 0 {
		pow_Sliding, err := utils.Power(drawdown, 2)
		if err != nil {
			return math.NaN(), err
		}
		Rf = Rf * scale
		result = (Rp - Rf) / math.Sqrt(pow_Sliding.Sum())
	} else {
		result = 0
	}

	modified := true
	if modified {
		result = result * math.Sqrt(float64(len))
	}
	return result, nil
}
Example #2
0
/// <summary>
/// Kappa is a generalized downside risk-adjusted performance measure.
/// To calculate it, we take the difference of the mean of the distribution
/// to the target and we divide it by the l-root of the lth lower partial
/// moment. To calculate the lth lower partial moment we take the subset of
/// returns below the target and we sum the differences of the target to
/// these returns. We then return return this sum divided by the length of
/// the whole distribution.
/// (非年化的超MAR平均收益率通过l阶根的低于MAR的收益率序列的l阶矩)
/// </summary>
func Kappa(Ra *utils.SlidingWindow, MAR float64, l float64) (float64, error) {
	undervalues, err := utils.NewSlidingWindow(Ra.Count())
	if err != nil {
		return math.NaN(), err
	}
	for i := 0; i < Ra.Count(); i++ {
		if Ra.Data()[i] < MAR {
			undervalues.Add(Ra.Data()[i])
		}
	}

	var n = float64(Ra.Count())
	var m = float64(Ra.Average())
	neg_Sliding, err := utils.Negative(undervalues)
	if err != nil {
		return math.NaN(), err
	}
	add_Sliding, err := utils.Add(MAR, neg_Sliding)
	if err != nil {
		return math.NaN(), err
	}
	pow_Sliding, err := utils.Power(add_Sliding, float64(l))
	if err != nil {
		return math.NaN(), err
	}
	var temp = pow_Sliding.Sum() / n
	return (m - MAR) / math.Pow(temp, (1.0/float64(l))), nil
}
Example #3
0
/// <summary>
/// 峰度
/// </summary>
// = "sample"
func Kurtosis(Ra *utils.SlidingWindow) (float64, error) {
	if Ra == nil || Ra.Count() <= 3 {
		return math.NaN(), errors.New("In Kurtosis, Ra == nil || Ra.Count() <= 3")
	}

	n := float64(Ra.Count())
	method := "sample_excess"
	switch method {
	case "sample_excess": //kurtosis = sum((x-mean(x))^4/var(x)^2)*n*(n+1)/((n-1)*(n-2)*(n-3)) - 3*(n-1)^2/((n-2)*(n-3))
		var_data, err := Variance(Ra)
		if err != nil {
			return math.NaN(), err
		}
		add_Sliding, err := utils.Add(-Ra.Average(), Ra)
		if err != nil {
			return math.NaN(), err
		}
		pow_Sliding, err := utils.Power(add_Sliding, 4.0)
		if err != nil {
			return math.NaN(), err
		}
		multi_Sliding, err := utils.Multi(1.0/math.Pow(var_data, 2.0), pow_Sliding)
		if err != nil {
			return math.NaN(), err
		}
		return multi_Sliding.Sum()*n*(n+1.0)/((n-1.0)*(n-2.0)*(n-3.0)) - 3*(n-1.0)*(n-1.0)/((n-2.0)*(n-3.0)), nil
	default:
		return math.NaN(), errors.New("In Kurtosis, method is default")
	}
	return math.NaN(), nil
}
Example #4
0
/// <summary>
/// 偏度
/// </summary>
// default = "moment"
func Skewness(Ra *utils.SlidingWindow) (float64, error) {
	if Ra == nil || Ra.Count() <= 2 {
		return math.NaN(), errors.New("In Skewness, Ra == nil || Ra.Count() <= 2")
	}

	n := float64(Ra.Count())
	method := "moment"
	switch method {
	//"moment", "fisher", "sample"
	case "moment": //skewness = sum((x-mean(x))^3/sqrt(var(x)*(n-1)/n)^3)/length(x)
		var_data, err := Variance(Ra)
		if err != nil {
			return math.NaN(), err
		}
		add_Sliding, err := utils.Add(-Ra.Average(), Ra)
		if err != nil {
			return math.NaN(), err
		}
		pow_Sliding, err := utils.Power(add_Sliding, 3.0)
		if err != nil {
			return math.NaN(), err
		}
		multi_Sliding, err := utils.Multi(1.0/math.Pow(var_data*(n-1.0)/n, 1.5), pow_Sliding)
		if err != nil {
			return math.NaN(), err
		}
		return multi_Sliding.Sum() / n, nil
	default:
		return math.NaN(), errors.New("In Skewness, method is default")
	}
	return math.NaN(), nil
}
Example #5
0
/// <summary>
/// downside risk (deviation, variance) of the return distribution
/// Downside deviation, semideviation, and semivariance are measures of downside
/// risk.
/// </summary>
// = "full"
// = false
//func DownsideDeviation(Ra *utils.SlidingWindow, MAR *utils.SlidingWindow, method string, potential bool) float64 {
func DownsideDeviation(Ra *utils.SlidingWindow, MAR *utils.SlidingWindow) (float64, error) {
	if Ra == nil {
		return math.NaN(), errors.New("In DownsideDeviation, Ra == nil")
	}
	if Ra.Count() <= 0 {
		return math.NaN(), errors.New("In DownsideDeviation, Ra.Count() <= 0")
	}

	r, err := utils.NewSlidingWindow(Ra.Count())
	if err != nil {
		return math.NaN(), err
	}

	newMAR, err := utils.NewSlidingWindow(Ra.Count())
	if err != nil {
		return math.NaN(), err
	}
	len := 0.0
	result := 0.0
	for i := 0; i < Ra.Count(); i++ {
		if Ra.Data()[i] < MAR.Data()[i] {
			r.Add(Ra.Data()[i])
			newMAR.Add(MAR.Data()[i])
		}
	}

	potential := false
	method := "subset"

	if method == "full" {
		len = float64(Ra.Count())
	} else if method == "subset" {
		len = float64(r.Count())
	} else {
		return math.NaN(), errors.New("In DownsideDeviation, method default !!!")
	}
	if newMAR.Count() <= 0 || r.Count() <= 0 || len <= 0 {
		return math.NaN(), errors.New("In DownsideDeviation, newMAR.Count() <= 0 || r.Count() <= 0 || len <= 0")
	}
	if potential {
		sub_Sliding, err := utils.Sub(newMAR, r)
		if err != nil {
			return math.NaN(), err
		}
		result = sub_Sliding.Sum() / len
	} else {
		sub_Sliding, err := utils.Sub(newMAR, r)
		if err != nil {
			return math.NaN(), err
		}
		pow_Sliding, err := utils.Power(sub_Sliding, 2.0)
		if err != nil {
			return math.NaN(), err
		}
		result = math.Sqrt(pow_Sliding.Sum() / len)
	}
	return result, nil
}
Example #6
0
/// <summary>
///  Upside Risk is the similar of semideviation taking the return above the
///  Minimum Acceptable Return instead of using the mean return or zero.
///  (一般来说,非对称类的比较,单求此统计量意义有限)
/// </summary>
func UpsideRisk(Ra *utils.SlidingWindow, MAR float64, stat string) (float64, error) {
	r, err := utils.AboveValue(Ra, MAR)
	if err != nil {
		return math.NaN(), err
	}
	var length float64
	method := "subset"
	switch method {
	case "full":
		length = float64(Ra.Count())
		break
	case "subset":
		length = float64(r.Count())
		break
	default:
		return math.NaN(), errors.New("In Upside Risk, method is default !!!")
	}
	if length <= 0 {
		return 0, nil
	}
	var result float64
	switch stat {
	case "risk":
		add_Sliding, err := utils.Add(-MAR, r)
		if err != nil {
			return math.NaN(), err
		}
		pow_Sliding, err := utils.Power(add_Sliding, 2.0)
		if err != nil {
			return math.NaN(), err
		}
		multi_Sliding, err := utils.Multi(1.0/length, pow_Sliding)
		if err != nil {
			return math.NaN(), err
		}
		result = math.Sqrt(multi_Sliding.Sum())
		break
	case "variance":
		add_Sliding, err := utils.Add(-MAR, r)
		if err != nil {
			return math.NaN(), err
		}
		pow_Sliding, err := utils.Power(add_Sliding, 2.0)
		if err != nil {
			return math.NaN(), err
		}
		multi_Sliding, err := utils.Multi(1.0/length, pow_Sliding)
		if err != nil {
			return math.NaN(), err
		}
		result = multi_Sliding.Sum()
		break
	case "potential":
		add_Sliding, err := utils.Add(-MAR, r)
		if err != nil {
			return math.NaN(), err
		}
		multi_Slding, err := utils.Multi(1.0/length, add_Sliding)
		if err != nil {
			return math.NaN(), err
		}
		result = multi_Slding.Sum()
		break
	default:
		return math.NaN(), errors.New("In UpSide Risk, method is default !!!")
	}

	return result, nil
}
Example #7
0
/// <summary>
/// Appraisal ratio is the Jensen's alpha adjusted for specific risk. The numerator
/// is divided by specific risk instead of total risk.
/// </summary>
func AppraisalRatio(Ra *utils.SlidingWindow, Rb *utils.SlidingWindow, scale float64, Rf float64, method string) (float64, error) {
	var result = 0.0
	switch method {
	case "appraisal":
		be_data, err := Beta2(Ra, Rb, Rf)
		if err != nil {
			return math.NaN(), err
		}
		multi_Sliding, err := utils.Multi(be_data, Rb)
		if err != nil {
			return math.NaN(), err
		}
		sub_Sliding, err := utils.Sub(Ra, multi_Sliding)
		if err != nil {
			return math.NaN(), err
		}
		al_data, err := Alpha2(Ra, Rb, Rf)
		if err != nil {
			return math.NaN(), err
		}
		epsilon, err := utils.Add(-al_data, sub_Sliding)
		if err != nil {
			return math.NaN(), err
		}
		add_Sliding, err := utils.Add(-epsilon.Average(), epsilon)
		if err != nil {
			return math.NaN(), err
		}
		pow_Sliding, err := utils.Power(add_Sliding, 2)
		if err != nil {
			return math.NaN(), err
		}
		specifikRisk := math.Sqrt(pow_Sliding.Sum()/float64(epsilon.Count())) * math.Sqrt(float64(scale))
		jsa_data, err := JensenAlpha2(Ra, Rb, Rf, scale)
		if err != nil {
			return math.NaN(), err
		}
		result = jsa_data / specifikRisk
		break
	case "modified":
		jsa2_data, err := JensenAlpha2(Ra, Rb, Rf, scale)
		if err != nil {
			return math.NaN(), err
		}
		be2_data, err := Beta2(Ra, Rb, Rf)
		if err != nil {
			return math.NaN(), err
		}
		result = jsa2_data / be2_data
		break
	case "alternative":
		jsa2_data, err := JensenAlpha2(Ra, Rb, Rf, scale)
		if err != nil {
			return math.NaN(), err
		}
		sr_data, err := SystematicRisk(Ra, Rb, scale, Rf)
		if err != nil {
			return math.NaN(), err
		}
		result = jsa2_data / sr_data
		break
	default:
		return math.NaN(), errors.New("In AppraisalRatio, method is default !!!")
	}
	return result, nil
}