//------------------------------------------------------------------------- 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); }