/*! gaussian-assumption y-th percentile */ /*! \pre percentile must be in range (0%-100%) extremes excluded */ public double gaussianPercentile(double percentile) { Utils.QL_REQUIRE(percentile > 0.0 && percentile < 1.0, () => "percentile (" + percentile + ") must be in (0.0, 1.0)"); InverseCumulativeNormal gInverse = new InverseCumulativeNormal(mean(), standardDeviation()); return(gInverse.value(percentile)); }
/*! gaussian-assumption y-th percentile, defined as the value x * such that \f[ y = \frac{1}{\sqrt{2 \pi}} * \int_{-\infty}^{x} \exp (-u^2/2) du \f] */ /*! \pre percentile must be in range (0%-100%) extremes excluded */ public double gaussianPercentile(double percentile) { if (!(percentile > 0.0 && percentile < 1.0)) { throw new ApplicationException("percentile (" + percentile + ") must be in (0.0, 1.0)"); } InverseCumulativeNormal gInverse = new InverseCumulativeNormal(mean(), standardDeviation()); return(gInverse.value(percentile)); }
//! gaussian-assumption Expected Shortfall at a given percentile /*! Assuming a gaussian distribution it * returns the expected loss in case that the loss exceeded * a VaR threshold, * * that is the average of observations below the * given percentile \f$ p \f$. * Also know as conditional value-at-risk. * * See Artzner, Delbaen, Eber and Heath, * "Coherent measures of risk", Mathematical Finance 9 (1999) */ public double gaussianExpectedShortfall(double percentile) { Utils.QL_REQUIRE(percentile < 1.0 && percentile >= 0.9, () => "percentile (" + percentile + ") out of range [0.9, 1)"); double m = this.mean(); double std = this.standardDeviation(); InverseCumulativeNormal gInverse = new InverseCumulativeNormal(m, std); double var = gInverse.value(1.0 - percentile); NormalDistribution g = new NormalDistribution(m, std); double result = m - std * std * g.value(var) / (1.0 - percentile); // expectedShortfall must be a loss // this means that it has to be MIN(result, 0.0) // expectedShortfall must also be a positive quantity, so -MIN(*) return(-Math.Min(result, 0.0)); }
// alternative delta type private double strikeFromDelta(double delta, DeltaVolQuote.DeltaType dt) { double res = 0.0; double arg = 0.0; InverseCumulativeNormal f = new InverseCumulativeNormal(); Utils.QL_REQUIRE(delta * phi_ >= 0.0, () => "Option type and delta are incoherent."); switch (dt) { case DeltaVolQuote.DeltaType.Spot: Utils.QL_REQUIRE(Math.Abs(delta) <= fDiscount_, () => "Spot delta out of range."); arg = -phi_ *f.value(phi_ *delta / fDiscount_) * stdDev_ + 0.5 * stdDev_ * stdDev_; res = forward_ * Math.Exp(arg); break; case DeltaVolQuote.DeltaType.Fwd: Utils.QL_REQUIRE(Math.Abs(delta) <= 1.0, () => "Forward delta out of range."); arg = -phi_ *f.value(phi_ *delta) * stdDev_ + 0.5 * stdDev_ * stdDev_; res = forward_ * Math.Exp(arg); break; case DeltaVolQuote.DeltaType.PaSpot: case DeltaVolQuote.DeltaType.PaFwd: // This has to be solved numerically. One of the // problems is that the premium adjusted call delta is // not monotonic in strike, such that two solutions // might occur. The one right to the max of the delta is // considered to be the correct strike. Some proper // interval bounds for the strike need to be chosen, the // numerics can otherwise be very unreliable and // unstable. I've chosen Brent over Newton, since the // interval can be specified explicitly and we can not // run into the area on the left of the maximum. The // put delta doesn't have this property and can be // solved without any problems, but also numerically. BlackDeltaPremiumAdjustedSolverClass f1 = new BlackDeltaPremiumAdjustedSolverClass( ot_, dt, spot_, dDiscount_, fDiscount_, stdDev_, delta); Brent solver = new Brent(); solver.setMaxEvaluations(1000); double accuracy = 1.0e-10; double rightLimit = 0.0; double leftLimit = 0.0; // Strike of not premium adjusted is always to the right of premium adjusted if (dt == DeltaVolQuote.DeltaType.PaSpot) { rightLimit = strikeFromDelta(delta, DeltaVolQuote.DeltaType.Spot); } else { rightLimit = strikeFromDelta(delta, DeltaVolQuote.DeltaType.Fwd); } if (phi_ < 0) { // if put res = solver.solve(f1, accuracy, rightLimit, 0.0, spot_ * 100.0); break; } else { // find out the left limit which is the strike // corresponding to the value where premium adjusted // deltas have their maximum. BlackDeltaPremiumAdjustedMaxStrikeClass g = new BlackDeltaPremiumAdjustedMaxStrikeClass( ot_, dt, spot_, dDiscount_, fDiscount_, stdDev_); leftLimit = solver.solve(g, accuracy, rightLimit * 0.5, 0.0, rightLimit); double guess = leftLimit + (rightLimit - leftLimit) * 0.5; res = solver.solve(f1, accuracy, guess, leftLimit, rightLimit); } // end if phi<0 else break; default: Utils.QL_FAIL("invalid delta type"); break; } return(res); }