/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.sesame; import java.util.Collection; import java.util.HashSet; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableSet; import com.opengamma.analytics.financial.forex.method.FXMatrix; import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.ProviderUtils; import com.opengamma.core.security.Security; import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration; import com.opengamma.financial.security.CurrenciesVisitor; import com.opengamma.financial.security.FinancialSecurity; import com.opengamma.sesame.trade.TradeWrapper; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; import com.opengamma.util.result.FailureStatus; import com.opengamma.util.result.Result; import com.opengamma.util.tuple.Pair; import com.opengamma.util.tuple.Pairs; /** * Creates a collection of multicurves based on a security and market exposure * selector, combining them into a single multicurve. */ public class ExposureFunctionsDiscountingMulticurveCombinerFn implements DiscountingMulticurveCombinerFn { private static final Logger s_logger = LoggerFactory.getLogger(ExposureFunctionsDiscountingMulticurveCombinerFn.class); /** * Generates the market exposure selector. In turn this can be used to get * an ExposureFunction. */ private final MarketExposureSelector _marketExposureSelector; /** * Generates a discounting multicurve bundle. */ private final DiscountingMulticurveBundleResolverFn _bundleResolver; /** Generates a matrix of FX rates. */ private final FXMatrixFn _fxMatrixFn; /** * Constructor for a multicurve function that selects the multicurves by either trade or security. * * @param marketExposureSelector the exposure function selector. * @param bundleResolver the function used to resolve the multicurves. * @param fxMatrixFn for generating a matrix of FX rates */ public ExposureFunctionsDiscountingMulticurveCombinerFn(MarketExposureSelector marketExposureSelector, DiscountingMulticurveBundleResolverFn bundleResolver, FXMatrixFn fxMatrixFn) { _fxMatrixFn = ArgumentChecker.notNull(fxMatrixFn, "fxMatrixFn"); _marketExposureSelector = ArgumentChecker.notNull(marketExposureSelector, "marketExposureSelector"); _bundleResolver = ArgumentChecker.notNull(bundleResolver, "bundleResolver"); } @Override public Result<MulticurveBundle> getMulticurveBundle(Environment env, TradeWrapper trade) { Set<Result<?>> incompleteBundles = new HashSet<>(); Set<MulticurveProviderDiscount> bundles = new HashSet<>(); CurveBuildingBlockBundle mergedJacobianBundle = new CurveBuildingBlockBundle(); Set<CurveConstructionConfiguration> curveConfigs = _marketExposureSelector.determineCurveConfigurations(trade.getTrade()); for (CurveConstructionConfiguration curveConfig : curveConfigs) { s_logger.debug("Generating bundle '{}', valuationTime {}", curveConfig.getName(), env.getValuationTime()); Result<MulticurveBundle> bundleResult = _bundleResolver.generateBundle(env, curveConfig); if (bundleResult.isSuccess()) { MulticurveBundle result = bundleResult.getValue(); bundles.add(result.getMulticurveProvider()); mergedJacobianBundle.addAll(result.getCurveBuildingBlockBundle()); } else { incompleteBundles.add(bundleResult); } } if (!curveConfigs.isEmpty() && incompleteBundles.isEmpty()) { Result<FXMatrix> fxMatrixResult = getFxMatrix(env, trade.getSecurity()); if (fxMatrixResult.isSuccess()) { FXMatrix fxMatrix = fxMatrixResult.getValue(); return Result.success(new MulticurveBundle(mergeBundlesAndMatrix(bundles, fxMatrix), mergedJacobianBundle)); } else { return Result.failure(fxMatrixResult); } } else if (curveConfigs.isEmpty()) { return Result.failure(FailureStatus.MISSING_DATA, "No matching curves found for trade: {}", trade); } else { return Result.failure(incompleteBundles); } } /** * Returns an {@link FXMatrix} containing FX rates for all the currencies in the security. * * @param env the environment used in calculations * @param security a security * @return an {@code FXMatrix} containing FX rates for all the currencies in the security. */ private Result<FXMatrix> getFxMatrix(Environment env, Security security) { if (security instanceof FinancialSecurity) { Collection<Currency> currencies = ((FinancialSecurity) security).accept(new CurrenciesVisitor()); return _fxMatrixFn.getFXMatrix(env, ImmutableSet.copyOf(currencies)); } else { return Result.failure(FailureStatus.CALCULATION_FAILED, "Security {} isn't a FinancialSecurity, can't get currencies for FX matrix", security); } } @Override public Result<Pair<MulticurveProviderDiscount, CurveBuildingBlockBundle>> createMergedMulticurveBundle( Environment env, TradeWrapper trade, FXMatrix fxMatrix) { Result<MulticurveBundle> result = getMulticurveBundle(env, trade); if (!result.isSuccess()) { return Result.failure(result); } MulticurveBundle multicurve = result.getValue(); return Result.success(Pairs.of(multicurve.getMulticurveProvider(), multicurve.getCurveBuildingBlockBundle())); } private MulticurveProviderDiscount mergeBundlesAndMatrix(Collection<MulticurveProviderDiscount> providers, FXMatrix fxMatrix) { return providers.size() > 1 ? ProviderUtils.mergeDiscountingProviders(mergeBundles(providers), fxMatrix) : providers.iterator().next(); } private MulticurveProviderDiscount mergeBundles(Collection<MulticurveProviderDiscount> providers) { return ProviderUtils.mergeDiscountingProviders(providers); } }