/** * 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 static com.opengamma.strata.market.ValueType.BLACK_VOLATILITY; import static com.opengamma.strata.market.ValueType.NORMAL_VOLATILITY; import static com.opengamma.strata.market.ValueType.STRIKE; import java.time.LocalDate; import java.time.ZonedDateTime; import java.util.List; import java.util.function.Function; import com.opengamma.strata.basics.ReferenceData; import com.opengamma.strata.basics.index.IborIndex; import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.market.surface.ConstantSurface; import com.opengamma.strata.market.surface.Surface; import com.opengamma.strata.market.surface.SurfaceMetadata; import com.opengamma.strata.pricer.option.RawOptionData; import com.opengamma.strata.pricer.rate.RatesProvider; import com.opengamma.strata.product.capfloor.ResolvedIborCapFloorLeg; /** * Caplet volatilities calibration to cap volatilities. */ abstract class IborCapletFloorletVolatilityCalibrator { /** * The cap/floor pricer. * <p> * This pricer is used for converting market cap volatilities to cap prices. */ private final VolatilityIborCapFloorLegPricer pricer; /** * The reference data. */ private final ReferenceData referenceData; /** * Constructor with cap pricer and reference data. * * @param pricer the cap pricer * @param referenceData the reference data */ public IborCapletFloorletVolatilityCalibrator(VolatilityIborCapFloorLegPricer pricer, ReferenceData referenceData) { this.pricer = ArgChecker.notNull(pricer, "pricer"); this.referenceData = ArgChecker.notNull(referenceData, "referenceData"); } /** * Calibrates caplet volatilities to cap volatilities. * * @param definition the caplet volatility definition * @param calibrationDateTime the calibration time * @param capFloorData the cap data * @param ratesProvider the rates provider * @return the calibration result */ public abstract IborCapletFloorletVolatilityCalibrationResult calibrate( IborCapletFloorletVolatilityDefinition definition, ZonedDateTime calibrationDateTime, RawOptionData capFloorData, RatesProvider ratesProvider); //------------------------------------------------------------------------- /** * Gets the reference data. * * @return the reference data */ protected ReferenceData getReferenceData() { return referenceData; } /** * Gets the leg pricer. * * @return the leg pricer */ protected VolatilityIborCapFloorLegPricer getLegPricer() { return pricer; } //------------------------------------------------------------------------- // create complete lists of caps, volatilities, strikes, expiries protected void reduceRawData( IborCapletFloorletVolatilityDefinition definition, RatesProvider ratesProvider, DoubleArray strikes, DoubleArray volatilityData, DoubleArray errors, LocalDate startDate, LocalDate endDate, SurfaceMetadata metadata, Function<Surface, IborCapletFloorletVolatilities> volatilityFunction, List<Double> timeList, List<Double> strikeList, List<Double> volList, List<ResolvedIborCapFloorLeg> capList, List<Double> priceList, List<Double> errorList) { int nStrikes = strikes.size(); for (int i = 0; i < nStrikes; ++i) { if (Double.isFinite(volatilityData.get(i))) { ResolvedIborCapFloorLeg capFloor = definition.createCap(startDate, endDate, strikes.get(i)).resolve(referenceData); capList.add(capFloor); strikeList.add(strikes.get(i)); volList.add(volatilityData.get(i)); ConstantSurface constVolSurface = ConstantSurface.of(metadata, volatilityData.get(i)); IborCapletFloorletVolatilities vols = volatilityFunction.apply(constVolSurface); timeList.add(vols.relativeTime(capFloor.getFinalFixingDateTime())); priceList.add(pricer.presentValue(capFloor, ratesProvider, vols).getAmount()); errorList.add(errors.get(i)); } } } // function creating volatilities object from surface protected Function<Surface, IborCapletFloorletVolatilities> volatilitiesFunction( IborCapletFloorletVolatilityDefinition definition, ZonedDateTime calibrationDateTime, RawOptionData capFloorData) { IborIndex index = definition.getIndex(); if (capFloorData.getStrikeType().equals(STRIKE)) { if (capFloorData.getDataType().equals(BLACK_VOLATILITY)) { return blackVolatilitiesFunction(index, calibrationDateTime); } else if (capFloorData.getDataType().equals(NORMAL_VOLATILITY)) { return normalVolatilitiesFunction(index, calibrationDateTime); } throw new IllegalArgumentException("Data type not supported"); } throw new IllegalArgumentException("strike type must be ValueType.STRIKE"); } private Function<Surface, IborCapletFloorletVolatilities> blackVolatilitiesFunction( IborIndex index, ZonedDateTime calibrationDateTime) { Function<Surface, IborCapletFloorletVolatilities> func = new Function<Surface, IborCapletFloorletVolatilities>() { @Override public IborCapletFloorletVolatilities apply(Surface s) { return BlackIborCapletFloorletExpiryStrikeVolatilities.of(index, calibrationDateTime, s); } }; return func; } private Function<Surface, IborCapletFloorletVolatilities> normalVolatilitiesFunction( IborIndex index, ZonedDateTime calibrationDateTime) { Function<Surface, IborCapletFloorletVolatilities> func = new Function<Surface, IborCapletFloorletVolatilities>() { @Override public IborCapletFloorletVolatilities apply(Surface s) { return NormalIborCapletFloorletExpiryStrikeVolatilities.of(index, calibrationDateTime, s); } }; return func; } }