/** * Create an analytic swaption approximation product for log normal forward rate model. * * <p>Note: It is implicitly assumed that swapTenor.getTime(0) is the exercise date (no forward * starting). * * @param swaprate The strike swap rate of the swaption. * @param swapTenor The swap tenor in doubles. */ public SwaptionAnalyticApproximation(double swaprate, TimeDiscretizationInterface swapTenor) { this(swaprate, swapTenor.getAsDoubleArray(), ValueUnit.VALUE); }
/** * This function calculate the partial derivative <i>d log(S) / d log(L<sub>k</sub>)</i> for a * given swap rate with respect to a vector of forward rates (on a given forward rate tenor). * * <p>It also returns some useful other quantities like the corresponding discout factors and swap * annuities. * * @param liborPeriodDiscretization The libor period discretization. * @param discountCurveInterface The discount curve. If this parameter is null, the discount curve * will be calculated from the forward curve. * @param forwardCurveInterface The forward curve. * @return A map containing the partial derivatives (key "value"), the discount factors (key * "discountFactors") and the annuities (key "annuities") as vectors of double[] (indexed by * forward rate tenor index starting at swap start) */ public Map<String, double[]> getLogSwaprateDerivative( TimeDiscretizationInterface liborPeriodDiscretization, DiscountCurveInterface discountCurveInterface, ForwardCurveInterface forwardCurveInterface) { /* * We cache the calculation of the log swaprate derivative. In a calibration this method might be called quite often with the same arguments. */ synchronized (cachedLogSwaprateDerivativeLock) { if (cachedLogSwaprateDerivative != null && liborPeriodDiscretization == cachedLogSwaprateDerivativeTimeDiscretization.get() && discountCurveInterface == cachedLogSwaprateDerivativeDiscountCurve.get() && forwardCurveInterface == cachedLogSwaprateDerivativeForwardCurve.get()) { return cachedLogSwaprateDerivative; } cachedLogSwaprateDerivativeTimeDiscretization = new WeakReference<TimeDiscretizationInterface>(liborPeriodDiscretization); cachedLogSwaprateDerivativeDiscountCurve = new WeakReference<DiscountCurveInterface>(discountCurveInterface); cachedLogSwaprateDerivativeForwardCurve = new WeakReference<ForwardCurveInterface>(forwardCurveInterface); /* * Small workaround for the case that the discount curve is not set. This part will be removed later. */ AnalyticModel model = null; if (discountCurveInterface == null) { discountCurveInterface = new DiscountCurveFromForwardCurve(forwardCurveInterface.getName()); model = new AnalyticModel(new CurveInterface[] {forwardCurveInterface, discountCurveInterface}); } double swapStart = swapTenor[0]; double swapEnd = swapTenor[swapTenor.length - 1]; // Get the indices of the swap start and end on the forward rate tenor int swapStartIndex = liborPeriodDiscretization.getTimeIndex(swapStart); int swapEndIndex = liborPeriodDiscretization.getTimeIndex(swapEnd); // Precalculate forward rates and discount factors. Note: the swap contains // swapEndIndex-swapStartIndex forward rates double[] forwardRates = new double[swapEndIndex - swapStartIndex + 1]; double[] discountFactors = new double[swapEndIndex - swapStartIndex + 1]; // Calculate discount factor at swap start discountFactors[0] = discountCurveInterface.getDiscountFactor(model, swapStart); // Calculate discount factors for swap period ends (used for swap annuity) for (int liborPeriodIndex = swapStartIndex; liborPeriodIndex < swapEndIndex; liborPeriodIndex++) { double libor = forwardCurveInterface.getForward( null, liborPeriodDiscretization.getTime(liborPeriodIndex)); forwardRates[liborPeriodIndex - swapStartIndex] = libor; discountFactors[liborPeriodIndex - swapStartIndex + 1] = discountCurveInterface.getDiscountFactor( model, liborPeriodDiscretization.getTime(liborPeriodIndex + 1)); } // Precalculate swap annuities double[] swapAnnuities = new double[swapTenor.length - 1]; double swapAnnuity = 0.0; for (int swapPeriodIndex = swapTenor.length - 2; swapPeriodIndex >= 0; swapPeriodIndex--) { int periodEndIndex = liborPeriodDiscretization.getTimeIndex(swapTenor[swapPeriodIndex + 1]); swapAnnuity += discountFactors[periodEndIndex - swapStartIndex] * (swapTenor[swapPeriodIndex + 1] - swapTenor[swapPeriodIndex]); swapAnnuities[swapPeriodIndex] = swapAnnuity; } // Precalculate weights: The formula is take from ISBN 0470047224 double[] swapCovarianceWeights = new double[swapEndIndex - swapStartIndex]; double valueFloatLeg = 0.0; for (int liborPeriodIndex = swapStartIndex; liborPeriodIndex < swapEndIndex; liborPeriodIndex++) { double liborPeriodLength = liborPeriodDiscretization.getTimeStep(liborPeriodIndex); valueFloatLeg += forwardRates[liborPeriodIndex - swapStartIndex] * discountFactors[liborPeriodIndex - swapStartIndex + 1] * liborPeriodLength; } int swapPeriodIndex = 0; double valueFloatLegUpToSwapStart = 0.0; for (int liborPeriodIndex = swapStartIndex; liborPeriodIndex < swapEndIndex; liborPeriodIndex++) { if (liborPeriodDiscretization.getTime(liborPeriodIndex) >= swapTenor[swapPeriodIndex + 1]) swapPeriodIndex++; double libor = forwardRates[liborPeriodIndex - swapStartIndex]; double liborPeriodLength = liborPeriodDiscretization.getTimeStep(liborPeriodIndex); valueFloatLegUpToSwapStart += forwardRates[liborPeriodIndex - swapStartIndex] * discountFactors[liborPeriodIndex - swapStartIndex + 1] * liborPeriodLength; double discountFactorAtPeriodEnd = discountCurveInterface.getDiscountFactor( model, liborPeriodDiscretization.getTime(liborPeriodIndex + 1)); double derivativeFloatLeg = (discountFactorAtPeriodEnd + valueFloatLegUpToSwapStart - valueFloatLeg) * liborPeriodLength / (1.0 + libor * liborPeriodLength) / valueFloatLeg; double derivativeFixLeg = -swapAnnuities[swapPeriodIndex] / swapAnnuity * liborPeriodLength / (1.0 + libor * liborPeriodLength); swapCovarianceWeights[liborPeriodIndex - swapStartIndex] = (derivativeFloatLeg - derivativeFixLeg) * libor; } // Return results Map<String, double[]> results = new HashMap<String, double[]>(); results.put("values", swapCovarianceWeights); results.put("discountFactors", discountFactors); results.put("swapAnnuities", swapAnnuities); cachedLogSwaprateDerivative = results; return results; } }