/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math.statistics.descriptive;
import java.util.Arrays;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.math.function.Function1D;
/**
* The second moment of a series of asset return data can be used as a measure
* of the risk of that asset. However, in many instances a large positive
* return is not regarded as a risk. The partial moment can be used as an
* alternative.
* <p>
* The lower (higher) partial moment considers only those values that are below
* (above) a threshold. Given a series of data $x_1, x_2, \dots, x_n$ sorted
* from lowest to highest, the first (last) $k$ values are below (above) the
* threshold $x_0$. The partial moment is given by:
* $$
* \begin{align*}
* \text{pm} = \sqrt{\frac{1}{k}\sum\limits_{i=1}^{k}(x_i - x_0)^2}
* \end{align*}
* $$
*/
public class PartialMomentCalculator extends Function1D<double[], Double> {
private final double _threshold;
private final boolean _useDownSide;
/**
* Creates calculator with default values: threshold = 0 and useDownSide = true
*/
public PartialMomentCalculator() {
this(0, true);
}
/**
*
* @param threshold The threshold value for the data
* @param useDownSide If true, all data below the threshold is used
*/
public PartialMomentCalculator(final double threshold, final boolean useDownSide) {
_threshold = threshold;
_useDownSide = useDownSide;
}
/**
* @param x The array of data, not null or empty
* @return The partial moment
*/
@Override
public Double evaluate(final double[] x) {
Validate.notNull(x, "x");
Validate.isTrue(x.length > 0, "x cannot be empty");
final int n = x.length;
final double[] copyX = Arrays.copyOf(x, n);
Arrays.sort(copyX);
double sum = 0;
if (_useDownSide) {
int i = 0;
if (copyX[i] > _threshold) {
return 0.;
}
while (i < n && copyX[i] < _threshold) {
sum += (copyX[i] - _threshold) * (copyX[i] - _threshold);
i++;
}
return Math.sqrt(sum / i);
}
int i = n - 1;
int count = 0;
if (copyX[i] < _threshold) {
return 0.;
}
while (i >= 0 && copyX[i] > _threshold) {
sum += (copyX[i] - _threshold) * (copyX[i] - _threshold);
count++;
i--;
}
return Math.sqrt(sum / count);
}
}