All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.pricer.capfloor.VolatilityOvernightInArrearsCapletFloorletPeriodPricer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2022 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.pricer.capfloor;

import java.time.LocalDate;
import java.time.ZoneOffset;

import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.ZeroRateSensitivity;
import com.opengamma.strata.pricer.impl.rate.ForwardOvernightCompoundedRateComputationFn;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.product.capfloor.OvernightInArrearsCapletFloorletPeriod;
import com.opengamma.strata.product.common.PutCall;
import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation;

/**
 * Pricer for overnight in-arrears caplet/floorlet based on volatilities.
 * 

* The pricing methodologies are defined in individual implementations of the volatilities, {@code IborCapletFloorletVolatilities}. *

* The volatilities are stored in {@code IborCapletFloorletVolatilities}, it should be understood as "TermRateCapletFloorletVolatilities". *

* The pricing is based on "interpolated volatilities" for the compounded in-arrears rates, * in particular Section 6.3 of the reference below. * Reference: A. Lyashenko and F. Mercurio. Looking forward to backward-looking rates: A modeling frame- * work for term rates replacing LIBOR. SSRN Working Paper 3330240, March 2019. */ public class VolatilityOvernightInArrearsCapletFloorletPeriodPricer { /** * Default implementation. */ public static final VolatilityOvernightInArrearsCapletFloorletPeriodPricer DEFAULT = new VolatilityOvernightInArrearsCapletFloorletPeriodPricer(); /** * The function to compute overnight rates, including if necessary the past composition from time series. */ private static final ForwardOvernightCompoundedRateComputationFn ON_FUNCT = ForwardOvernightCompoundedRateComputationFn.DEFAULT; //------------------------------------------------------------------------- /** * Calculates the present value of the overnight in-arrears caplet/floorlet period. *

* The result is expressed using the currency of the period. * * @param period the caplet/floorlet period * @param ratesProvider the rates provider * @param volatilities the volatilities * @return the present value */ public CurrencyAmount presentValue( OvernightInArrearsCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { Currency currency = period.getCurrency(); if (ratesProvider.getValuationDate().isAfter(period.getPaymentDate())) { return CurrencyAmount.of(currency, 0d); } OvernightCompoundedRateComputation onComputation = period.getOvernightRate(); LocalDate startDate = onComputation.getStartDate(); LocalDate endDate = onComputation.getEndDate(); double startTime = volatilities.relativeTime(startDate.atStartOfDay(ZoneOffset.UTC)); // ON rates don't have an exact fixing time double endTime = volatilities.relativeTime(endDate.atStartOfDay(ZoneOffset.UTC)); double df = ratesProvider.discountFactor(currency, period.getPaymentDate()); PutCall putCall = period.getPutCall(); double strike = period.getStrike(); double forward = ON_FUNCT .rate(onComputation, onComputation.getStartDate(), onComputation.getEndDate(), ratesProvider); if (!ratesProvider.getValuationDate().isBefore(period.getEndDate())) { // Between end compounding and payment date double dfPayment = ratesProvider.discountFactor(currency, period.getPaymentDate()); return period.payoff(forward).multipliedBy(dfPayment); } double volatility = volatilities.volatility(endTime, strike, forward); double adjustedVolatility = adjustedVolatility(startTime, endTime, volatility); double price = df * period.getYearFraction() * volatilities.price(endTime, putCall, strike, forward, adjustedVolatility); return CurrencyAmount.of(currency, price * period.getNotional()); } /** * Computes the present value sensitivity to the rate with a volatility "sticky strike". * * @param period the caplet/floorlet period * @param ratesProvider the rates provider * @param volatilities the volatilities * @return the present value rate sensitivity */ public PointSensitivityBuilder presentValueSensitivityRatesStickyStrike( OvernightInArrearsCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { Currency currency = period.getCurrency(); if (ratesProvider.getValuationDate().isAfter(period.getPaymentDate())) { return PointSensitivityBuilder.none(); } OvernightCompoundedRateComputation onComputation = period.getOvernightRate(); LocalDate startDate = onComputation.getStartDate(); LocalDate endDate = onComputation.getEndDate(); double startTime = volatilities.relativeTime(startDate.atStartOfDay(ZoneOffset.UTC)); // ON rates don't have an exact fixing time double endTime = volatilities.relativeTime(endDate.atStartOfDay(ZoneOffset.UTC)); double dfPayment = ratesProvider.discountFactor(currency, period.getPaymentDate()); PutCall putCall = period.getPutCall(); double strike = period.getStrike(); double forward = ON_FUNCT .rate(onComputation, onComputation.getStartDate(), onComputation.getEndDate(), ratesProvider); if (!ratesProvider.getValuationDate().isBefore(period.getEndDate())) { // Between end compounding and payment date double pvForward = period.payoff(forward).getAmount(); // Backward sweep double dfPaymentBar = pvForward; ZeroRateSensitivity ddfPaymentdr = ratesProvider .discountFactors(currency).zeroRatePointSensitivity(period.getPaymentDate()); return ddfPaymentdr.multipliedBy(dfPaymentBar); } double volatility = volatilities.volatility(endTime, strike, forward); double adjustedVolatility = adjustedVolatility(startTime, endTime, volatility); double price = volatilities.price(endTime, putCall, strike, forward, adjustedVolatility); double pv = dfPayment * period.getYearFraction() * price * period.getNotional(); // Backward sweep double pvBar = 1.0; double priceBar = dfPayment * period.getYearFraction() * period.getNotional() * pvBar; double dfPaymentBar = pv / dfPayment * pvBar; double priceDelta = volatilities.priceDelta(endTime, putCall, strike, forward, adjustedVolatility); double forwardBar = priceDelta * priceBar; PointSensitivityBuilder dforwarddr = ON_FUNCT .rateSensitivity(onComputation, onComputation.getStartDate(), onComputation.getEndDate(), ratesProvider); ZeroRateSensitivity ddfPaymentdr = ratesProvider .discountFactors(currency).zeroRatePointSensitivity(period.getPaymentDate()); return ddfPaymentdr.multipliedBy(dfPaymentBar).combinedWith(dforwarddr.multipliedBy(forwardBar)); } /** * Computes the present value sensitivity to the volatilities. * * @param period the caplet/floorlet period * @param ratesProvider the rates provider * @param volatilities the volatilities * @return the present value volatility sensitivity */ public PointSensitivityBuilder presentValueSensitivityModelParamsVolatility( OvernightInArrearsCapletFloorletPeriod period, RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { Currency currency = period.getCurrency(); if (!ratesProvider.getValuationDate().isBefore(period.getEndDate())) { return PointSensitivityBuilder.none(); } OvernightCompoundedRateComputation onComputation = period.getOvernightRate(); LocalDate startDate = onComputation.getStartDate(); LocalDate endDate = onComputation.getEndDate(); double startTime = volatilities.relativeTime(startDate.atStartOfDay(ZoneOffset.UTC)); // ON rates don't have an exact fixing time double endTime = volatilities.relativeTime(endDate.atStartOfDay(ZoneOffset.UTC)); double df = ratesProvider.discountFactor(currency, period.getPaymentDate()); PutCall putCall = period.getPutCall(); double strike = period.getStrike(); double forward = ON_FUNCT .rate(onComputation, onComputation.getStartDate(), onComputation.getEndDate(), ratesProvider); double volatility = volatilities.volatility(endTime, strike, forward); double adjustedVolatility = adjustedVolatility(startTime, endTime, volatility); double price = volatilities.price(endTime, putCall, strike, forward, adjustedVolatility); double pv = df * period.getYearFraction() * price * period.getNotional(); // Backward sweep double pvBar = 1.0; double priceBar = pv / price * pvBar; double priceVega = volatilities.priceVega(endTime, putCall, strike, forward, adjustedVolatility); double adjustedVolatilityBar = priceVega * priceBar; double volatilityBar = adjustedVolatility / volatility * adjustedVolatilityBar; return IborCapletFloorletSensitivity.of( volatilities.getName(), endTime, strike, forward, currency, volatilityBar); } /** * Volatility adjusted for the decrease of forward rate volatility in the composition period. * * @param startTime the start time * @param endTime the end time * @param volatility the volatility * @return the adjusted volatility */ public double adjustedVolatility(double startTime, double endTime, double volatility) { if (startTime > 0) { return volatility * Math.sqrt(1.0 / 3.0 + 2.0d / 3.0d * startTime / endTime); } return volatility * endTime / (endTime - startTime) / Math.sqrt(3.0d); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy