Java tutorial
/** * Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.function.calculation.fra; import static com.opengamma.strata.collect.Guavate.toImmutableSet; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.index.IborIndex; import com.opengamma.strata.basics.market.MarketDataKey; import com.opengamma.strata.basics.market.ObservableKey; import com.opengamma.strata.calc.config.Measure; import com.opengamma.strata.calc.config.Measures; import com.opengamma.strata.calc.marketdata.CalculationMarketData; import com.opengamma.strata.calc.marketdata.FunctionRequirements; import com.opengamma.strata.calc.runner.function.CalculationFunction; import com.opengamma.strata.calc.runner.function.FunctionUtils; import com.opengamma.strata.calc.runner.function.result.ScenarioResult; import com.opengamma.strata.collect.result.FailureReason; import com.opengamma.strata.collect.result.Result; import com.opengamma.strata.market.key.DiscountCurveKey; import com.opengamma.strata.market.key.IborIndexCurveKey; import com.opengamma.strata.market.key.IndexRateKey; import com.opengamma.strata.product.fra.ExpandedFra; import com.opengamma.strata.product.fra.Fra; import com.opengamma.strata.product.fra.FraTrade; /** * Perform calculations on a single {@code FraTrade} for each of a set of scenarios. * <p> * This uses the standard discounting calculation method. * The supported built-in measures are: * <ul> * <li>{@linkplain Measures#PAR_RATE Par rate} * <li>{@linkplain Measures#PAR_SPREAD Par spread} * <li>{@linkplain Measures#PRESENT_VALUE Present value} * <li>{@linkplain Measures#PRESENT_VALUE_MULTI_CCY Present value with no currency conversion} * <li>{@linkplain Measures#EXPLAIN_PRESENT_VALUE Explain present value} * <li>{@linkplain Measures#CASH_FLOWS Cash flows} * <li>{@linkplain Measures#PV01 PV01} * <li>{@linkplain Measures#BUCKETED_PV01 Bucketed PV01} * <li>{@linkplain Measures#BUCKETED_GAMMA_PV01 Bucketed Gamma PV01} * </ul> */ public class FraCalculationFunction implements CalculationFunction<FraTrade> { /** * The calculations by measure. */ private static final ImmutableMap<Measure, SingleMeasureCalculation> CALCULATORS = ImmutableMap .<Measure, SingleMeasureCalculation>builder().put(Measures.PAR_RATE, FraMeasureCalculations::parRate) .put(Measures.PAR_SPREAD, FraMeasureCalculations::parSpread) .put(Measures.PRESENT_VALUE, FraMeasureCalculations::presentValue) .put(Measures.EXPLAIN_PRESENT_VALUE, FraMeasureCalculations::explainPresentValue) .put(Measures.CASH_FLOWS, FraMeasureCalculations::cashFlows) .put(Measures.PV01, FraMeasureCalculations::pv01) .put(Measures.BUCKETED_PV01, FraMeasureCalculations::bucketedPv01) .put(Measures.BUCKETED_GAMMA_PV01, FraMeasureCalculations::bucketedGammaPv01).build(); private static final ImmutableSet<Measure> MEASURES = ImmutableSet.<Measure>builder() .addAll(CALCULATORS.keySet()).add(Measures.PRESENT_VALUE_MULTI_CCY).build(); /** * Creates an instance. */ public FraCalculationFunction() { } //------------------------------------------------------------------------- @Override public Set<Measure> supportedMeasures() { return MEASURES; } @Override public Currency naturalCurrency(FraTrade target) { return target.getProduct().getCurrency(); } //------------------------------------------------------------------------- @Override public FunctionRequirements requirements(FraTrade trade, Set<Measure> measures) { Fra product = trade.getProduct(); // Create a set of all indices referenced by the FRA Set<IborIndex> indices = new HashSet<>(); // The main index is always present indices.add(product.getIndex()); // The index used for linear interpolation is optional product.getIndexInterpolated().ifPresent(indices::add); // Create a key identifying the rate of each index referenced by the FRA Set<ObservableKey> indexRateKeys = indices.stream().map(IndexRateKey::of).collect(toImmutableSet()); // Create a key identifying the forward curve of each index referenced by the FRA Set<MarketDataKey<?>> indexCurveKeys = indices.stream().map(IborIndexCurveKey::of) .collect(toImmutableSet()); // Create a key identifying the discount factors for the FRA currency Set<DiscountCurveKey> discountFactorsKeys = ImmutableSet.of(DiscountCurveKey.of(product.getCurrency())); return FunctionRequirements.builder() .singleValueRequirements(Sets.union(indexCurveKeys, discountFactorsKeys)) .timeSeriesRequirements(indexRateKeys).outputCurrencies(product.getCurrency()).build(); } //------------------------------------------------------------------------- @Override public Map<Measure, Result<?>> calculate(FraTrade trade, Set<Measure> measures, CalculationMarketData scenarioMarketData) { // expand the trade once for all measures and all scenarios ExpandedFra product = trade.getProduct().expand(); // loop around measures, calculating all scenarios for one measure Map<Measure, Result<?>> results = new HashMap<>(); for (Measure measure : measures) { results.put(measure, calculate(measure, trade, product, scenarioMarketData)); } // The calculated value is the same for these two measures but they are handled differently WRT FX conversion FunctionUtils.duplicateResult(Measures.PRESENT_VALUE, Measures.PRESENT_VALUE_MULTI_CCY, results); return results; } // calculate one measure private Result<?> calculate(Measure measure, FraTrade trade, ExpandedFra product, CalculationMarketData scenarioMarketData) { SingleMeasureCalculation calculator = CALCULATORS.get(measure); if (calculator == null) { return Result.failure(FailureReason.INVALID_INPUT, "Unsupported measure: {}", measure); } return Result.of(() -> calculator.calculate(trade, product, scenarioMarketData)); } //------------------------------------------------------------------------- @FunctionalInterface interface SingleMeasureCalculation { public abstract ScenarioResult<?> calculate(FraTrade trade, ExpandedFra product, CalculationMarketData marketData); } }