Exemplo n.º 1
0
        //-------------------------------------------------------------------------
        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);
        }
Exemplo n.º 3
0
        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));
        }
Exemplo n.º 4
0
        //-------------------------------------------------------------------------
        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));
        }
Exemplo n.º 5
0
        //-------------------------------------------------------------------------
        /// <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));
        }