/// <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 }
/// <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 }
/// <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 }
/// <summary> /// To calculate Mean absolute deviation we take /// the sum of the absolute value of the difference between the returns and the mean of the returns /// and we divide it by the number of returns. /// (描述收益率偏离均值得一个指标) /// </summary> func MeanAbsoluteDeviation(Ra *utils.SlidingWindow) (float64, error) { if Ra.Count() <= 0 { return math.NaN(), errors.New("In MeanAbsoluteDeviation, Ra.Count() <= 0") } add_Sliding, _ := utils.Add(-Ra.Average(), Ra) ads_Sliding, _ := utils.Abs(add_Sliding) return ads_Sliding.Sum() / float64(Ra.Count()), nil }
/// <param name="returns"></param> /// <returns></returns> func Centered(returns *utils.SlidingWindow) (*utils.SlidingWindow, error) { if returns == nil { return nil, errors.New("Centered Sliding window is nil") } if returns.Count() == 0 { return nil, errors.New("Centered Count is Zero !!!") } return utils.Add(-returns.Average(), returns) }
/// <summary> /// 方差 /// </summary> func Variance(Ra *utils.SlidingWindow) (float64, error) { if Ra == nil || Ra.Count() <= 1 { return math.NaN(), errors.New("In Variance, Ra == nil || Ra.Count() <= 1") } result := 0.0 mean := Ra.Average() for i := 0; i < Ra.Count(); i++ { result += (Ra.Data()[i] - mean) * (Ra.Data()[i] - mean) } return result / (float64)(Ra.Count()-1), nil }
/// <param name="returns"></param> /// <param name="scale"></param> /// <param name="geometric"></param> /// <returns></returns> func Annualized(returns *utils.SlidingWindow, scale float64, geometric bool) (float64, error) { if returns == nil { return math.NaN(), errors.New("Returns Utils Sliding Window is nil") } if returns.Count() == 0 { return math.NaN(), errors.New("Returns Windows content is Zero") } n := returns.Count() if geometric { add_Sliding, err := utils.Add(1.0, returns) if err != nil { return math.NaN(), err } prod_Data, err := utils.Prod(add_Sliding) if err != nil { return math.NaN(), err } return math.Pow(prod_Data, float64(scale)/float64(n)) - 1.0, nil } else { return returns.Average() * float64(scale), nil } }