diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketData.java new file mode 100644 index 0000000000..9e9efc8345 --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketData.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.light.LightMetaBean; + +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; + +/** + * The default market data for Overnight future options. + *

+ * This uses a {@link OvernightFutureOptionMarketDataLookup} to provide a view on {@link MarketData}. + */ +@BeanDefinition(style = "light") +final class DefaultOvernightFutureOptionMarketData implements OvernightFutureOptionMarketData, ImmutableBean, Serializable { + + /** + * The lookup. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final OvernightFutureOptionMarketDataLookup lookup; + /** + * The market data. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final MarketData marketData; + + //------------------------------------------------------------------------- + /** + * Obtains an instance based on a lookup and market data. + *

+ * The lookup knows how to obtain the volatilities from the market data. + * This might involve accessing a surface or a cube. + * + * @param lookup the lookup + * @param marketData the market data + * @return the rates market view + */ + public static DefaultOvernightFutureOptionMarketData of( + OvernightFutureOptionMarketDataLookup lookup, + MarketData marketData) { + + return new DefaultOvernightFutureOptionMarketData(lookup, marketData); + } + + @ImmutableConstructor + private DefaultOvernightFutureOptionMarketData( + OvernightFutureOptionMarketDataLookup lookup, + MarketData marketData) { + + this.lookup = ArgChecker.notNull(lookup, "lookup"); + this.marketData = ArgChecker.notNull(marketData, "marketData"); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionMarketData withMarketData(MarketData marketData) { + return DefaultOvernightFutureOptionMarketData.of(lookup, marketData); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionVolatilities volatilities(OvernightIndex index) { + return lookup.volatilities(index, marketData); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketData}. + */ + private static final TypedMetaBean META_BEAN = + LightMetaBean.of( + DefaultOvernightFutureOptionMarketData.class, + MethodHandles.lookup(), + new String[] { + "lookup", + "marketData"}, + new Object[0]); + + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketData}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the lookup. + * @return the value of the property, not null + */ + @Override + public OvernightFutureOptionMarketDataLookup getLookup() { + return lookup; + } + + //----------------------------------------------------------------------- + /** + * Gets the market data. + * @return the value of the property, not null + */ + @Override + public MarketData getMarketData() { + return marketData; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + DefaultOvernightFutureOptionMarketData other = (DefaultOvernightFutureOptionMarketData) 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("DefaultOvernightFutureOptionMarketData{"); + buf.append("lookup").append('=').append(JodaBeanUtils.toString(lookup)).append(',').append(' '); + buf.append("marketData").append('=').append(JodaBeanUtils.toString(marketData)); + buf.append('}'); + return buf.toString(); + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketDataLookup.java new file mode 100644 index 0000000000..00647bc00f --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketDataLookup.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.light.LightMetaBean; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.index.Index; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.calc.CalculationRules; +import com.opengamma.strata.calc.runner.CalculationParameter; +import com.opengamma.strata.calc.runner.FunctionRequirements; +import com.opengamma.strata.collect.Messages; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.MarketDataId; +import com.opengamma.strata.data.MarketDataNotFoundException; +import com.opengamma.strata.data.scenario.ScenarioMarketData; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilitiesId; + +/** + * The Overnight future option lookup, used to select volatilities for pricing. + *

+ * This provides Overnight future option volatilities by index. + *

+ * The lookup implements {@link CalculationParameter} and is used by passing it + * as an argument to {@link CalculationRules}. It provides the link between the + * data that the function needs and the data that is available in {@link ScenarioMarketData}. + */ +@BeanDefinition(style = "light") +final class DefaultOvernightFutureOptionMarketDataLookup + implements OvernightFutureOptionMarketDataLookup, ImmutableBean, Serializable { + + /** + * The volatility identifiers, keyed by index. + */ + @PropertyDefinition(validate = "notNull") + private final ImmutableMap volatilityIds; + + //------------------------------------------------------------------------- + /** + * Obtains an instance based on a single mapping from index to volatility identifier. + *

+ * The lookup provides volatilities for the specified index. + * + * @param index the Overnight index + * @param volatilityId the volatility identifier + * @return the Overnight future option lookup containing the specified mapping + */ + public static DefaultOvernightFutureOptionMarketDataLookup of(OvernightIndex index, OvernightFutureOptionVolatilitiesId volatilityId) { + return new DefaultOvernightFutureOptionMarketDataLookup(ImmutableMap.of(index, volatilityId)); + } + + /** + * Obtains an instance based on a map of volatility identifiers. + *

+ * The map is used to specify the appropriate volatilities to use for each index. + * + * @param volatilityIds the volatility identifiers, keyed by index + * @return the Overnight future option lookup containing the specified volatilities + */ + public static DefaultOvernightFutureOptionMarketDataLookup of(Map volatilityIds) { + return new DefaultOvernightFutureOptionMarketDataLookup(volatilityIds); + } + + //------------------------------------------------------------------------- + @Override + public ImmutableSet getVolatilityIndices() { + return volatilityIds.keySet(); + } + + @Override + public ImmutableSet> getVolatilityIds(OvernightIndex index) { + OvernightFutureOptionVolatilitiesId id = volatilityIds.get(index); + if (id == null) { + throw new IllegalArgumentException(msgIndexNotFound(index)); + } + return ImmutableSet.of(id); + } + + //------------------------------------------------------------------------- + @Override + public FunctionRequirements requirements(Set indices) { + Set volIds = new HashSet<>(); + for (Index index : indices) { + if (!volatilityIds.keySet().contains(index)) { + throw new IllegalArgumentException(msgIndexNotFound(index)); + } + volIds.add(volatilityIds.get(index)); + } + return FunctionRequirements.builder().valueRequirements(volIds).build(); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionVolatilities volatilities(OvernightIndex index, MarketData marketData) { + OvernightFutureOptionVolatilitiesId volatilityId = volatilityIds.get(index); + if (volatilityId == null) { + throw new MarketDataNotFoundException(msgIndexNotFound(index)); + } + return marketData.getValue(volatilityId); + } + + //------------------------------------------------------------------------- + private String msgIndexNotFound(Index index) { + return Messages.format("OvernightFutureOption lookup has no volatilities defined for index '{}'", index); + } + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketDataLookup}. + */ + private static final TypedMetaBean META_BEAN = + LightMetaBean.of( + DefaultOvernightFutureOptionMarketDataLookup.class, + MethodHandles.lookup(), + new String[] { + "volatilityIds"}, + ImmutableMap.of()); + + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketDataLookup}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + private DefaultOvernightFutureOptionMarketDataLookup( + Map volatilityIds) { + JodaBeanUtils.notNull(volatilityIds, "volatilityIds"); + this.volatilityIds = ImmutableMap.copyOf(volatilityIds); + } + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the volatility identifiers, keyed by index. + * @return the value of the property, not null + */ + public ImmutableMap getVolatilityIds() { + return volatilityIds; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + DefaultOvernightFutureOptionMarketDataLookup other = (DefaultOvernightFutureOptionMarketDataLookup) obj; + return JodaBeanUtils.equal(volatilityIds, other.volatilityIds); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(volatilityIds); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(64); + buf.append("DefaultOvernightFutureOptionMarketDataLookup{"); + buf.append("volatilityIds").append('=').append(JodaBeanUtils.toString(volatilityIds)); + buf.append('}'); + return buf.toString(); + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionScenarioMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionScenarioMarketData.java new file mode 100644 index 0000000000..776207083f --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionScenarioMarketData.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.light.LightMetaBean; + +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.data.scenario.ScenarioMarketData; + +/** + * The default market data for Overnight future options, used for calculation across multiple scenarios. + *

+ * This uses a {@link OvernightFutureOptionMarketDataLookup} to provide a view on {@link ScenarioMarketData}. + */ +@BeanDefinition(style = "light") +final class DefaultOvernightFutureOptionScenarioMarketData + implements OvernightFutureOptionScenarioMarketData, ImmutableBean, Serializable { + + /** + * The lookup. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final OvernightFutureOptionMarketDataLookup lookup; + /** + * The market data. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ScenarioMarketData marketData; + + //------------------------------------------------------------------------- + /** + * Obtains an instance based on a lookup and market data. + *

+ * The lookup knows how to obtain the volatilities from the market data. + * This might involve accessing a surface or a cube. + * + * @param lookup the lookup + * @param marketData the market data + * @return the rates market view + */ + public static DefaultOvernightFutureOptionScenarioMarketData of( + OvernightFutureOptionMarketDataLookup lookup, + ScenarioMarketData marketData) { + + return new DefaultOvernightFutureOptionScenarioMarketData(lookup, marketData); + } + + @ImmutableConstructor + private DefaultOvernightFutureOptionScenarioMarketData( + OvernightFutureOptionMarketDataLookup lookup, + ScenarioMarketData marketData) { + + this.lookup = ArgChecker.notNull(lookup, "lookup"); + this.marketData = ArgChecker.notNull(marketData, "marketData"); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionScenarioMarketData withMarketData(ScenarioMarketData marketData) { + return DefaultOvernightFutureOptionScenarioMarketData.of(lookup, marketData); + } + + //------------------------------------------------------------------------- + @Override + public int getScenarioCount() { + return marketData.getScenarioCount(); + } + + @Override + public OvernightFutureOptionMarketData scenario(int scenarioIndex) { + return lookup.marketDataView(marketData.scenario(scenarioIndex)); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code DefaultOvernightFutureOptionScenarioMarketData}. + */ + private static final TypedMetaBean META_BEAN = + LightMetaBean.of( + DefaultOvernightFutureOptionScenarioMarketData.class, + MethodHandles.lookup(), + new String[] { + "lookup", + "marketData"}, + new Object[0]); + + /** + * The meta-bean for {@code DefaultOvernightFutureOptionScenarioMarketData}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the lookup. + * @return the value of the property, not null + */ + @Override + public OvernightFutureOptionMarketDataLookup getLookup() { + return lookup; + } + + //----------------------------------------------------------------------- + /** + * Gets the market data. + * @return the value of the property, not null + */ + @Override + public ScenarioMarketData getMarketData() { + return marketData; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + DefaultOvernightFutureOptionScenarioMarketData other = (DefaultOvernightFutureOptionScenarioMarketData) 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("DefaultOvernightFutureOptionScenarioMarketData{"); + buf.append("lookup").append('=').append(JodaBeanUtils.toString(lookup)).append(',').append(' '); + buf.append("marketData").append('=').append(JodaBeanUtils.toString(marketData)); + buf.append('}'); + return buf.toString(); + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketData.java new file mode 100644 index 0000000000..c7e09a8d56 --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketData.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.time.LocalDate; + +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.MarketDataNotFoundException; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; + +/** + * Market data for Overnight future options. + *

+ * This interface exposes the market data necessary for pricing an Overnight future option. + *

+ * Implementations of this interface must be immutable. + */ +public interface OvernightFutureOptionMarketData { + + /** + * Gets the valuation date. + * + * @return the valuation date + */ + public default LocalDate getValuationDate() { + return getMarketData().getValuationDate(); + } + + //------------------------------------------------------------------------- + /** + * Gets the lookup that provides access to Overnight future option volatilities. + * + * @return the Overnight future option lookup + */ + public abstract OvernightFutureOptionMarketDataLookup getLookup(); + + /** + * Gets the market data. + * + * @return the market data + */ + public abstract MarketData getMarketData(); + + /** + * Returns a copy of this instance with the specified market data. + * + * @param marketData the market data to use + * @return a market view based on the specified data + */ + public abstract OvernightFutureOptionMarketData withMarketData(MarketData marketData); + + //------------------------------------------------------------------------- + /** + * Gets the volatilities for the specified Overnight index. + *

+ * If the index is not found, an exception is thrown. + * + * @param index the Overnight index + * @return the volatilities for the index + * @throws MarketDataNotFoundException if the index is not found + */ + public abstract OvernightFutureOptionVolatilities volatilities(OvernightIndex index); + +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookup.java new file mode 100644 index 0000000000..c8c4a8690e --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookup.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.calc.CalculationRules; +import com.opengamma.strata.calc.runner.CalculationParameter; +import com.opengamma.strata.calc.runner.CalculationParameters; +import com.opengamma.strata.calc.runner.FunctionRequirements; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.MarketDataId; +import com.opengamma.strata.data.MarketDataNotFoundException; +import com.opengamma.strata.data.scenario.ScenarioMarketData; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilitiesId; + +/** + * The lookup that provides access to Overnight future option volatilities in market data. + *

+ * The Overnight future option market lookup provides access to the volatilities used to price Overnight future options. + *

+ * The lookup implements {@link CalculationParameter} and is used by passing it + * as an argument to {@link CalculationRules}. It provides the link between the + * data that the function needs and the data that is available in {@link ScenarioMarketData}. + *

+ * Implementations of this interface must be immutable. + */ +public interface OvernightFutureOptionMarketDataLookup extends CalculationParameter { + + /** + * Obtains an instance based on a single mapping from index to volatility identifier. + *

+ * The lookup provides volatilities for the specified index. + * + * @param index the Overnight index + * @param volatilityId the volatility identifier + * @return the Overnight future option lookup containing the specified mapping + */ + public static OvernightFutureOptionMarketDataLookup of(OvernightIndex index, OvernightFutureOptionVolatilitiesId volatilityId) { + return DefaultOvernightFutureOptionMarketDataLookup.of(ImmutableMap.of(index, volatilityId)); + } + + /** + * Obtains an instance based on a map of volatility identifiers. + *

+ * The map is used to specify the appropriate volatilities to use for each index. + * + * @param volatilityIds the volatility identifiers, keyed by index + * @return the Overnight future option lookup containing the specified volatilities + */ + public static OvernightFutureOptionMarketDataLookup of(Map volatilityIds) { + return DefaultOvernightFutureOptionMarketDataLookup.of(volatilityIds); + } + + //------------------------------------------------------------------------- + /** + * Gets the type that the lookup will be queried by. + *

+ * This returns {@code OvernightFutureOptionMarketLookup.class}. + * When querying parameters using {@link CalculationParameters#findParameter(Class)}, + * {@code OvernightFutureOptionMarketLookup.class} must be passed in to find the instance. + * + * @return the type of the parameter implementation + */ + @Override + public default Class queryType() { + return OvernightFutureOptionMarketDataLookup.class; + } + + //------------------------------------------------------------------------- + /** + * Gets the set of indices that volatilities are provided for. + * + * @return the set of indices + */ + public abstract ImmutableSet getVolatilityIndices(); + + /** + * Gets the identifiers used to obtain the volatilities for the specified currency. + *

+ * The result will typically refer to a surface or cube. + * If the index is not found, an exception is thrown. + * + * @param index the index for which identifiers are required + * @return the set of market data identifiers + * @throws IllegalArgumentException if the index is not found + */ + public abstract ImmutableSet> getVolatilityIds(OvernightIndex index); + + //------------------------------------------------------------------------- + /** + * Creates market data requirements for the specified indices. + * + * @param indices the indices, for which volatilities are required + * @return the requirements + */ + public default FunctionRequirements requirements(OvernightIndex... indices) { + return requirements(ImmutableSet.copyOf(indices)); + } + + /** + * Creates market data requirements for the specified indices. + * + * @param indices the indices, for which volatilities are required + * @return the requirements + */ + public abstract FunctionRequirements requirements(Set indices); + + //------------------------------------------------------------------------- + /** + * Obtains a filtered view of the complete set of market data. + *

+ * This method returns an instance that binds the lookup to the market data. + * The input is {@link ScenarioMarketData}, which contains market data for all scenarios. + * + * @param marketData the complete set of market data for all scenarios + * @return the filtered market data + */ + public default OvernightFutureOptionScenarioMarketData marketDataView(ScenarioMarketData marketData) { + return DefaultOvernightFutureOptionScenarioMarketData.of(this, marketData); + } + + /** + * Obtains a filtered view of the complete set of market data. + *

+ * This method returns an instance that binds the lookup to the market data. + * The input is {@link MarketData}, which contains market data for one scenario. + * + * @param marketData the complete set of market data for one scenario + * @return the filtered market data + */ + public default OvernightFutureOptionMarketData marketDataView(MarketData marketData) { + return DefaultOvernightFutureOptionMarketData.of(this, marketData); + } + + //------------------------------------------------------------------------- + /** + * Obtains Overnight future option volatilities based on the specified market data. + *

+ * This provides {@link OvernightFutureOptionVolatilities} suitable for pricing an Overnight future option. + * Although this method can be used directly, it is typically invoked indirectly + * via {@link OvernightFutureOptionMarketData}: + *

+   *  // bind the baseData to this lookup
+   *  OvernightFutureOptionMarketData view = lookup.marketDataView(baseData);
+   *
+   *  // pass around OvernightFutureOptionMarketData within the function to use in pricing
+   *  OvernightFutureOptionVolatilities vols = view.volatilities(index);
+   * 
+ * + * @param index the Overnight index + * @param marketData the complete set of market data for one scenario + * @return the volatilities + * @throws MarketDataNotFoundException if the index is not found + */ + public abstract OvernightFutureOptionVolatilities volatilities(OvernightIndex index, MarketData marketData); + +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionScenarioMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionScenarioMarketData.java new file mode 100644 index 0000000000..f0ac64ac04 --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionScenarioMarketData.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import com.opengamma.strata.data.scenario.ScenarioMarketData; + +/** + * Market data for Overnight future options, used for calculation across multiple scenarios. + *

+ * This interface exposes the market data necessary for pricing an Overnight future option. + *

+ * Implementations of this interface must be immutable. + */ +public interface OvernightFutureOptionScenarioMarketData { + + /** + * Gets the lookup that provides access to Overnight future option volatilities. + * + * @return the Overnight future option lookup + */ + public abstract OvernightFutureOptionMarketDataLookup getLookup(); + + /** + * Gets the market data. + * + * @return the market data + */ + public abstract ScenarioMarketData getMarketData(); + + /** + * Returns a copy of this instance with the specified market data. + * + * @param marketData the market data to use + * @return a market view based on the specified data + */ + public abstract OvernightFutureOptionScenarioMarketData withMarketData(ScenarioMarketData marketData); + + //------------------------------------------------------------------------- + /** + * Gets the number of scenarios. + * + * @return the number of scenarios + */ + public abstract int getScenarioCount(); + + /** + * Returns market data for a single scenario. + *

+ * This returns a view of the market data for the specified scenario. + * + * @param scenarioIndex the scenario index + * @return the market data for the specified scenario + * @throws IndexOutOfBoundsException if the scenario index is invalid + */ + public abstract OvernightFutureOptionMarketData scenario(int scenarioIndex); + +} diff --git a/modules/measure/src/test/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookupTest.java b/modules/measure/src/test/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookupTest.java new file mode 100644 index 0000000000..a05ea88848 --- /dev/null +++ b/modules/measure/src/test/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookupTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import static com.opengamma.strata.basics.index.OvernightIndices.GBP_SONIA; +import static com.opengamma.strata.basics.index.OvernightIndices.USD_FED_FUND; +import static com.opengamma.strata.basics.index.OvernightIndices.USD_SOFR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.collect.TestHelper.date; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.time.LocalDate; + +import org.joda.beans.ImmutableBean; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.calc.runner.FunctionRequirements; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.scenario.ScenarioMarketData; +import com.opengamma.strata.measure.curve.TestMarketDataMap; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilitiesId; + +/** + * Test {@link OvernightFutureOptionMarketDataLookup}. + */ +public class OvernightFutureOptionMarketDataLookupTest { + + private static final OvernightFutureOptionVolatilitiesId VOL_ID1 = OvernightFutureOptionVolatilitiesId.of("USD1"); + private static final OvernightFutureOptionVolatilities MOCK_VOLS = mock(OvernightFutureOptionVolatilities.class); + private static final MarketData MOCK_MARKET_DATA = mock(MarketData.class); + private static final ScenarioMarketData MOCK_CALC_MARKET_DATA = mock(ScenarioMarketData.class); + + static { + when(MOCK_MARKET_DATA.getValue(VOL_ID1)).thenReturn(MOCK_VOLS); + } + + //------------------------------------------------------------------------- + @Test + public void test_of_single() { + OvernightFutureOptionMarketDataLookup test = OvernightFutureOptionMarketDataLookup.of(USD_SOFR, VOL_ID1); + assertThat(test.queryType()).isEqualTo(OvernightFutureOptionMarketDataLookup.class); + assertThat(test.getVolatilityIndices()).containsOnly(USD_SOFR); + assertThat(test.getVolatilityIds(USD_SOFR)).containsOnly(VOL_ID1); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.getVolatilityIds(GBP_SONIA)); + + assertThat(test.requirements(USD_SOFR)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThat(test.requirements(ImmutableSet.of(USD_SOFR))) + .isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.requirements(ImmutableSet.of(GBP_SONIA))); + } + + @Test + public void test_of_map() { + ImmutableMap ids = + ImmutableMap.of(USD_SOFR, VOL_ID1, USD_FED_FUND, VOL_ID1); + OvernightFutureOptionMarketDataLookup test = OvernightFutureOptionMarketDataLookup.of(ids); + assertThat(test.queryType()).isEqualTo(OvernightFutureOptionMarketDataLookup.class); + assertThat(test.getVolatilityIndices()).containsOnly(USD_SOFR, USD_FED_FUND); + assertThat(test.getVolatilityIds(USD_SOFR)).containsOnly(VOL_ID1); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.getVolatilityIds(GBP_SONIA)); + + assertThat(test.requirements(USD_SOFR)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThat(test.requirements(ImmutableSet.of(USD_SOFR))) + .isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.requirements(ImmutableSet.of(GBP_SONIA))); + + assertThat(test.volatilities(USD_SOFR, MOCK_MARKET_DATA)).isEqualTo(MOCK_VOLS); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.volatilities(GBP_SONIA, MOCK_MARKET_DATA)); + } + + //------------------------------------------------------------------------- + @Test + public void test_marketDataView() { + OvernightFutureOptionMarketDataLookup test = OvernightFutureOptionMarketDataLookup.of(USD_SOFR, VOL_ID1); + LocalDate valDate = date(2015, 6, 30); + ScenarioMarketData md = new TestMarketDataMap(valDate, ImmutableMap.of(), ImmutableMap.of()); + OvernightFutureOptionScenarioMarketData multiScenario = test.marketDataView(md); + assertThat(multiScenario.getLookup()).isEqualTo(test); + assertThat(multiScenario.getMarketData()).isEqualTo(md); + assertThat(multiScenario.getScenarioCount()).isEqualTo(1); + OvernightFutureOptionMarketData scenario = multiScenario.scenario(0); + assertThat(scenario.getLookup()).isEqualTo(test); + assertThat(scenario.getMarketData()).isEqualTo(md.scenario(0)); + assertThat(scenario.getValuationDate()).isEqualTo(valDate); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + DefaultOvernightFutureOptionMarketDataLookup test = + DefaultOvernightFutureOptionMarketDataLookup.of(ImmutableMap.of(USD_SOFR, VOL_ID1, USD_FED_FUND, VOL_ID1)); + coverImmutableBean(test); + DefaultOvernightFutureOptionMarketDataLookup test2 = DefaultOvernightFutureOptionMarketDataLookup.of(USD_SOFR, VOL_ID1); + coverBeanEquals(test, test2); + + coverImmutableBean((ImmutableBean) test.marketDataView(MOCK_CALC_MARKET_DATA)); + coverImmutableBean((ImmutableBean) test.marketDataView(MOCK_MARKET_DATA)); + } + + @Test + public void test_serialization() { + DefaultOvernightFutureOptionMarketDataLookup test = + DefaultOvernightFutureOptionMarketDataLookup.of(ImmutableMap.of(USD_SOFR, VOL_ID1, USD_FED_FUND, VOL_ID1)); + assertSerialization(test); + } + +}