/** * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.math.impl.statistics.descriptive; import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.array.DoubleArray; /** * Abstract method to estimate quantiles and expected shortfalls from sample observations. */ public abstract class QuantileCalculationMethod { /** * Compute the quantile estimation. * <p> * The quantile level is in decimal, i.e. 99% = 0.99 and 0 < level < 1 should be satisfied. * This is measured from the bottom, that is, the quantile estimation with the level 99% corresponds to * the smallest 99% observations and 1% of the observation are above that level. * <p> * If index value computed from the level is outside of the sample data range, * {@code IllegalArgumentException} is thrown. * <p> * The sample observations are sorted from the smallest to the largest. * * @param level the quantile level * @param sortedSample the sample observations * @return the quantile estimation */ public double quantileFromSorted(double level, DoubleArray sortedSample) { return quantile(level, sortedSample, false); } /** * Compute the quantile estimation. * <p> * The quantile level is in decimal, i.e. 99% = 0.99 and 0 < level < 1 should be satisfied. * This is measured from the bottom, that is, the quantile estimation with the level 99% corresponds to * the smallest 99% observations and 1% of the observation are above that level. * <p> * If index value computed from the level is outside of the sample data range, * {@code IllegalArgumentException} is thrown. * <p> * The sample observations are supposed to be unsorted, the first step is to sort the data. * * @param level the quantile level * @param sample the sample observations * @return The quantile estimation */ public double quantileFromUnsorted(double level, DoubleArray sample) { return quantileFromSorted(level, sample.sorted()); } /** * Compute the quantile estimation. * <p> * The quantile level is in decimal, i.e. 99% = 0.99 and 0 < level < 1 should be satisfied. * This is measured from the bottom, that is, the quantile estimation with the level 99% corresponds to * the smallest 99% observations and 1% of the observation are above that level. * <p> * If index value computed from the level is outside of the sample data range, the nearest data point is used, i.e., * quantile is computed with flat extrapolation. * <p> * The sample observations are sorted from the smallest to the largest. * * @param level the quantile level * @param sortedSample the sample observations * @return the quantile estimation */ public double quantileWithExtrapolationFromSorted(double level, DoubleArray sortedSample) { return quantile(level, sortedSample, true); } /** * Compute the quantile estimation. * <p> * The quantile level is in decimal, i.e. 99% = 0.99 and 0 < level < 1 should be satisfied. * This is measured from the bottom, that is, the quantile estimation with the level 99% corresponds to * the smallest 99% observations and 1% of the observation are above that level. * <p> * If index value computed from the level is outside of the sample data range, the nearest data point is used, i.e., * quantile is computed with flat extrapolation. * <p> * The sample observations are supposed to be unsorted, the first step is to sort the data. * * @param level the quantile level * @param sample the sample observations * @return The quantile estimation */ public double quantileWithExtrapolationFromUnsorted(double level, DoubleArray sample) { return quantileWithExtrapolationFromSorted(level, sample.sorted()); } //------------------------------------------------------------------------- /** * Compute the expected shortfall. * <p> * The shortfall level is in decimal, i.e. 99% = 0.99 and 0 < level < 1 should be satisfied. * This is measured from the bottom, that is, the expected shortfall with the level 99% corresponds to * the average of the smallest 99% of the observations. * <p> * If index value computed from the level is outside of the sample data range, the nearest data point is used, i.e., * expected short fall is computed with flat extrapolation. * Thus this is coherent to {@link #quantileWithExtrapolationFromSorted(double, DoubleArray)}. * <p> * The sample observations are sorted from the smallest to the largest. * * @param level the quantile level * @param sortedSample the sample observations * @return the quantile estimation */ public double expectedShortfallFromSorted(double level, DoubleArray sortedSample) { return expectedShortfall(level, sortedSample); } /** * Compute the expected shortfall. * <p> * The quantile level is in decimal, i.e. 99% = 0.99 and 0 < level < 1 should be satisfied. * This is measured from the bottom, that is, Thus the expected shortfall with the level 99% corresponds to * the average of the smallest 99% of the observations. * <p> * If index value computed from the level is outside of the sample data range, the nearest data point is used, i.e., * expected short fall is computed with flat extrapolation. * Thus this is coherent to {@link #quantileWithExtrapolationFromUnsorted(double, DoubleArray)}. * <p> * The sample observations are supposed to be unsorted, the first step is to sort the data. * * @param level the quantile level * @param sample the sample observations * @return The expected shortfall estimation */ public double expectedShortfallFromUnsorted(double level, DoubleArray sample) { return expectedShortfallFromSorted(level, sample.sorted()); } //------------------------------------------------------------------------- /** * Computed the quantile. * <p> * This protected method should be implemented in subclasses. * * @param level the quantile level * @param sortedSample the sample observations * @param isExtrapolated extrapolated if true, not extrapolated otherwise. * @return the quantile */ protected abstract double quantile(double level, DoubleArray sortedSample, boolean isExtrapolated); /** * Computed the expected shortfall. * <p> * This protected method should be implemented in subclasses * and coherent to {@link #quantile(double, DoubleArray, boolean)}. * * @param level the quantile level * @param sortedSample the sample observations * @return the expected shortfall */ protected abstract double expectedShortfall(double level, DoubleArray sortedSample); /** * Check the index is within the sample data range. * * If the index is outside the data range, the nearest data point is used in case of {@code isExtrapolated == true} or * an exception is thrown in case of {@code isExtrapolated == false}. * * @param index the index * @param size the sample size * @param isExtrapolated extrapolated if true, not extrapolated otherwise * @return the index */ protected double checkIndex(double index, int size, boolean isExtrapolated) { if (isExtrapolated) { return Math.min(Math.max(index, 1), size); } ArgChecker.isTrue(index >= 1, "Quantile can not be computed below the lowest probability level."); ArgChecker.isTrue(index <= size, "Quantile can not be computed above the highest probability level."); return index; } }