/** * Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.strata.measure.rate; import static com.opengamma.strata.collect.Guavate.toImmutableSet; import java.io.Serializable; import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Stream; import org.joda.beans.BeanDefinition; import org.joda.beans.ImmutableBean; import org.joda.beans.ImmutableConstructor; import org.joda.beans.JodaBeanUtils; import org.joda.beans.MetaBean; import org.joda.beans.Property; import org.joda.beans.PropertyDefinition; import org.joda.beans.impl.light.LightMetaBean; import com.google.common.collect.ImmutableSet; 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.currency.FxRateProvider; import com.opengamma.strata.basics.index.FxIndex; import com.opengamma.strata.basics.index.IborIndex; import com.opengamma.strata.basics.index.Index; import com.opengamma.strata.basics.index.OvernightIndex; import com.opengamma.strata.basics.index.PriceIndex; import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; import com.opengamma.strata.data.MarketData; import com.opengamma.strata.data.MarketDataId; import com.opengamma.strata.data.MarketDataName; import com.opengamma.strata.data.MarketDataNotFoundException; import com.opengamma.strata.data.ObservableId; import com.opengamma.strata.market.curve.Curve; import com.opengamma.strata.market.curve.CurveId; import com.opengamma.strata.market.observable.IndexQuoteId; import com.opengamma.strata.pricer.DiscountFactors; import com.opengamma.strata.pricer.fx.DiscountFxForwardRates; import com.opengamma.strata.pricer.fx.ForwardFxIndexRates; import com.opengamma.strata.pricer.fx.FxForwardRates; import com.opengamma.strata.pricer.fx.FxIndexRates; import com.opengamma.strata.pricer.rate.IborIndexRates; import com.opengamma.strata.pricer.rate.ImmutableRatesProvider; import com.opengamma.strata.pricer.rate.OvernightIndexRates; import com.opengamma.strata.pricer.rate.PriceIndexValues; import com.opengamma.strata.pricer.rate.RatesProvider; /** * A rates provider based on a rates lookup. * <p> * This uses a {@link DefaultRatesMarketDataLookup} to provide a view on {@link MarketData}. */ @BeanDefinition(style = "light") final class DefaultLookupRatesProvider implements RatesProvider, ImmutableBean, Serializable { /** * The lookup. */ @PropertyDefinition(validate = "notNull") private final DefaultRatesMarketDataLookup lookup; /** * The market data. */ @PropertyDefinition(validate = "notNull") private final MarketData marketData; /** * The FX rate provider. */ private final transient FxRateProvider fxRateProvider; // derived //------------------------------------------------------------------------- /** * Obtains an instance based on a lookup and market data. * <p> * The lookup provides the mapping from currency to discount curve, and from * index to forward curve. The curves are in the market data. * * @param lookup the lookup * @param marketData the market data * @return the rates provider */ public static DefaultLookupRatesProvider of(DefaultRatesMarketDataLookup lookup, MarketData marketData) { return new DefaultLookupRatesProvider(lookup, marketData); } @ImmutableConstructor private DefaultLookupRatesProvider(DefaultRatesMarketDataLookup lookup, MarketData marketData) { this.lookup = ArgChecker.notNull(lookup, "lookup"); this.marketData = ArgChecker.notNull(marketData, "marketData"); this.fxRateProvider = lookup.fxRateProvider(marketData); } // ensure standard constructor is invoked private Object readResolve() { return new DefaultLookupRatesProvider(lookup, marketData); } //------------------------------------------------------------------------- @Override public LocalDate getValuationDate() { return marketData.getValuationDate(); } @Override public ImmutableSet<Currency> getDiscountCurrencies() { return lookup.getDiscountCurrencies(); } @Override public ImmutableSet<IborIndex> getIborIndices() { return lookup.getForwardIndices().stream() .filter(IborIndex.class::isInstance) .map(IborIndex.class::cast) .collect(toImmutableSet()); } @Override public ImmutableSet<OvernightIndex> getOvernightIndices() { return lookup.getForwardIndices().stream() .filter(OvernightIndex.class::isInstance) .map(OvernightIndex.class::cast) .collect(toImmutableSet()); } @Override public ImmutableSet<PriceIndex> getPriceIndices() { return lookup.getForwardIndices().stream() .filter(PriceIndex.class::isInstance) .map(PriceIndex.class::cast) .collect(toImmutableSet()); } //------------------------------------------------------------------------- @Override public <T> T data(MarketDataId<T> key) { return marketData.getValue(key); } //------------------------------------------------------------------------- @Override public <T> Optional<T> findData(MarketDataName<T> name) { return Stream.concat(lookup.getDiscountCurves().values().stream(), lookup.getForwardCurves().values().stream()) .filter(id -> id.getMarketDataName().equals(name)) .findFirst() .flatMap(id -> marketData.findValue(id)) .map(v -> name.getMarketDataType().cast(v)); } @Override public LocalDateDoubleTimeSeries timeSeries(Index index) { return marketData.getTimeSeries(IndexQuoteId.of(index)); } //------------------------------------------------------------------------- @Override public double fxRate(Currency baseCurrency, Currency counterCurrency) { return fxRateProvider.fxRate(baseCurrency, counterCurrency); } //------------------------------------------------------------------------- @Override public DiscountFactors discountFactors(Currency currency) { CurveId curveId = lookup.getDiscountCurves().get(currency); if (curveId == null) { throw new MarketDataNotFoundException(lookup.msgCurrencyNotFound(currency)); } Curve curve = marketData.getValue(curveId); return DiscountFactors.of(currency, getValuationDate(), curve); } //------------------------------------------------------------------------- @Override public FxIndexRates fxIndexRates(FxIndex index) { FxForwardRates fxForwardRates = fxForwardRates(index.getCurrencyPair()); return ForwardFxIndexRates.of(index, fxForwardRates, timeSeries(index)); } //------------------------------------------------------------------------- @Override public FxForwardRates fxForwardRates(CurrencyPair currencyPair) { DiscountFactors base = discountFactors(currencyPair.getBase()); DiscountFactors counter = discountFactors(currencyPair.getCounter()); FxRate fxRate = FxRate.of(currencyPair, fxRate(currencyPair)); return DiscountFxForwardRates.of(currencyPair, fxRate, base, counter); }; //------------------------------------------------------------------------- @Override public IborIndexRates iborIndexRates(IborIndex index) { CurveId curveId = lookup.getForwardCurves().get(index); if (curveId == null) { throw new MarketDataNotFoundException(lookup.msgIndexNotFound(index)); } Curve curve = marketData.getValue(curveId); return IborIndexRates.of(index, getValuationDate(), curve, timeSeries(index)); } //------------------------------------------------------------------------- @Override public OvernightIndexRates overnightIndexRates(OvernightIndex index) { CurveId curveId = lookup.getForwardCurves().get(index); if (curveId == null) { throw new MarketDataNotFoundException(lookup.msgIndexNotFound(index)); } Curve curve = marketData.getValue(curveId); return OvernightIndexRates.of(index, getValuationDate(), curve, timeSeries(index)); } //------------------------------------------------------------------------- @Override public PriceIndexValues priceIndexValues(PriceIndex index) { CurveId curveId = lookup.getForwardCurves().get(index); if (curveId == null) { throw new MarketDataNotFoundException(lookup.msgIndexNotFound(index)); } Curve curve = marketData.getValue(curveId); return PriceIndexValues.of(index, getValuationDate(), curve, timeSeries(index)); } //------------------------------------------------------------------------- @Override public ImmutableRatesProvider toImmutableRatesProvider() { // discount curves Map<Currency, Curve> dscMap = new HashMap<>(); for (Currency currency : lookup.getDiscountCurrencies()) { CurveId curveId = lookup.getDiscountCurves().get(currency); if (curveId != null && marketData.containsValue(curveId)) { dscMap.put(currency, marketData.getValue(curveId)); } } // forward curves Map<Index, Curve> fwdMap = new HashMap<>(); for (Index index : lookup.getForwardIndices()) { CurveId curveId = lookup.getForwardCurves().get(index); if (curveId != null && marketData.containsValue(curveId)) { fwdMap.put(index, marketData.getValue(curveId)); } } // time-series Map<Index, LocalDateDoubleTimeSeries> tsMap = new HashMap<>(); for (ObservableId id : marketData.getTimeSeriesIds()) { if (id instanceof IndexQuoteId) { IndexQuoteId indexId = (IndexQuoteId) id; tsMap.put(indexId.getIndex(), marketData.getTimeSeries(id)); } } // build result return ImmutableRatesProvider.builder(getValuationDate()) .discountCurves(dscMap) .indexCurves(fwdMap) .timeSeries(tsMap) .fxRateProvider(fxRateProvider) .build(); } //------------------------- AUTOGENERATED START ------------------------- ///CLOVER:OFF /** * The meta-bean for {@code DefaultLookupRatesProvider}. */ private static MetaBean META_BEAN = LightMetaBean.of(DefaultLookupRatesProvider.class); /** * The meta-bean for {@code DefaultLookupRatesProvider}. * @return the meta-bean, not null */ public static MetaBean meta() { return META_BEAN; } static { JodaBeanUtils.registerMetaBean(META_BEAN); } /** * The serialization version id. */ private static final long serialVersionUID = 1L; @Override public MetaBean metaBean() { return META_BEAN; } @Override public <R> Property<R> property(String propertyName) { return metaBean().<R>metaProperty(propertyName).createProperty(this); } @Override public Set<String> propertyNames() { return metaBean().metaPropertyMap().keySet(); } //----------------------------------------------------------------------- /** * Gets the lookup. * @return the value of the property, not null */ public DefaultRatesMarketDataLookup getLookup() { return lookup; } //----------------------------------------------------------------------- /** * Gets the market data. * @return the value of the property, not null */ public MarketData getMarketData() { return marketData; } //----------------------------------------------------------------------- @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (obj != null && obj.getClass() == this.getClass()) { DefaultLookupRatesProvider other = (DefaultLookupRatesProvider) obj; return JodaBeanUtils.equal(lookup, other.lookup) && JodaBeanUtils.equal(marketData, other.marketData); } return false; } @Override public int hashCode() { int hash = getClass().hashCode(); hash = hash * 31 + JodaBeanUtils.hashCode(lookup); hash = hash * 31 + JodaBeanUtils.hashCode(marketData); return hash; } @Override public String toString() { StringBuilder buf = new StringBuilder(96); buf.append("DefaultLookupRatesProvider{"); buf.append("lookup").append('=').append(lookup).append(',').append(' '); buf.append("marketData").append('=').append(JodaBeanUtils.toString(marketData)); buf.append('}'); return buf.toString(); } ///CLOVER:ON //-------------------------- AUTOGENERATED END -------------------------- }