//------------------------------------------------------------------------- public override NodalCurve calibrate(IList <ResolvedCdsTrade> calibrationCDSs, DoubleArray premiums, DoubleArray pointsUpfront, CurveName name, LocalDate valuationDate, CreditDiscountFactors discountFactors, RecoveryRates recoveryRates, ReferenceData refData) { int n = calibrationCDSs.Count; double[] guess = new double[n]; double[] t = new double[n]; double[] lgd = new double[n]; for (int i = 0; i < n; i++) { LocalDate endDate = calibrationCDSs[i].Product.ProtectionEndDate; t[i] = discountFactors.relativeYearFraction(endDate); lgd[i] = 1d - recoveryRates.recoveryRate(endDate); guess[i] = (premiums.get(i) + pointsUpfront.get(i) / t[i]) / lgd[i]; } DoubleArray times = DoubleArray.ofUnsafe(t); CurveMetadata baseMetadata = DefaultCurveMetadata.builder().xValueType(ValueType.YEAR_FRACTION).yValueType(ValueType.ZERO_RATE).curveName(name).dayCount(discountFactors.DayCount).build(); NodalCurve creditCurve = n == 1 ? ConstantNodalCurve.of(baseMetadata, t[0], guess[0]) : InterpolatedNodalCurve.of(baseMetadata, times, DoubleArray.ofUnsafe(guess), CurveInterpolators.PRODUCT_LINEAR, CurveExtrapolators.FLAT, CurveExtrapolators.PRODUCT_LINEAR); for (int i = 0; i < n; i++) { System.Func <double, double> func = getPriceFunction(i, calibrationCDSs[i], premiums.get(i), pointsUpfront.get(i), valuationDate, creditCurve, discountFactors, recoveryRates, refData); double[] bracket = BRACKER.getBracketedPoints(func, 0.8 * guess[i], 1.25 * guess[i], 0.0, double.PositiveInfinity); double zeroRate = bracket[0] > bracket[1] ? ROOTFINDER.getRoot(func, bracket[1], bracket[0]) : ROOTFINDER.getRoot(func, bracket[0], bracket[1]); //Negative guess handled creditCurve = creditCurve.withParameter(i, zeroRate); } return(creditCurve); }
//------------------------------------------------------------------------- private double[] computesFittingParameters() { double[] param = new double[3]; // Implementation note: called a,b,c in the note. // Computes derivatives at cut-off. double[] vD = new double[6]; //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] vD2 = new double[2][2]; double[][] vD2 = RectangularArrays.ReturnRectangularDoubleArray(2, 2); volatilityK = sabrFunction.volatilityAdjoint2(forward, cutOffStrike, timeToExpiry, sabrData, vD, vD2); Pair <ValueDerivatives, double[][]> pa2 = BlackFormulaRepository.priceAdjoint2(forward, cutOffStrike, timeToExpiry, volatilityK, true); double[] bsD = pa2.First.Derivatives.toArrayUnsafe(); double[][] bsD2 = pa2.Second; priceK[0] = pa2.First.Value; priceK[1] = bsD[1] + bsD[3] * vD[1]; priceK[2] = bsD2[1][1] + bsD2[1][2] * vD[1] + (bsD2[2][1] + bsD2[2][2] * vD[1]) * vD[1] + bsD[3] * vD2[1][1]; if (Math.Abs(priceK[0]) < SMALL_PRICE && Math.Abs(priceK[1]) < SMALL_PRICE && Math.Abs(priceK[2]) < SMALL_PRICE) { // Implementation note: If value and its derivatives is too small, then parameters are such that the extrapolated price is "very small". return(new double[] { -100.0, 0, 0 }); } System.Func <double, double> toSolveC = getCFunction(priceK, cutOffStrike, mu); BracketRoot bracketer = new BracketRoot(); double accuracy = 1.0E-5; RidderSingleRootFinder rootFinder = new RidderSingleRootFinder(accuracy); double[] range = bracketer.getBracketedPoints(toSolveC, -1.0, 1.0); param[2] = rootFinder.getRoot(toSolveC, range[0], range[1]).Value; param[1] = -2 * param[2] / cutOffStrike - (priceK[1] / priceK[0] * cutOffStrike + mu) * cutOffStrike; param[0] = Math.Log(priceK[0] / Math.Pow(cutOffStrike, -mu)) - param[1] / cutOffStrike - param[2] / (cutOffStrike * cutOffStrike); return(param); }
public YieldTermStructure fitSwap(int curveIndex, BasicFixedLeg swap, YieldTermStructure curve, double swapRate) { int nPayments = swap._nPayments; int nNodes = curve.nJumps_; double t1 = curveIndex == 0 ? 0.0 : curve.t[curveIndex - 1]; double t2 = curveIndex == nNodes - 1 ? double.PositiveInfinity : curve.t[curveIndex + 1]; double temp = 0; double temp2 = 0; int i1 = 0; int i2 = nPayments; double[] paymentAmounts = new double[nPayments]; for (int i = 0; i < nPayments; i++) { double t = swap.getPaymentTime(i); paymentAmounts[i] = swap.getPaymentAmounts(i, swapRate); if (t <= t1) { double df = Math.Exp(-curve.getRT_(t)); temp += paymentAmounts[i] * df; temp2 -= paymentAmounts[i] * curve.getSingleNodeDiscountFactorSensitivity(t, curveIndex); i1++; } else if (t >= t2) { double df = Math.Exp(-curve.getRT_(t)); temp += paymentAmounts[i] * df; temp2 += paymentAmounts[i] * curve.getSingleNodeDiscountFactorSensitivity(t, curveIndex); i2--; } } double cachedValues = temp; double cachedSense = temp2; int index1 = i1; int index2 = i2; BracketRoot BRACKETER = new BracketRoot(); NewtonRaphsonSingleRootFinder ROOTFINDER = new NewtonRaphsonSingleRootFinder(); Func <double, double> func = x => apply_(x, curve, curveIndex, cachedValues, index1, index2, swap, paymentAmounts); Func <double, double> grad = x => apply_sen(x, curve, curveIndex, cachedSense, index1, index2, swap, swapRate); double guess = curve.getZeroRateAtIndex(curveIndex); if (guess == 0.0 && func(guess) == 0.0) { return(curve); } double[] bracket = BRACKETER.getBracketedPoints(func, 0.8 * guess, 1.25 * guess, 0, double.PositiveInfinity); double r = ROOTFINDER.getRoot(func, grad, bracket[0], bracket[1]); return(curve.withRate(r, curveIndex)); }
//------------------------------------------------------------------------- private double[] bracketRoot(double optionPrice, double sigma) { BracketRoot bracketer = new BracketRoot(); System.Func <double, double> func = (double?volatility) => { return(priceFunc.apply(volatility) / optionPrice - 1.0); }; return(bracketer.getBracketedPoints(func, Math.Max(0.0, sigma - BRACKET_STEP), sigma + BRACKET_STEP, 0d, double.PositiveInfinity)); }
//------------------------------------------------------------------------- /// <summary> /// Computes the implied volatility. /// <para> /// If the volatility data is not zero, it is used as a starting point for the volatility search. /// </para> /// <para> /// Note that the 'numeraire' is a simple multiplier and is the responsibility of the caller. /// /// </para> /// </summary> /// <param name="optionPrice"> the price of the option </param> /// <param name="forward"> the forward value of the underlying </param> /// <param name="strike"> the strike </param> /// <param name="timeToExpiry"> the time to expiry </param> /// <param name="initialNormalVol"> the normal volatility used to start the search </param> /// <param name="numeraire"> the numeraire </param> /// <param name="putCall"> whether it is put or call </param> /// <returns> the implied volatility </returns> public static double impliedVolatility(double optionPrice, double forward, double strike, double timeToExpiry, double initialNormalVol, double numeraire, PutCall putCall) { double intrinsicPrice = numeraire * Math.Max(0, (putCall.Call ? 1 : -1) * (forward - strike)); ArgChecker.isTrue(optionPrice > intrinsicPrice || DoubleMath.fuzzyEquals(optionPrice, intrinsicPrice, 1e-6), "Option price (" + optionPrice + ") less than intrinsic value (" + intrinsicPrice + ")"); if (System.BitConverter.DoubleToInt64Bits(optionPrice) == Double.doubleToLongBits(intrinsicPrice)) { return(0d); } double sigma = (Math.Abs(initialNormalVol) < 1e-10 ? 0.3 * forward : initialNormalVol); double maxChange = 0.5 * forward; ValueDerivatives price = priceAdjoint(forward, strike, timeToExpiry, sigma, numeraire, putCall); double vega = price.getDerivative(1); double change = (price.Value - optionPrice) / vega; double sign = Math.Sign(change); change = sign * Math.Min(maxChange, Math.Abs(change)); if (change > 0 && change > sigma) { change = sigma; } int count = 0; while (Math.Abs(change) > EPS) { sigma -= change; price = priceAdjoint(forward, strike, timeToExpiry, sigma, numeraire, putCall); vega = price.getDerivative(1); change = (price.Value - optionPrice) / vega; sign = Math.Sign(change); change = sign * Math.Min(maxChange, Math.Abs(change)); if (change > 0 && change > sigma) { change = sigma; } if (count++ > MAX_ITERATIONS) { BracketRoot bracketer = new BracketRoot(); BisectionSingleRootFinder rootFinder = new BisectionSingleRootFinder(EPS); System.Func <double, double> func = (double?volatility) => { return(numeraire * NormalFormulaRepository.price(forward, strike, timeToExpiry, volatility.Value, putCall) - optionPrice); }; double[] range = bracketer.getBracketedPoints(func, 0d, 10d); return(rootFinder.getRoot(func, range[0], range[1]).Value); } } return(sigma); }
/// <summary> /// Calculates the common part of the exercise boundary of European swaptions forward. /// <para> /// This is intended to be used in particular for Bermudan swaption first step of the pricing. /// </para> /// <para> /// Reference: Henrard, "M. Bermudan Swaptions in Gaussian HJM One-Factor Model: Analytical and Numerical Approaches". /// SSRN, October 2008. Available at SSRN: http://ssrn.com/abstract=1287982 /// /// </para> /// </summary> /// <param name="discountedCashFlow"> the swap discounted cash flows </param> /// <param name="alpha2"> square of the alpha parameter </param> /// <param name="hwH"> the H factors </param> /// <returns> the exercise boundary </returns> public double lambda(DoubleArray discountedCashFlow, DoubleArray alpha2, DoubleArray hwH) { //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: final java.util.function.Function<double, double> swapValue = new java.util.function.Function<double, double>() System.Func <double, double> swapValue = (double?x) => { double value = 0.0; for (int loopcf = 0; loopcf < alpha2.size(); loopcf++) { value += discountedCashFlow.get(loopcf) * Math.Exp(-0.5 * alpha2.get(loopcf) - hwH.get(loopcf) * x); } return(value); }; BracketRoot bracketer = new BracketRoot(); double accuracy = 1.0E-8; RidderSingleRootFinder rootFinder = new RidderSingleRootFinder(accuracy); double[] range = bracketer.getBracketedPoints(swapValue, -2.0, 2.0); return(rootFinder.getRoot(swapValue, range[0], range[1]).Value); }
//------------------------------------------------------------------------- private InterpolatedNodalCurve fitSwap(int curveIndex, BasicFixedLeg swap, InterpolatedNodalCurve curve, double swapRate) { int nPayments = swap.NumPayments; int nNodes = curve.ParameterCount; double t1 = curveIndex == 0 ? 0.0 : curve.XValues.get(curveIndex - 1); double t2 = curveIndex == nNodes - 1 ? double.PositiveInfinity : curve.XValues.get(curveIndex + 1); double temp = 0; double temp2 = 0; int i1 = 0; int i2 = nPayments; double[] paymentAmounts = new double[nPayments]; for (int i = 0; i < nPayments; i++) { double t = swap.getPaymentTime(i); paymentAmounts[i] = swap.getPaymentAmounts(i, swapRate); if (t <= t1) { double df = Math.Exp(-curve.yValue(t) * t); temp += paymentAmounts[i] * df; temp2 += paymentAmounts[i] * t *df *curve.yValueParameterSensitivity(t).Sensitivity.get(curveIndex); i1++; } else if (t >= t2) { double df = Math.Exp(-curve.yValue(t) * t); temp += paymentAmounts[i] * df; temp2 -= paymentAmounts[i] * t *df *curve.yValueParameterSensitivity(t).Sensitivity.get(curveIndex); i2--; } } double cachedValues = temp; double cachedSense = temp2; int index1 = i1; int index2 = i2; //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: java.util.function.Function<double, double> func = new java.util.function.Function<double, double>() System.Func <double, double> func = (double?x) => { InterpolatedNodalCurve tempCurve = curve.withParameter(curveIndex, x); double sum = 1.0 - cachedValues; // Floating leg at par for (int i = index1; i < index2; i++) { double t = swap.getPaymentTime(i); sum -= paymentAmounts[i] * Math.Exp(-tempCurve.yValue(t) * t); } return(sum); }; //JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final': //ORIGINAL LINE: java.util.function.Function<double, double> grad = new java.util.function.Function<double, double>() System.Func <double, double> grad = (double?x) => { InterpolatedNodalCurve tempCurve = curve.withParameter(curveIndex, x); double sum = cachedSense; for (int i = index1; i < index2; i++) { double t = swap.getPaymentTime(i); sum += swap.getPaymentAmounts(i, swapRate) * t * Math.Exp(-tempCurve.yValue(t) * t) * tempCurve.yValueParameterSensitivity(t).Sensitivity.get(curveIndex); } return(sum); }; double guess = curve.getParameter(curveIndex); if (guess == 0.0 && func(guess) == 0.0) { return(curve); } double[] bracket = guess > 0d ? BRACKETER.getBracketedPoints(func, 0.8 * guess, 1.25 * guess, double.NegativeInfinity, double.PositiveInfinity) : BRACKETER.getBracketedPoints(func, 1.25 * guess, 0.8 * guess, double.NegativeInfinity, double.PositiveInfinity); double r = rootFinder.getRoot(func, grad, bracket[0], bracket[1]).Value; return(curve.withParameter(curveIndex, r)); }