/** * 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.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.analytics.financial.forex.method.EmptyFXMatrix; import com.opengamma.analytics.financial.forex.method.FXMatrix; import com.opengamma.core.config.ConfigSource; import com.opengamma.core.config.impl.ConfigItem; import com.opengamma.core.convention.ConventionSource; import com.opengamma.core.security.SecuritySource; import com.opengamma.financial.analytics.curve.AbstractCurveDefinition; import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration; import com.opengamma.financial.analytics.curve.CurveDefinition; import com.opengamma.financial.analytics.curve.CurveGroupConfiguration; import com.opengamma.financial.analytics.curve.CurveNodeCurrencyVisitor; import com.opengamma.financial.analytics.curve.CurveTypeConfiguration; import com.opengamma.financial.analytics.ircurve.strips.CurveNode; import com.opengamma.financial.currency.CurrencyPair; import com.opengamma.id.VersionCorrection; import com.opengamma.sesame.component.CurrencyPairSet; import com.opengamma.sesame.marketdata.MarketDataFn; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.money.Currency; import com.opengamma.util.result.Result; /** * Function implementation that provides a FX matrix. */ public class DefaultFXMatrixFn implements FXMatrixFn { /** * The convention source. */ private final ConventionSource _conventionSource; /** * The security source. */ private final SecuritySource _securitySource; /** * The market data function. */ private final MarketDataFn _marketDataFn; /** * The config source. */ private final ConfigSource _configSource; public DefaultFXMatrixFn(ConfigSource configSource, ConventionSource conventionSource, SecuritySource securitySource, MarketDataFn marketDataFn) { _configSource = ArgumentChecker.notNull(configSource, "configSource"); _conventionSource = ArgumentChecker.notNull(conventionSource, "conventionSource"); _securitySource = ArgumentChecker.notNull(securitySource, "securitySource"); _marketDataFn = ArgumentChecker.notNull(marketDataFn, "marketDataProviderFunction"); } //------------------------------------------------------------------------- private Set<Currency> extractCurrencies(CurveConstructionConfiguration configuration, CurveNodeCurrencyVisitor curveNodeCurrencyVisitor) { final Set<Currency> currencies = new TreeSet<>(); for (final CurveGroupConfiguration group : configuration.getCurveGroups()) { for (final Map.Entry<String, List<? extends CurveTypeConfiguration>> entry : group.getTypesForCurves().entrySet()) { final String curveName = entry.getKey(); final AbstractCurveDefinition curveDefinition = findCurveDefinition(curveName); if (curveDefinition == null) { throw new OpenGammaRuntimeException("Could not get curve definition called " + curveName); } if (curveDefinition instanceof CurveDefinition) { for (final CurveNode node : ((CurveDefinition) curveDefinition).getNodes()) { currencies.addAll(node.accept(curveNodeCurrencyVisitor)); } } else { return Collections.emptySet(); } } } final List<String> exogenousConfigurations = configuration.getExogenousConfigurations(); if (exogenousConfigurations != null) { for (final String name : exogenousConfigurations) { final CurveConstructionConfiguration exogenousConfiguration = _configSource.getLatestByName(CurveConstructionConfiguration.class, name); currencies.addAll(extractCurrencies(exogenousConfiguration, curveNodeCurrencyVisitor)); } } return currencies; } private AbstractCurveDefinition findCurveDefinition(String curveName) { Collection<ConfigItem<Object>> items = _configSource.get(Object.class, curveName, VersionCorrection.LATEST); for (ConfigItem<Object> item : items) { Object value = item.getValue(); if (value instanceof AbstractCurveDefinition) { return (AbstractCurveDefinition) value; } } return null; } @Override public Result<FXMatrix> getFXMatrix(Environment env, CurveConstructionConfiguration configuration) { // todo - should this actually be another function or set of functions Set<Currency> currencies = extractCurrencies(configuration, new CurveNodeCurrencyVisitor(_conventionSource, _securitySource)); return getFXMatrix(env, currencies); } @Override public Result<FXMatrix> getFXMatrix(Environment env, Set<Currency> currencies) { FXMatrix matrix = EmptyFXMatrix.INSTANCE; Currency refCurr = null; List<Result<?>> failures = new ArrayList<>(); for (Currency currency : currencies) { // Use the first currency in the set as the reference currency in the matrix if (refCurr == null) { refCurr = currency; } else { // currency matrix will ensure the spotRate returned is interpreted correctly, // depending on the order base and counter are specified in. CurrencyPair currencyPair = CurrencyPair.of(refCurr, currency); Result<Double> marketDataResult = _marketDataFn.getFxRate(env, currencyPair); if (marketDataResult.isSuccess()) { if (EmptyFXMatrix.INSTANCE == matrix) { matrix = new FXMatrix(); } matrix.addCurrency(currencyPair.getCounter(), currencyPair.getBase(), marketDataResult.getValue()); } else { failures.add(marketDataResult); } } } if (failures.isEmpty()) { return Result.success(matrix); } else { return Result.failure(failures); } } @Override public Result<Map<Currency, FXMatrix>> getAvailableFxRates(Environment env, CurrencyPairSet currencyPairs) { Map<Currency, FXMatrix> fxMatrices = new HashMap<Currency, FXMatrix>(); for (CurrencyPair currencyPair : currencyPairs.getCurrencyPairs()) { if (!fxMatrices.containsKey(currencyPair.getBase())) { fxMatrices.put(currencyPair.getBase(), new FXMatrix(currencyPair.getBase())); } FXMatrix matrix = fxMatrices.get(currencyPair.getBase()); Result<Double> marketDataResult = _marketDataFn.getFxRate(env, currencyPair); if (marketDataResult.isSuccess()) { matrix.addCurrency(currencyPair.getCounter(), currencyPair.getBase(), marketDataResult.getValue()); } } return Result.success(fxMatrices); } }