Beispiel #1
0
//= "full"
// = false
func DownsideDeviation2(Ra *utils.SlidingWindow, MAR float64) (float64, error) {
	if Ra == nil || Ra.Count() <= 0 {
		return math.NaN(), errors.New("In DownsideDeviation2, Ra == nil || Ra.Count() <= 0")
	}
	newMAR, _ := utils.CreateList(MAR, Ra.Count())
	return DownsideDeviation(Ra, newMAR)
}
Beispiel #2
0
/// <summary>
/// subset of returns that are
/// more than the target (or Minimum Acceptable Returns (MAR)) returns and
/// divide the length of this subset by the total number of returns.
/// (超过MAR的频率)
/// </summary>
func UpsideFrequency(Ra *utils.SlidingWindow, MAR float64) (float64, error) {
	aboveMAR, err := utils.AboveValue(Ra, MAR)
	if err != nil {
		return math.NaN(), err
	}
	return float64(aboveMAR.Count()) / float64(Ra.Count()), nil
}
Beispiel #3
0
/// <summary>
/// Upside Potential Ratio,compared to Sortino, was a further improvement, extending the
/// measurement of only upside on the numerator, and only downside of the
/// denominator of the ratio equation.
/// (分子只考虑超过MAR部分,分母只考虑DownsideDeviation的下跌风险)
/// </summary>
func UpsidePotentialRatio(Ra *utils.SlidingWindow, MAR float64) (float64, error) {
	//var r = Ra.Where<float64>(singleData => singleData > MAR).ToList<float64>();
	r, err := utils.AboveValue(Ra, MAR)
	if err != nil {
		return math.NaN(), err
	}
	var length int
	method := "subset"
	switch method {
	case "full":
		length = Ra.Count()
		break
	case "subset":
		length = r.Count()
		break
	default:
		return math.NaN(), errors.New("In UpsidePotentialRatio, method is default !!!")
	}
	add_Sliding, err := utils.Add(-MAR, r)
	if err != nil {
		return math.NaN(), err
	}
	dd2Data, err := DownsideDeviation2(Ra, MAR)
	if err != nil {
		return math.NaN(), err
	}
	var result = (add_Sliding.Sum() / float64(length)) / dd2Data
	return result, nil
}
Beispiel #4
0
/// <summary>
/// calculate a traditional or modified Sharpe Ratio of Return over StdDev or
/// VaR or ES
///
/// The Sharpe ratio is simply the return per unit of risk (represented by
/// variability).  In the classic case, the unit of risk is the standard
/// deviation of the returns.
/// </summary>
func SharpeRatio(Ra *utils.SlidingWindow, Rf_val float64, scale float64) (float64, error) {
	Rf, err := utils.CreateList(Rf_val, Ra.Count())
	if err != nil {
		return math.NaN(), err
	}
	xR, err := Excess(Ra, Rf)
	if err != nil {
		return math.NaN(), err
	}
	numerator := 0.0
	denominator := 0.0
	annualize := 1
	if annualize == 1 {
		denominator, err = StdDev_Annualized(Ra, scale)
		if err != nil {
			return math.NaN(), err
		}
		numerator, err = Annualized(xR, scale, true)
		if err != nil {
			return math.NaN(), err
		}
	} else {
		denominator, err = StdDev(Ra)
		if err != nil {
			return math.NaN(), err
		}
		numerator = xR.Average()
	}

	return numerator / denominator, nil
}
Beispiel #5
0
/// <summary>
/// Calculate the drawdown levels in a timeseries
/// </summary>
//= true
func Drawdowns(Rb *utils.SlidingWindow) ([]float64, error) {
	Ra := Rb.Data()
	if Ra == nil || len(Ra) <= 0 {
		return nil, errors.New("In Drawdowns, Ra == nil")
	}

	geometric := 1

	curReturn := 1.0
	curMaxReturn := 1.0 + Ra[0]
	result := []float64{}
	if geometric == 1 {
		for _, r := range Ra {
			curReturn = curReturn * (1.0 + r)
			if curReturn > curMaxReturn {
				curMaxReturn = curReturn
			}
			result = append(result, curReturn/curMaxReturn-1.0)
		}
	} else {
		for _, r := range Ra {
			curReturn = curReturn + r
			if curReturn > curMaxReturn {
				curMaxReturn = curReturn
			}
			result = append(result, curReturn/curMaxReturn-1.0)
		}
	}

	return result, nil
}
Beispiel #6
0
func Beta2(Ra, Rb *utils.SlidingWindow, Rf float64) (float64, error) {
	RfList, err := utils.CreateList(Rf, Ra.Count())
	if err != nil {
		return math.NaN(), err
	}
	return Beta(Ra, Rb, RfList)
}
Beispiel #7
0
/// <summary>
/// 收益率序列的几何均值,非年化
/// </summary>
func MeanGeometric(Ra *utils.SlidingWindow) (float64, error) {
	if Ra.Count() <= 0 {
		return math.NaN(), errors.New("In MeanGeometric, Ra.Count() <= 0")
	}
	add_Sliding, _ := utils.Add(1, Ra)
	log_Sliding, _ := utils.Log(add_Sliding)
	return math.Exp(log_Sliding.Average()) - 1.0, nil
}
Beispiel #8
0
/// <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)
}
Beispiel #9
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
}
Beispiel #10
0
/// <summary>
/// Fama beta is a beta used to calculate the loss of diversification. It is made
/// so that the systematic risk is equivalent to the total portfolio risk.
/// </summary>
func FamaBeta(Ra *utils.SlidingWindow, Rb *utils.SlidingWindow, Ra_sclae float64, Rb_scale float64) (float64, error) {
	var n1 = Ra.Count()
	var n2 = Rb.Count()
	var_Ra, err := Variance(Ra)
	if err != nil {
		return math.NaN(), err
	}
	var_Rb, err := Variance(Rb)
	if err != nil {
		return math.NaN(), err
	}
	var result = math.Sqrt(var_Ra*float64(n1-1)/float64(n1)) * math.Sqrt(float64(Ra_sclae)) / (math.Sqrt(var_Rb*float64(n2-1)/float64(n2)) * math.Sqrt(float64(Rb_scale)))
	return result, nil
}
Beispiel #11
0
/// <summary>
/// Prospect ratio is a ratio used to penalise loss since most people feel loss
/// greater than gain
/// (经验类型调整收益率,给损失赋予更大的权重)
/// </summary>
func ProspectRatio(Ra *utils.SlidingWindow, MAR float64) (float64, error) {
	var n = Ra.Count()
	SigD, err := DownsideDeviation2(Ra, MAR)
	if err != nil {
		return math.NaN(), err
	}

	positivevalues, negativevalues, err := utils.PosNegValues(Ra)
	if err != nil {
		return math.NaN(), err
	}

	var result = ((positivevalues.Sum()+2.25*negativevalues.Sum())/float64(n) - MAR) / SigD
	return result, nil
}
Beispiel #12
0
/// <summary>
/// downside frequency of the return distribution
/// To calculate Downside Frequency, we take the subset of returns that are
/// less than the target (or Minimum Acceptable Returns (MAR)) returns and
/// divide the length of this subset by the total number of returns.
/// </summary>
func DownsideFrequency(Ra *utils.SlidingWindow, MAR *utils.SlidingWindow) (float64, error) {
	if Ra == nil {
		return math.NaN(), errors.New("In DownsideFrequency, Ra == nil")
	}
	if Ra.Count() <= 0 {
		return math.NaN(), errors.New("In DownsideFrequency, Ra.Count() <= 0")
	}
	len := 0.0
	for i := 0; i < Ra.Count(); i++ {
		if Ra.Data()[i] < MAR.Data()[i] {
			len++
		}
	}

	return len / float64(Ra.Count()), nil
}
Beispiel #13
0
func Excess(returns, Rf *utils.SlidingWindow) (*utils.SlidingWindow, error) {
	result, err := utils.NewSlidingWindow(returns.Count())
	if err != nil {
		return nil, err
	}
	for i := 0; i < returns.Count(); i++ {
		result.Add(returns.Data()[i] - Rf.Data()[i])
	}
	return result, nil
}
Beispiel #14
0
func PainRatio(Ra *utils.SlidingWindow, Rf float64, scale float64) (float64, error) {
	PI, err := PainIndex(Ra)
	if err != nil {
		return math.NaN(), err
	}
	n := Ra.Count()
	add_Sliding, err := utils.Add(1.0, Ra)
	if err != nil {
		return math.NaN(), err
	}
	prod_Sliding, err := utils.Prod(add_Sliding)
	if err != nil {
		return math.NaN(), err
	}
	Rp := math.Pow(prod_Sliding, float64(scale)/float64(n)) - 1.0
	Rf = Rf * scale
	return (Rp - Rf) / PI, nil
}
Beispiel #15
0
/// <param name="returns"></param>
/// <param name="geometric"></param>
/// <returns></returns>
func Cumulative(returns *utils.SlidingWindow, geometric bool) (float64, error) {
	if returns == nil {
		return math.NaN(), errors.New("Cumulative Sliding window is Nil !!!")
	}
	if returns.Count() == 0 {
		return math.NaN(), errors.New("Cumulative Count == 0 !!")
	}
	if !geometric {
		return (returns.Sum()), nil
	} else {
		add_data, err := utils.Add(1.0, returns)
		if err != nil {
			return math.NaN(), err
		}
		prod_data, err := utils.Prod(add_data)
		if err != nil {
			return math.NaN(), err
		}
		return (prod_data - 1.0), nil
	}
}
Beispiel #16
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
}
Beispiel #17
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
}
Beispiel #18
0
/// <param name="Ra"></param>
/// <param name="Rb"></param>
/// <returns></returns>
func Relative(Ra, Rb *utils.SlidingWindow) (*utils.SlidingWindow, error) {
	res4Ra := 1.0
	res4Rb := 1.0
	result, err := utils.NewSlidingWindow(Ra.Count())
	if err != nil {
		return nil, err
	}
	for i := 0; i < Ra.Count(); i++ {
		res4Ra = res4Ra * (1 + Ra.Data()[i])
		res4Rb = res4Rb * (1 + Rb.Data()[i])
		result.Add(res4Ra / res4Rb)
	}
	return result, nil
}
Beispiel #19
0
/// <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
}
Beispiel #20
0
/// <summary>
/// M squared is a risk adjusted return useful to judge the size of relative
/// performance between differents portfolios. With it you can compare portfolios
/// with different levels of risk.
/// (使得不同组合的收益率可比的调整措施)
/// </summary>
func MSquared(Ra *utils.SlidingWindow, Rb *utils.SlidingWindow, scale float64, Rf float64) (float64, error) {
	var n = Ra.Count()
	Rp, err := Annualized(Ra, scale, true)
	if err != nil {
		return math.NaN(), err
	}
	var_Ra_data, err := Variance(Ra)
	if err != nil {
		return math.NaN(), err
	}
	sigp := math.Sqrt(var_Ra_data*float64(n-1)/float64(n)) * math.Sqrt(float64(scale))
	if err != nil {
		return math.NaN(), err
	}
	var_Rb_data, err := Variance(Rb)
	if err != nil {
		return math.NaN(), err
	}
	var sigm = math.Sqrt(var_Rb_data*float64(n-1)/float64(n)) * math.Sqrt(float64(scale))
	//var result = (Rp-Rf)*sigp/sigm + Rf//Source
	Rf = Rf * scale
	var result = (Rp-Rf)*sigm/sigp + Rf
	return result, nil
}
Beispiel #21
0
/// <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
	}
}
Beispiel #22
0
/// <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
}
Beispiel #23
0
/// <param name="prices"></param>
/// <param name="method"></param>
/// <returns></returns>
func Calculate(prices *utils.SlidingWindow, method string) (*utils.SlidingWindow, error) {
	if prices == nil {
		return nil, errors.New("Prices Utils Sliding Window is nil")
	}
	if prices.Count() == 0 {
		return nil, errors.New("Returns Windows content is Zero")
	}

	lastPrice := prices.First()
	returns, err := utils.NewSlidingWindow(prices.Count())
	if err != nil {
		return nil, errors.New("create a Sliding Window is Error !!")
	}

	switch method {
	case "simple":
	case "discrete":
		for i := 0; i < prices.Count(); i++ {
			price := prices.Data()[i]
			if lastPrice != 0.0 {
				returns.Add(price/lastPrice - 1.0)
			} else {
				returns.Add(0.0)
			}
			lastPrice = price
		}
	case "compound":
	case "log":
		for i := 0; i < prices.Count(); i++ {
			price := prices.Data()[i]
			if lastPrice != 0.0 {
				returns.Add(math.Log(price / lastPrice))
			} else {
				returns.Add(0.0)
			}
			lastPrice = price
		}
	default:
		return nil, errors.New("The input Method is nil !!!")
	}
	return returns, nil
}
Beispiel #24
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
}
Beispiel #25
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
}
Beispiel #26
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
}
Beispiel #27
0
/// <summary>
/// 只测试了默认参数
/// Calculate metrics on how the asset in R performed in up and down markets,
/// measured by periods when the benchmark asset was up or down.
/// Up (Down) Capture Ratio: this is a measure of an investment's compound
/// return when the benchmark was up (down) divided by the benchmark's compound
/// return when the benchmark was up (down). The greater (lower) the value, the
/// better.(Up越大越好,Down越小越好)
///
/// Up (Down) Number Ratio: similarly, this is a measure of the number of
/// periods that the investment was up (down) when the benchmark was up (down),
/// divided by the number of periods that the Benchmark was up (down).(Up越大越好,Down越小越好)
///
/// Up (Down) Percentage Ratio: this is a measure of the number of periods that
/// the investment outperformed the benchmark when the benchmark was up (down),
/// divided by the number of periods that the benchmark was up (down). Unlike
/// the prior two metrics, in both cases a higher value is better.(Up、Down均为越大越好)
/// (当市场涨跌时,组合收益率涨跌所占比率,)
/// </summary>
func UpDownRatios(Ra *utils.SlidingWindow, Rb *utils.SlidingWindow) (float64, error) {
	var cumRa = 0.0
	var cumRb = 0.0
	var result = 0.0

	method := "Capture"
	side := "Up"

	switch method {
	case "Capture":

		switch side {
		case "Up":

			UpRa, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			UpRb, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			for i := 0; i < Ra.Count(); i++ {
				if Rb.Data()[i] > 0 {
					UpRa.Add(Ra.Data()[i])
					UpRb.Add(Rb.Data()[i])
				}
			}
			cumRa = UpRa.Sum()
			cumRb = UpRb.Sum()
			result = cumRa / cumRb
			return result, nil

		case "Down":

			DnRa, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			DnRb, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			for i := 0; i < Ra.Count(); i++ {
				if Rb.Data()[i] <= 0 {
					DnRa.Add(Ra.Data()[i])
					DnRb.Add(Rb.Data()[i])
				}
			}
			cumRa = DnRa.Sum()
			cumRb = DnRb.Sum()
			result = cumRa / cumRb
			return result, nil

		default:
			return math.NaN(), errors.New("In UpDownRatios, method Default!!")
		}

	case "Number":

		switch side {
		case "Up":

			UpRa, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			UpRb, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			for i := 0; i < Ra.Count(); i++ {
				if Ra.Data()[i] > 0 && Rb.Data()[i] > 0 {
					UpRa.Add(Ra.Data()[i])
				}
			}
			for i := 0; i < Ra.Count(); i++ {
				if Rb.Data()[i] > 0 {
					UpRb.Add(Rb.Data()[i])
				}
			}

			cumRa = float64(UpRa.Count())
			cumRb = float64(UpRb.Count())
			result = cumRa / cumRb
			return result, nil

		case "Down":

			DnRa, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			DnRb, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			for i := 0; i < Ra.Count(); i++ {
				if Ra.Data()[i] < 0 && Rb.Data()[i] < 0 {
					DnRa.Add(Ra.Data()[i])
				}
			}
			for i := 0; i < Ra.Count(); i++ {
				if Rb.Data()[i] < 0 {
					DnRb.Add(Rb.Data()[i])
				}
			}

			cumRa = float64(DnRa.Count())
			cumRb = float64(DnRb.Count())
			result = cumRa / cumRb
			return result, nil

		default:
			return math.NaN(), errors.New("In UpDownRatios, method default 2 error !!!")
		}

	case "Percent":

		switch side {
		case "Up":

			UpRa, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			UpRb, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			for i := 0; i < Ra.Count(); i++ {
				if Ra.Data()[i] > Rb.Data()[i] && Rb.Data()[i] > 0 {
					UpRa.Add(Ra.Data()[i])
				}
			}
			for i := 0; i < Ra.Count(); i++ {
				if Rb.Data()[i] > 0 {
					UpRb.Add(Rb.Data()[i])
				}
			}

			cumRa = float64(UpRa.Count())
			cumRb = float64(UpRb.Count())
			result = cumRa / cumRb
			return result, nil

		case "Down":

			DnRa, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			DnRb, err := utils.NewSlidingWindow(Ra.Count())
			if err != nil {
				return math.NaN(), err
			}
			for i := 0; i < Ra.Count(); i++ {
				if Ra.Data()[i] > Rb.Data()[i] && Rb.Data()[i] < 0 {
					DnRa.Add(Ra.Data()[i])
				}
			}
			for i := 0; i < Ra.Count(); i++ {
				if Rb.Data()[i] < 0 {
					DnRb.Add(Rb.Data()[i])
				}
			}

			cumRa = float64(DnRa.Count())
			cumRb = float64(DnRb.Count())
			result = cumRa / cumRb
			return result, nil

		default:
			return math.NaN(), errors.New("In UpDownRatios, method default 3 is Error !!!")
		}

	default:
		return math.NaN(), errors.New("In UpDownRatios, method default 4 is Error !!!")
	}
	return math.NaN(), nil
}
Beispiel #28
0
/// <summary>
/// d ratio of the return distribution
/// The d ratio is similar to the Bernado Ledoit ratio but inverted and
/// taking into account the frequency of positive and negative returns.
/// </summary>
func DRatio(Ra *utils.SlidingWindow) (float64, error) {
	if Ra == nil {
		return math.NaN(), errors.New("In DRatio, Ra == nil")
	}
	if Ra.Count() <= 0 {
		return math.NaN(), errors.New("In DRatio, Ra.Count() <= 0")
	}

	upList, _ := utils.NewSlidingWindow(Ra.Count())
	downList, _ := utils.NewSlidingWindow(Ra.Count())

	for i := 0; i < Ra.Count(); i++ {
		if Ra.Data()[i] < 0 {
			downList.Add(Ra.Data()[i])
		} else if Ra.Data()[i] > 0 {
			upList.Add(Ra.Data()[i])
		}
	}

	return -(downList.Sum() * float64(downList.Count())) / (float64(upList.Sum()) * float64(upList.Count())), nil
}