/// <summary> /// Computes expected shortfall. /// </summary> /// <param name="index"> the index from which the ES should be computed </param> /// <param name="runningWeight"> the running weight up to index </param> /// <param name="s"> the sorted sample </param> /// <param name="w"> the sorted weights </param> /// <param name="order"> the order of the sorted sample in the unsorted sample </param> /// <param name="level"> the level at which the ES should be computed </param> /// <returns> the expected shortfall and the details of sample data used to compute it </returns> private QuantileResult esFromIndexRunningWeight(int index, double runningWeight, double[] s, double[] w, double[] order, double level) { int nbData = s.Length; if ((index == nbData - 1) || (index == nbData)) { return(QuantileResult.of(s[nbData - 1], new int[] { (int)(long)Math.Round(order[nbData - 1], MidpointRounding.AwayFromZero) }, DoubleArray.of(1.0d))); } double alpha = (runningWeight - (1.0 - level)) / w[index]; int[] indices = new int[nbData - index]; double[] impacts = new double[nbData - index]; for (int i = 0; i < nbData - index; i++) { indices[i] = (int)(long)Math.Round(order[index + i], MidpointRounding.AwayFromZero); } impacts[0] = 0.5 * (1 - alpha) * (1 - alpha) * w[index] / (1.0 - level); impacts[1] = (alpha + 1) * 0.5 * (1 - alpha) * w[index] / (1.0 - level); for (int i = 1; i < nbData - index - 1; i++) { impacts[i] += 0.5 * w[index + i] / (1.0 - level); impacts[i + 1] += 0.5 * w[index + i] / (1.0 - level); } impacts[nbData - index - 1] += w[nbData - 1] / (1.0 - level); double es = 0; for (int i = 0; i < nbData - index; i++) { es += s[index + i] * impacts[i]; } return(QuantileResult.of(es, indices, DoubleArray.ofUnsafe(impacts))); }
protected internal override QuantileResult expectedShortfall(double level, DoubleArray sample) { ArgChecker.isTrue(level > 0, "Quantile should be above 0."); ArgChecker.isTrue(level < 1, "Quantile should be below 1."); int sampleSize = sampleCorrection(sample.size()); double[] order = createIndexArray(sample.size()); double[] s = sample.toArray(); DoubleArrayMath.sortPairs(s, order); double fractionalIndex = level * sampleSize; int index = (int)checkIndex(this.index(fractionalIndex), sample.size(), true); int[] indices = new int[index]; double[] weights = new double[index]; double interval = 1d / (double)sampleSize; double losses = s[0] * interval *indexShift(); for (int i = 0; i < index - 1; i++) { losses += s[i] * interval; indices[i] = (int)order[i]; weights[i] = interval; } losses += s[index - 1] * (fractionalIndex - index + 1 - indexShift()) * interval; indices[index - 1] = (int)order[index - 1]; weights[0] += interval * indexShift(); weights[index - 1] = (fractionalIndex - index + 1 - indexShift()) * interval; return(QuantileResult.of(losses / level, indices, DoubleArray.ofUnsafe(weights).dividedBy(level))); }
//----------------------------------------------------------------------- public override bool Equals(object obj) { if (obj == this) { return(true); } if (obj != null && obj.GetType() == this.GetType()) { QuantileResult other = (QuantileResult)obj; return(JodaBeanUtils.equal(value, other.value) && JodaBeanUtils.equal(indices, other.indices) && JodaBeanUtils.equal(weights, other.weights)); } return(false); }
protected internal override QuantileResult quantile(double level, DoubleArray sample, bool isExtrapolated) { ArgChecker.isTrue(level > 0, "Quantile should be above 0."); ArgChecker.isTrue(level < 1, "Quantile should be below 1."); int sampleSize = sampleCorrection(sample.size()); double[] order = createIndexArray(sample.size()); double[] s = sample.toArray(); DoubleArrayMath.sortPairs(s, order); int index = (int)checkIndex(this.index(level * sampleSize), sample.size(), isExtrapolated); int[] ind = new int[1]; ind[0] = (int)order[index - 1]; return(QuantileResult.of(s[index - 1], ind, DoubleArray.of(1))); }
protected internal override QuantileResult expectedShortfall(double level, DoubleArray sample) { ArgChecker.isTrue(level > 0, "Quantile should be above 0."); ArgChecker.isTrue(level < 1, "Quantile should be below 1."); int sampleSize = sampleCorrection(sample.size()); double fractionalIndex = level * sampleSize + indexCorrection(); double adjustedLevel = checkIndex(fractionalIndex, sample.size(), true); double[] order = createIndexArray(sample.size()); double[] s = sample.toArray(); DoubleArrayMath.sortPairs(s, order); int lowerIndex = (int)Math.Floor(adjustedLevel); int upperIndex = (int)Math.Ceiling(adjustedLevel); int[] indices = new int[upperIndex]; double[] weights = new double[upperIndex]; double interval = 1d / (double)sampleSize; weights[0] = interval * (Math.Min(fractionalIndex, 1d) - indexCorrection()); double losses = s[0] * weights[0]; for (int i = 0; i < lowerIndex - 1; i++) { losses += 0.5 * (s[i] + s[i + 1]) * interval; indices[i] = (int)order[i]; weights[i] += 0.5 * interval; weights[i + 1] += 0.5 * interval; } if (lowerIndex != upperIndex) { double lowerWeight = upperIndex - adjustedLevel; double upperWeight = 1d - lowerWeight; double quantile = lowerWeight * s[lowerIndex - 1] + upperWeight * s[upperIndex - 1]; losses += 0.5 * (s[lowerIndex - 1] + quantile) * interval * upperWeight; indices[lowerIndex - 1] = (int)order[lowerIndex - 1]; indices[upperIndex - 1] = (int)order[upperIndex - 1]; weights[lowerIndex - 1] += 0.5 * (1d + lowerWeight) * interval * upperWeight; weights[upperIndex - 1] = 0.5 * upperWeight * interval * upperWeight; } if (fractionalIndex > sample.size()) { losses += s[sample.size() - 1] * (fractionalIndex - sample.size()) * interval; indices[sample.size() - 1] = (int)order[sample.size() - 1]; weights[sample.size() - 1] += (fractionalIndex - sample.size()) * interval; } return(QuantileResult.of(losses / level, indices, DoubleArray.ofUnsafe(weights).dividedBy(level))); }
protected internal override QuantileResult quantile(double level, DoubleArray sample, bool isExtrapolated) { ArgChecker.isTrue(level > 0, "Quantile should be above 0."); ArgChecker.isTrue(level < 1, "Quantile should be below 1."); int sampleSize = sampleCorrection(sample.size()); double adjustedLevel = checkIndex(level * sampleSize + indexCorrection(), sample.size(), isExtrapolated); double[] order = createIndexArray(sample.size()); double[] s = sample.toArray(); DoubleArrayMath.sortPairs(s, order); int lowerIndex = (int)Math.Floor(adjustedLevel); int upperIndex = (int)Math.Ceiling(adjustedLevel); double lowerWeight = upperIndex - adjustedLevel; double upperWeight = 1d - lowerWeight; return(QuantileResult.of(lowerWeight * s[lowerIndex - 1] + upperWeight * s[upperIndex - 1], new int[] { (int)order[lowerIndex - 1], (int)order[upperIndex - 1] }, DoubleArray.of(lowerWeight, upperWeight))); }
public virtual void es_details() { double[] level = new double[] { 0.98, 0.981, 0.9811, 0.97 }; for (int i = 0; i < level.Length; i++) { double es = METHOD.expectedShortfallFromUnsorted(level[i], DATA_123); QuantileResult r = METHOD.expectedShortfallDetailsFromUnsorted(level[i], DATA_123); assertEquals(r.Value, es, TOLERANCE_QUANTILE); assertEquals(r.Indices.Length, r.Weights.size()); double qExpected = 0.0; for (int j = 0; j < r.Indices.Length; j++) { // Recompute ES from details qExpected += DATA_123.get(r.Indices[j]) * r.Weights.get(j); } assertEquals(qExpected, es, TOLERANCE_QUANTILE); } }
/// <summary> /// Computes value-at-risk. /// </summary> /// <param name="index"> the index from which the VaR should be computed </param> /// <param name="runningWeight"> the running weight up to index </param> /// <param name="isExtrapolated"> flag indicating if value should be extrapolated (flat) beyond the last value </param> /// <param name="s"> the sorted sample </param> /// <param name="w"> the sorted weights </param> /// <param name="order"> the order of the sorted sample in the unsorted sample </param> /// <param name="level"> the level at which the VaR should be computed </param> /// <returns> the VaR and the details of sample data used to compute it </returns> private QuantileResult quantileFromIndexRunningWeight(int index, double runningWeight, bool isExtrapolated, double[] s, double[] w, double[] order, double level) { int nbData = s.Length; if ((index == nbData - 1) || (index == nbData)) { ArgChecker.isTrue(isExtrapolated, "Quantile can not be computed above the highest probability level."); return(QuantileResult.of(s[nbData - 1], new int[] { (int)(long)Math.Round(order[nbData - 1], MidpointRounding.AwayFromZero) }, DoubleArray.of(1.0d))); } double alpha = (runningWeight - (1.0 - level)) / w[index]; int[] indices = new int[nbData - index]; double[] impacts = new double[nbData - index]; for (int i = 0; i < nbData - index; i++) { indices[i] = (int)(long)Math.Round(order[index + i], MidpointRounding.AwayFromZero); } impacts[0] = 1 - alpha; impacts[1] = alpha; return(QuantileResult.of((1 - alpha) * s[index] + alpha * s[index + 1], indices, DoubleArray.ofUnsafe(impacts))); }
public virtual void es_weights_indices_test() { QuantileResult esAbove = QUANTILE_INDEX_ABOVE.expectedShortfallResultFromUnsorted(LEVEL2, UNSORTED_100); double expectedValueAbove = 0d; double sumWeightsAbove = 0d; for (int i = 0; i < esAbove.Indices.Length; i++) { expectedValueAbove += UNSORTED_100.get(esAbove.Indices[i]) * esAbove.Weights.get(i); sumWeightsAbove += esAbove.Weights.get(i); } assertEquals(esAbove.Indices.Length, esAbove.Weights.size()); assertEquals(sumWeightsAbove, 1d, TOL); assertEquals(esAbove.Value, expectedValueAbove, TOL); QuantileResult esNearest = QUANTILE_NEAREST_INDEX.expectedShortfallResultFromUnsorted(LEVEL2, UNSORTED_100); double expectedValueNearest = 0d; double sumWeightsNearest = 0d; for (int i = 0; i < esNearest.Indices.Length; i++) { expectedValueNearest += UNSORTED_100.get(esNearest.Indices[i]) * esNearest.Weights.get(i); sumWeightsNearest += esNearest.Weights.get(i); } assertEquals(esNearest.Indices.Length, esNearest.Weights.size()); assertEquals(sumWeightsNearest, 1d, TOL); assertEquals(esNearest.Value, expectedValueNearest, TOL); QuantileResult esSample = QUANTILE_SAMPLE1_NEAREST_INDEX.expectedShortfallResultFromUnsorted(LEVEL2, UNSORTED_100); double expectedValueSample = 0d; double sumWeightsSample = 0d; for (int i = 0; i < esSample.Indices.Length; i++) { expectedValueSample += UNSORTED_100.get(esSample.Indices[i]) * esSample.Weights.get(i); sumWeightsSample += esSample.Weights.get(i); } assertEquals(esSample.Indices.Length, esSample.Weights.size()); assertEquals(sumWeightsSample, 1d, TOL); assertEquals(esSample.Value, expectedValueSample, TOL); QuantileResult esSampleInterp = QUANTILE_SAMPLE_INTERPOLATION.expectedShortfallResultFromUnsorted(LEVEL2, UNSORTED_100); double expectedValueSampleInterp = 0d; double sumWeightsSampleInterp = 0d; for (int i = 0; i < esSampleInterp.Indices.Length; i++) { expectedValueSampleInterp += UNSORTED_100.get(esSampleInterp.Indices[i]) * esSampleInterp.Weights.get(i); sumWeightsSampleInterp += esSampleInterp.Weights.get(i); } assertEquals(esSampleInterp.Indices.Length, esSampleInterp.Weights.size()); assertEquals(sumWeightsSampleInterp, 1d, TOL); assertEquals(esSampleInterp.Value, expectedValueSampleInterp, TOL); QuantileResult esSample1Interp = QUANTILE_SAMPLE1_INTERPOLATION.expectedShortfallResultFromUnsorted(LEVEL2, UNSORTED_100); double expectedValueSample1Interp = 0d; double sumWeightsSample1Interp = 0d; for (int i = 0; i < esSample1Interp.Indices.Length; i++) { expectedValueSample1Interp += UNSORTED_100.get(esSample1Interp.Indices[i]) * esSample1Interp.Weights.get(i); sumWeightsSample1Interp += esSample1Interp.Weights.get(i); } assertEquals(esSample1Interp.Indices.Length, esSample1Interp.Weights.size()); assertEquals(sumWeightsSample1Interp, 1d, TOL); assertEquals(esSample1Interp.Value, expectedValueSample1Interp, TOL); QuantileResult esMidInterp = QUANTILE_MIDWAY_INTERPOLATION.expectedShortfallResultFromUnsorted(LEVEL2, UNSORTED_100); double expectedValueMidInterp = 0d; double sumWeightsMidInterp = 0d; for (int i = 0; i < esMidInterp.Indices.Length; i++) { expectedValueMidInterp += UNSORTED_100.get(esMidInterp.Indices[i]) * esMidInterp.Weights.get(i); sumWeightsMidInterp += esMidInterp.Weights.get(i); } assertEquals(esMidInterp.Indices.Length, esMidInterp.Weights.size()); assertEquals(sumWeightsMidInterp, 1d, TOL); assertEquals(esMidInterp.Value, expectedValueMidInterp, TOL); }