com.opengamma.strata.pricer.capfloor.VolatilityIborCapFloorLegPricer Maven / Gradle / Ivy
/*
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.capfloor;
import java.util.Map;
import com.google.common.collect.ImmutableMap;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.MapStream;
import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.product.capfloor.IborCapFloorLeg;
import com.opengamma.strata.product.capfloor.IborCapletFloorletPeriod;
import com.opengamma.strata.product.capfloor.ResolvedIborCapFloorLeg;
/**
* Pricer for cap/floor legs based on volatilities.
*
* This function provides the ability to price {@link ResolvedIborCapFloorLeg}.
* One must apply {@code expand()} in order to price {@link IborCapFloorLeg}.
*
* The pricing methodologies are defined in individual implementations of the
* volatilities, {@link IborCapletFloorletVolatilities}.
*/
public class VolatilityIborCapFloorLegPricer {
/**
* Default implementation.
*/
public static final VolatilityIborCapFloorLegPricer DEFAULT =
new VolatilityIborCapFloorLegPricer(VolatilityIborCapletFloorletPeriodPricer.DEFAULT);
/**
* Pricer for {@link IborCapletFloorletPeriod}.
*/
private final VolatilityIborCapletFloorletPeriodPricer periodPricer;
/**
* Creates an instance.
*
* @param periodPricer the pricer for {@link IborCapletFloorletPeriod}.
*/
public VolatilityIborCapFloorLegPricer(VolatilityIborCapletFloorletPeriodPricer periodPricer) {
this.periodPricer = ArgChecker.notNull(periodPricer, "periodPricer");
}
//-------------------------------------------------------------------------
/**
* Obtains the underlying period pricer.
*
* @return the period pricer
*/
public VolatilityIborCapletFloorletPeriodPricer getPeriodPricer() {
return periodPricer;
}
//-------------------------------------------------------------------------
/**
* Calculates the present value of the Ibor cap/floor leg.
*
* The present value of the leg is the value on the valuation date.
* The result is returned using the payment currency of the leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the present value
*/
public CurrencyAmount presentValue(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
return capFloorLeg.getCapletFloorletPeriods()
.stream()
.map(period -> periodPricer.presentValue(period, ratesProvider, volatilities))
.reduce((c1, c2) -> c1.plus(c2))
.get();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value for each caplet/floorlet of the Ibor cap/floor leg.
*
* The present value of each caplet/floorlet is the value on the valuation date.
* The result is returned using the payment currency of the leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the present values
*/
public IborCapletFloorletPeriodCurrencyAmounts presentValueCapletFloorletPeriods(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
Map periodPresentValues =
MapStream.of(capFloorLeg.getCapletFloorletPeriods())
.mapValues(period -> periodPricer.presentValue(period, ratesProvider, volatilities))
.toMap();
return IborCapletFloorletPeriodCurrencyAmounts.of(periodPresentValues);
}
//-------------------------------------------------------------------------
/**
* Calculates the present value delta of the Ibor cap/floor leg.
*
* The present value delta of the leg is the sensitivity value on the valuation date.
* The result is returned using the payment currency of the leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the present value delta
*/
public CurrencyAmount presentValueDelta(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
return capFloorLeg.getCapletFloorletPeriods()
.stream()
.map(period -> periodPricer.presentValueDelta(period, ratesProvider, volatilities))
.reduce((c1, c2) -> c1.plus(c2))
.get();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value gamma of the Ibor cap/floor leg.
*
* The present value gamma of the leg is the sensitivity value on the valuation date.
* The result is returned using the payment currency of the leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the present value gamma
*/
public CurrencyAmount presentValueGamma(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
return capFloorLeg.getCapletFloorletPeriods()
.stream()
.map(period -> periodPricer.presentValueGamma(period, ratesProvider, volatilities))
.reduce((c1, c2) -> c1.plus(c2))
.get();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value theta of the Ibor cap/floor leg.
*
* The present value theta of the leg is the sensitivity value on the valuation date.
* The result is returned using the payment currency of the leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the present value theta
*/
public CurrencyAmount presentValueTheta(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
return capFloorLeg.getCapletFloorletPeriods()
.stream()
.map(period -> periodPricer.presentValueTheta(period, ratesProvider, volatilities))
.reduce((c1, c2) -> c1.plus(c2))
.get();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value rates sensitivity of the Ibor cap/floor leg.
*
* The present value rates sensitivity of the leg is the sensitivity
* of the present value to the underlying curves.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the present value curve sensitivity
*/
public PointSensitivityBuilder presentValueSensitivityRates(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
return capFloorLeg.getCapletFloorletPeriods()
.stream()
.map(period -> periodPricer.presentValueSensitivityRates(period, ratesProvider, volatilities))
.reduce((p1, p2) -> p1.combinedWith(p2))
.get();
}
//-------------------------------------------------------------------------
/**
* Calculates the present value volatility sensitivity of the Ibor cap/floor leg.
*
* The present value volatility sensitivity of the leg is the sensitivity
* of the present value to the volatility values.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the present value volatility sensitivity
*/
public PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
return capFloorLeg.getCapletFloorletPeriods()
.stream()
.map(period -> periodPricer.presentValueSensitivityModelParamsVolatility(period, ratesProvider, volatilities))
.reduce((c1, c2) -> c1.combinedWith(c2))
.get();
}
//-------------------------------------------------------------------------
/**
* Calculates the current cash of the Ibor cap/floor leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the current cash
*/
public CurrencyAmount currentCash(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
return capFloorLeg.getCapletFloorletPeriods()
.stream()
.filter(period -> period.getPaymentDate().equals(ratesProvider.getValuationDate()))
.map(period -> periodPricer.presentValue(period, ratesProvider, volatilities))
.reduce((c1, c2) -> c1.plus(c2))
.orElse(CurrencyAmount.zero(capFloorLeg.getCurrency()));
}
//-------------------------------------------------------------------------
/**
* Calculates the forward rates for each caplet/floorlet of the Ibor cap/floor leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @return the forward rates
*/
public IborCapletFloorletPeriodAmounts forwardRates(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider) {
Map forwardRates = MapStream.of(capFloorLeg.getCapletFloorletPeriods())
.filterKeys(period -> !ratesProvider.getValuationDate().isAfter(period.getFixingDate()))
.mapValues(period -> periodPricer.forwardRate(period, ratesProvider))
.toMap();
return IborCapletFloorletPeriodAmounts.of(forwardRates);
}
//-------------------------------------------------------------------------
/**
* Calculates the implied volatilities for each caplet/floorlet of the Ibor cap/floor leg.
*
* @param capFloorLeg the Ibor cap/floor leg
* @param ratesProvider the rates provider
* @param volatilities the volatilities
* @return the implied volatilities
*/
public IborCapletFloorletPeriodAmounts impliedVolatilities(
ResolvedIborCapFloorLeg capFloorLeg,
RatesProvider ratesProvider,
IborCapletFloorletVolatilities volatilities) {
validate(ratesProvider, volatilities);
ImmutableMap impliedVolatilities = MapStream.of(capFloorLeg.getCapletFloorletPeriods())
.filterKeys(period -> volatilities.relativeTime(period.getFixingDateTime()) >= 0)
.mapValues(period -> periodPricer.impliedVolatility(period, ratesProvider, volatilities))
.toMap();
return IborCapletFloorletPeriodAmounts.of(impliedVolatilities);
}
//-------------------------------------------------------------------------
protected void validate(RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) {
ArgChecker.isTrue(volatilities.getValuationDate().equals(ratesProvider.getValuationDate()),
"volatility and rate data must be for the same date");
}
}