/**
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.examples.finance;
import static com.opengamma.strata.basics.date.DayCounts.ACT_365F;
import static com.opengamma.strata.examples.finance.SwaptionCubeData.DATA_ARRAY_FULL;
import static com.opengamma.strata.examples.finance.SwaptionCubeData.DATA_ARRAY_SPARSE;
import static com.opengamma.strata.examples.finance.SwaptionCubeData.EXPIRIES;
import static com.opengamma.strata.examples.finance.SwaptionCubeData.MONEYNESS;
import static com.opengamma.strata.examples.finance.SwaptionCubeData.TENORS;
import static com.opengamma.strata.market.ValueType.NORMAL_VOLATILITY;
import static com.opengamma.strata.market.ValueType.SIMPLE_MONEYNESS;
import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR;
import static com.opengamma.strata.product.swap.type.FixedIborSwapConventions.EUR_FIXED_1Y_EURIBOR_6M;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.collect.ImmutableList;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.currency.CurrencyAmount;
import com.opengamma.strata.basics.date.AdjustableDate;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.collect.io.ResourceLocator;
import com.opengamma.strata.data.ImmutableMarketData;
import com.opengamma.strata.loader.csv.QuotesCsvLoader;
import com.opengamma.strata.loader.csv.RatesCalibrationCsvLoader;
import com.opengamma.strata.market.ValueType;
import com.opengamma.strata.market.curve.CurveGroupDefinition;
import com.opengamma.strata.market.curve.CurveGroupName;
import com.opengamma.strata.market.observable.QuoteId;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.market.surface.ConstantSurface;
import com.opengamma.strata.market.surface.DefaultSurfaceMetadata;
import com.opengamma.strata.market.surface.Surface;
import com.opengamma.strata.market.surface.SurfaceMetadata;
import com.opengamma.strata.market.surface.interpolator.GridSurfaceInterpolator;
import com.opengamma.strata.market.surface.interpolator.SurfaceInterpolator;
import com.opengamma.strata.pricer.curve.CalibrationMeasures;
import com.opengamma.strata.pricer.curve.CurveCalibrator;
import com.opengamma.strata.pricer.option.RawOptionData;
import com.opengamma.strata.pricer.option.TenorRawOptionData;
import com.opengamma.strata.pricer.rate.RatesProvider;
import com.opengamma.strata.pricer.swaption.SabrParametersSwaptionVolatilities;
import com.opengamma.strata.pricer.swaption.SabrSwaptionCalibrator;
import com.opengamma.strata.pricer.swaption.SabrSwaptionDefinition;
import com.opengamma.strata.pricer.swaption.SabrSwaptionPhysicalProductPricer;
import com.opengamma.strata.pricer.swaption.SwaptionVolatilitiesName;
import com.opengamma.strata.product.common.BuySell;
import com.opengamma.strata.product.common.LongShort;
import com.opengamma.strata.product.swap.SwapTrade;
import com.opengamma.strata.product.swaption.PhysicalSwaptionSettlement;
import com.opengamma.strata.product.swaption.ResolvedSwaption;
import com.opengamma.strata.product.swaption.Swaption;
/**
* Analysis of the pricing and risk of a swaption with calibrated SABR parameters.
*/
public class SabrSwaptionCubePvRiskExample {
private static final ReferenceData REF_DATA = ReferenceData.standard();
private static final LocalDate CALIBRATION_DATE = LocalDate.of(2016, 2, 29);
private static final ZonedDateTime CALIBRATION_TIME = CALIBRATION_DATE.atTime(10, 0).atZone(ZoneId.of("Europe/Berlin"));
private static final SabrSwaptionCalibrator SABR_CALIBRATION = SabrSwaptionCalibrator.DEFAULT;
private static final String BASE_DIR = "src/main/resources/";
private static final String GROUPS_FILE = "example-calibration/curves/EUR-DSCONOIS-E3BS-E6IRS-group.csv";
private static final String SETTINGS_FILE = "example-calibration/curves/EUR-DSCONOIS-E3BS-E6IRS-settings.csv";
private static final String NODES_FILE = "example-calibration/curves/EUR-DSCONOIS-E3BS-E6IRS-nodes.csv";
private static final String QUOTES_FILE = "example-calibration/quotes/quotes-20160229-eur.csv";
private static final CurveGroupDefinition CONFIGS =
RatesCalibrationCsvLoader.load(
ResourceLocator.of(BASE_DIR + GROUPS_FILE),
ResourceLocator.of(BASE_DIR + SETTINGS_FILE),
ResourceLocator.of(BASE_DIR + NODES_FILE)).get(CurveGroupName.of("EUR-DSCONOIS-E3BS-E6IRS"));
private static final Map<QuoteId, Double> MAP_MQ =
QuotesCsvLoader.load(CALIBRATION_DATE, ImmutableList.of(ResourceLocator.of(BASE_DIR + QUOTES_FILE)));
private static final ImmutableMarketData MARKET_QUOTES = ImmutableMarketData.of(CALIBRATION_DATE, MAP_MQ);
private static final CalibrationMeasures CALIBRATION_MEASURES = CalibrationMeasures.PAR_SPREAD;
private static final CurveCalibrator CALIBRATOR = CurveCalibrator.of(1e-9, 1e-9, 100, CALIBRATION_MEASURES);
private static final SabrSwaptionPhysicalProductPricer SWAPTION_PRICER = SabrSwaptionPhysicalProductPricer.DEFAULT;
private static final TenorRawOptionData DATA_FULL = rawData(DATA_ARRAY_FULL);
private static final TenorRawOptionData DATA_SPARSE = rawData(DATA_ARRAY_SPARSE);
private static final SurfaceInterpolator INTERPOLATOR_2D = GridSurfaceInterpolator.of(LINEAR, LINEAR);
private static final SwaptionVolatilitiesName NAME_SABR = SwaptionVolatilitiesName.of("Calibrated-SABR");
private static final SabrSwaptionDefinition DEFINITION =
SabrSwaptionDefinition.of(NAME_SABR, EUR_FIXED_1Y_EURIBOR_6M, ACT_365F, INTERPOLATOR_2D);
//-------------------------------------------------------------------------
/**
* Runs the calibration of SABR on swaptions and print on the console the present value, bucketed PV01 and
* the bucketed Vega of a 18M x 4Y swaption.
*
* @param args -s to use the spares data
*/
public static void main(String[] args) {
long start, end;
// Swaption description
BuySell payer = BuySell.BUY;
Period expiry = Period.ofMonths(18);
double notional = 1_000_000;
double strike = 0.0100;
Tenor tenor = Tenor.TENOR_4Y;
LocalDate expiryDate = EUR_FIXED_1Y_EURIBOR_6M.getFloatingLeg().getStartDateBusinessDayAdjustment()
.adjust(CALIBRATION_DATE.plus(expiry), REF_DATA);
SwapTrade underlying = EUR_FIXED_1Y_EURIBOR_6M.createTrade(expiryDate, tenor, payer, notional, strike, REF_DATA);
Swaption swaption = Swaption.builder().expiryDate(AdjustableDate.of(expiryDate)).expiryTime(LocalTime.of(11, 00))
.expiryZone(ZoneId.of("Europe/Berlin")).underlying(underlying.getProduct()).longShort(LongShort.LONG)
.swaptionSettlement(PhysicalSwaptionSettlement.DEFAULT).build();
ResolvedSwaption resolvedSwaption = swaption.resolve(REF_DATA);
// select data
TenorRawOptionData data = DATA_FULL;
if (args.length > 0) {
if (args[0].equals("-s")) {
data = DATA_SPARSE;
}
}
start = System.currentTimeMillis();
// Curve calibration
RatesProvider multicurve = CALIBRATOR.calibrate(CONFIGS, MARKET_QUOTES, REF_DATA);
end = System.currentTimeMillis();
System.out.println("Curve calibration time: " + (end - start) + " ms.");
// SABR calibration
start = System.currentTimeMillis();
double beta = 0.50;
SurfaceMetadata betaMetadata = DefaultSurfaceMetadata.builder()
.xValueType(ValueType.YEAR_FRACTION)
.yValueType(ValueType.YEAR_FRACTION)
.zValueType(ValueType.SABR_BETA)
.surfaceName("Beta").build();
Surface betaSurface = ConstantSurface.of(betaMetadata, beta);
double shift = 0.0300;
Surface shiftSurface = ConstantSurface.of("SABR-Shift", shift);
SabrParametersSwaptionVolatilities sabr = SABR_CALIBRATION.calibrateWithFixedBetaAndShift(
DEFINITION, CALIBRATION_TIME, data, multicurve, betaSurface, shiftSurface);
end = System.currentTimeMillis();
System.out.println("SABR calibration time: " + (end - start) + " ms.");
// Price and risk
System.out.println("Risk measures: ");
start = System.currentTimeMillis();
CurrencyAmount pv = SWAPTION_PRICER.presentValue(resolvedSwaption, multicurve, sabr);
System.out.println(" |-> PV: " + pv.toString());
PointSensitivities deltaPts =
SWAPTION_PRICER.presentValueSensitivityRatesStickyModel(resolvedSwaption, multicurve, sabr).build();
CurrencyParameterSensitivities deltaBucketed = multicurve.parameterSensitivity(deltaPts);
System.out.println(" |-> Delta bucketed: " + deltaBucketed.toString());
PointSensitivities vegaPts =
SWAPTION_PRICER.presentValueSensitivityModelParamsSabr(resolvedSwaption, multicurve, sabr).build();
System.out.println(" |-> Vega point: " + vegaPts.toString());
CurrencyParameterSensitivities vegaBucketed = sabr.parameterSensitivity(vegaPts);
for (int i = 0; i < vegaBucketed.size(); i++) {
System.out.println(" |-> Vega bucketed: " + vegaBucketed.getSensitivities().get(i));
}
end = System.currentTimeMillis();
System.out.println("PV and risk time: " + (end - start) + " ms.");
}
private static TenorRawOptionData rawData(double[][][] dataArray) {
Map<Tenor, RawOptionData> raw = new TreeMap<>();
for (int looptenor = 0; looptenor < dataArray.length; looptenor++) {
DoubleMatrix matrix = DoubleMatrix.ofUnsafe(dataArray[looptenor]);
raw.put(TENORS.get(looptenor), RawOptionData.of(EXPIRIES, MONEYNESS, SIMPLE_MONEYNESS, matrix, NORMAL_VOLATILITY));
}
return TenorRawOptionData.of(raw);
}
}