/** * Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.pricer.curve; import java.time.LocalDate; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.collect.ImmutableList; import com.opengamma.strata.basics.ReferenceData; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyPair; import com.opengamma.strata.basics.currency.FxRate; import com.opengamma.strata.basics.index.Index; import com.opengamma.strata.collect.Messages; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; import com.opengamma.strata.data.FxRateId; import com.opengamma.strata.data.ImmutableMarketData; import com.opengamma.strata.data.MarketData; import com.opengamma.strata.data.MarketDataId; import com.opengamma.strata.market.curve.CurveGroupDefinition; import com.opengamma.strata.market.curve.CurveGroupEntry; import com.opengamma.strata.market.curve.CurveNode; import com.opengamma.strata.market.curve.NodalCurveDefinition; import com.opengamma.strata.market.observable.IndexQuoteId; import com.opengamma.strata.pricer.rate.RatesProvider; import com.opengamma.strata.product.ResolvedTrade; /** * Synthetic curve calibrator. * <p> * A synthetic curve is a curve calibrated on synthetic instruments. * A synthetic instrument is an instrument for which a theoretical or synthetic quote * can be computed from a {@link RatesProvider}. * <p> * This curve transformation is often used to have a different risk view or to standardize * all risk to a common set of instruments, even if they are not the most liquid in a market. */ public final class SyntheticCurveCalibrator { /** * The standard synthetic curve calibrator. * <p> * This uses the standard {@link CurveCalibrator} and {@link CalibrationMeasures}. */ private static final SyntheticCurveCalibrator STANDARD = SyntheticCurveCalibrator.of( CurveCalibrator.standard(), CalibrationMeasures.MARKET_QUOTE); /** * The curve calibrator. */ private final CurveCalibrator calibrator; /** * The market-quotes measures used to produce the synthetic quotes. */ private final CalibrationMeasures measures; //------------------------------------------------------------------------- /** * The standard synthetic curve calibrator. * <p> * The {@link CalibrationMeasures#MARKET_QUOTE} measures are used for calibration. * The underlying calibrator is {@link CurveCalibrator#standard()}. * * @return the standard synthetic curve calibrator */ public static SyntheticCurveCalibrator standard() { return STANDARD; } /** * Obtains an instance, specifying market quotes measures to use and calibrator. * * @param calibrator the mechanism used to calibrate curves once the synthetic market quotes are known * @param marketQuotesMeasures the measures used to compute the market quotes * @return the synthetic curve calibrator */ public static SyntheticCurveCalibrator of(CurveCalibrator calibrator, CalibrationMeasures marketQuotesMeasures) { return new SyntheticCurveCalibrator(calibrator, marketQuotesMeasures); } // restricted constructor private SyntheticCurveCalibrator(CurveCalibrator calibrator, CalibrationMeasures marketQuotesMeasures) { this.measures = marketQuotesMeasures; this.calibrator = calibrator; } //------------------------------------------------------------------------- /** * Gets the market quote measures. * * @return the measures */ public CalibrationMeasures getMeasures() { return measures; } /** * Gets the curve calibrator. * * @return the calibrator */ public CurveCalibrator getCalibrator() { return calibrator; } //------------------------------------------------------------------------- /** * Calibrates synthetic curves from the configuration of the new curves and an existing rates provider. * * @param group the curve group definition for the synthetic curves and instruments * @param inputProvider the input rates provider * @param refData the reference data, used to resolve the trades * @return the rates provider */ public RatesProvider calibrate( CurveGroupDefinition group, RatesProvider inputProvider, ReferenceData refData) { // Computes the synthetic market quotes MarketData marketQuotesSy = marketData(group, inputProvider, refData); // Calibrate to the synthetic instrument with the synthetic quotes return calibrator.calibrate(group, marketQuotesSy, refData); } /** * Constructs the synthetic market data from an existing rates provider and the configuration of the new curves. * * @param group the curve group definition for the synthetic curves and instruments * @param inputProvider the input rates provider * @param refData the reference data, used to resolve the trades * @return the market data */ MarketData marketData( CurveGroupDefinition group, RatesProvider inputProvider, ReferenceData refData) { // Retrieve the set of required indices and the list of required currencies Set<Index> indicesRequired = new HashSet<Index>(); List<Currency> ccyRequired = new ArrayList<>(); for (CurveGroupEntry entry : group.getEntries()) { indicesRequired.addAll(entry.getIndices()); ccyRequired.addAll(entry.getDiscountCurrencies()); } // Retrieve the required time series if present in the original provider Map<IndexQuoteId, LocalDateDoubleTimeSeries> ts = new HashMap<>(); for (Index idx : indicesRequired) { ts.put(IndexQuoteId.of(idx), inputProvider.timeSeries(idx)); } LocalDate valuationDate = inputProvider.getValuationDate(); ImmutableList<NodalCurveDefinition> curveGroups = group.getCurveDefinitions(); // Create fake market quotes of 0, only to be able to generate trades Map<MarketDataId<?>, Double> mapId0 = new HashMap<>(); for (NodalCurveDefinition entry : curveGroups) { ImmutableList<CurveNode> nodes = entry.getNodes(); for (int i = 0; i < nodes.size(); i++) { for (MarketDataId<?> key : nodes.get(i).requirements()) { mapId0.put(key, 0.0d); } } } ImmutableMarketData marketQuotes0 = ImmutableMarketData.of(valuationDate, mapId0); // Generate market quotes from the trades Map<MarketDataId<?>, Object> mapIdSy = new HashMap<>(); for (NodalCurveDefinition entry : curveGroups) { ImmutableList<CurveNode> nodes = entry.getNodes(); for (CurveNode node : nodes) { ResolvedTrade trade = node.resolvedTrade(1d, marketQuotes0, refData); double mq = measures.value(trade, inputProvider); MarketDataId<?> k = node.requirements().iterator().next(); mapIdSy.put(k, mq); } } // Generate quotes for FX pairs. The first currency is arbitrarily selected as starting point. // The crosses are automatically generated by the MarketDataFxRateProvider used in calibration. for (int loopccy = 1; loopccy < ccyRequired.size(); loopccy++) { CurrencyPair ccyPair = CurrencyPair.of(ccyRequired.get(0), ccyRequired.get(loopccy)); FxRateId fxId = FxRateId.of(ccyPair); mapIdSy.put(fxId, FxRate.of(ccyPair, inputProvider.fxRate(ccyPair))); } return MarketData.of(valuationDate, mapIdSy, ts); } //------------------------------------------------------------------------- @Override public String toString() { return Messages.format("SyntheticCurveCalibrator[{}, {}]", calibrator, measures); } }