com.opengamma.strata.pricer.option.RawOptionData Maven / Gradle / Ivy
/*
* Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.pricer.option;
import java.io.Serializable;
import java.lang.invoke.MethodHandles;
import java.time.Period;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.OptionalDouble;
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.ImmutableList;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.collect.tuple.Pair;
import com.opengamma.strata.market.ValueType;
/**
* Raw data from the volatility market.
*/
@BeanDefinition(style = "light")
public final class RawOptionData
implements ImmutableBean, Serializable {
/**
* The expiry values.
*/
@PropertyDefinition(validate = "notNull")
private final ImmutableList expiries;
/**
* The strike values. Can be directly strike or moneyness (simple or log)
*/
@PropertyDefinition(validate = "notNull")
private final DoubleArray strikes;
/**
* The value type of the strike-like dimension.
*/
@PropertyDefinition(validate = "notNull")
private final ValueType strikeType;
/**
* The data. The values can be model parameters (like Black or normal volatilities) or direct
* option prices. The first (outer) dimension is the expiry, the second dimension is the strike.
* A 'NaN' value indicates that the data is not available.
*/
@PropertyDefinition(validate = "notNull")
private final DoubleMatrix data;
/**
* The measurement error of the option data.
*
* These will be used if the option data is calibrated by a least square method.
* {@code data} and {@code error} must have the same number of elements.
*/
@PropertyDefinition(get = "optional")
private final DoubleMatrix error;
/**
* The type of the raw data.
*/
@PropertyDefinition(validate = "notNull")
private final ValueType dataType;
/**
* The shift for which the raw data is valid. Used only if the dataType is 'BlackVolatility'.
*/
@PropertyDefinition(get = "optional")
private final Double shift;
//-------------------------------------------------------------------------
/**
* Obtains an instance of the raw volatility.
*
* The data values can be model parameters (like Black or normal volatilities) or direct option prices.
*
* @param expiries the expiries
* @param strikes the strikes-like data
* @param strikeType the value type of the strike-like dimension
* @param data the data
* @param dataType the data type
* @return the instance
*/
public static RawOptionData of(
List expiries,
DoubleArray strikes,
ValueType strikeType,
DoubleMatrix data,
ValueType dataType) {
ArgChecker.isTrue(expiries.size() == data.rowCount(),
"expiries list should be of the same size as the external data dimension");
for (int i = 0; i < expiries.size(); i++) {
ArgChecker.isTrue(strikes.size() == data.columnCount(),
"strikes should be of the same size as the inner data dimension");
}
return new RawOptionData(expiries, strikes, strikeType, data, null, dataType, 0.0);
}
/**
* Obtains an instance of the raw volatility for shifted Black (log-normal) volatility.
*
* @param expiries the expiries
* @param strikes the strikes-like data
* @param strikeType the value type of the strike-like dimension
* @param data the data
* @param shift the shift
* @return the instance
*/
public static RawOptionData ofBlackVolatility(
List expiries,
DoubleArray strikes,
ValueType strikeType,
DoubleMatrix data,
Double shift) {
ArgChecker.isTrue(expiries.size() == data.rowCount(),
"expiries list should be of the same size as the external data dimension");
for (int i = 0; i < expiries.size(); i++) {
ArgChecker.isTrue(strikes.size() == data.columnCount(),
"strikes should be of the same size as the inner data dimension");
}
return new RawOptionData(expiries, strikes, strikeType, data, null, ValueType.BLACK_VOLATILITY, shift);
}
/**
* Obtains an instance of the raw data with error.
*
* The data values can be model parameters (like Black or normal volatilities) or direct option prices.
*
* @param expiries the expiries
* @param strikes the strikes-like data
* @param strikeType the value type of the strike-like dimension
* @param data the data
* @param error the error
* @param dataType the data type
* @return the instance
*/
public static RawOptionData of(
List expiries,
DoubleArray strikes,
ValueType strikeType,
DoubleMatrix data,
DoubleMatrix error,
ValueType dataType) {
ArgChecker.isTrue(expiries.size() == data.rowCount(),
"expiries list should be of the same size as the external data dimension");
ArgChecker.isTrue(error.rowCount() == data.rowCount(),
"the error row count should be the same as the data raw count");
ArgChecker.isTrue(error.columnCount() == data.columnCount(),
"the error column count should the same as the data column count");
for (int i = 0; i < expiries.size(); i++) {
ArgChecker.isTrue(strikes.size() == data.columnCount(),
"strikes should be of the same size as the inner data dimension");
}
return new RawOptionData(expiries, strikes, strikeType, data, error, dataType, 0.0);
}
/**
* Obtains an instance of the raw data with error for shifted Black (log-normal) volatility.
*
* @param expiries the expiries
* @param strikes the strikes-like data
* @param strikeType the value type of the strike-like dimension
* @param data the data
* @param error the error
* @param shift the shift
* @return the instance
*/
public static RawOptionData ofBlackVolatility(
List expiries,
DoubleArray strikes,
ValueType strikeType,
DoubleMatrix data,
DoubleMatrix error,
Double shift) {
ArgChecker.isTrue(expiries.size() == data.rowCount(),
"expiries list should be of the same size as the external data dimension");
for (int i = 0; i < expiries.size(); i++) {
ArgChecker.isTrue(strikes.size() == data.columnCount(),
"strikes should be of the same size as the inner data dimension");
}
return new RawOptionData(expiries, strikes, strikeType, data, error, ValueType.BLACK_VOLATILITY, shift);
}
//-------------------------------------------------------------------------
/**
* For a given expiration returns all the data available.
*
* @param expiry the expiration
* @return the strikes and related volatilities for all available data at the given expiration
*/
public Pair availableSmileAtExpiry(Period expiry) {
int index = expiries.indexOf(expiry);
ArgChecker.isTrue(index >= 0, "expiry not available");
List strikesAvailable = new ArrayList<>();
List volatilitiesAvailable = new ArrayList<>();
for (int i = 0; i < strikes.size(); i++) {
if (!Double.isNaN(data.get(index, i))) {
strikesAvailable.add(strikes.get(i));
volatilitiesAvailable.add(data.get(index, i));
}
}
return Pair.of(DoubleArray.copyOf(strikesAvailable), DoubleArray.copyOf(volatilitiesAvailable));
}
//------------------------- AUTOGENERATED START -------------------------
/**
* The meta-bean for {@code RawOptionData}.
*/
private static final TypedMetaBean META_BEAN =
LightMetaBean.of(
RawOptionData.class,
MethodHandles.lookup(),
new String[] {
"expiries",
"strikes",
"strikeType",
"data",
"error",
"dataType",
"shift"},
ImmutableList.of(),
null,
null,
null,
null,
null,
null);
/**
* The meta-bean for {@code RawOptionData}.
* @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 RawOptionData(
List expiries,
DoubleArray strikes,
ValueType strikeType,
DoubleMatrix data,
DoubleMatrix error,
ValueType dataType,
Double shift) {
JodaBeanUtils.notNull(expiries, "expiries");
JodaBeanUtils.notNull(strikes, "strikes");
JodaBeanUtils.notNull(strikeType, "strikeType");
JodaBeanUtils.notNull(data, "data");
JodaBeanUtils.notNull(dataType, "dataType");
this.expiries = ImmutableList.copyOf(expiries);
this.strikes = strikes;
this.strikeType = strikeType;
this.data = data;
this.error = error;
this.dataType = dataType;
this.shift = shift;
}
@Override
public TypedMetaBean metaBean() {
return META_BEAN;
}
//-----------------------------------------------------------------------
/**
* Gets the expiry values.
* @return the value of the property, not null
*/
public ImmutableList getExpiries() {
return expiries;
}
//-----------------------------------------------------------------------
/**
* Gets the strike values. Can be directly strike or moneyness (simple or log)
* @return the value of the property, not null
*/
public DoubleArray getStrikes() {
return strikes;
}
//-----------------------------------------------------------------------
/**
* Gets the value type of the strike-like dimension.
* @return the value of the property, not null
*/
public ValueType getStrikeType() {
return strikeType;
}
//-----------------------------------------------------------------------
/**
* Gets the data. The values can be model parameters (like Black or normal volatilities) or direct
* option prices. The first (outer) dimension is the expiry, the second dimension is the strike.
* A 'NaN' value indicates that the data is not available.
* @return the value of the property, not null
*/
public DoubleMatrix getData() {
return data;
}
//-----------------------------------------------------------------------
/**
* Gets the measurement error of the option data.
*
* These will be used if the option data is calibrated by a least square method.
* {@code data} and {@code error} must have the same number of elements.
* @return the optional value of the property, not null
*/
public Optional getError() {
return Optional.ofNullable(error);
}
//-----------------------------------------------------------------------
/**
* Gets the type of the raw data.
* @return the value of the property, not null
*/
public ValueType getDataType() {
return dataType;
}
//-----------------------------------------------------------------------
/**
* Gets the shift for which the raw data is valid. Used only if the dataType is 'BlackVolatility'.
* @return the optional value of the property, not null
*/
public OptionalDouble getShift() {
return shift != null ? OptionalDouble.of(shift) : OptionalDouble.empty();
}
//-----------------------------------------------------------------------
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj != null && obj.getClass() == this.getClass()) {
RawOptionData other = (RawOptionData) obj;
return JodaBeanUtils.equal(expiries, other.expiries) &&
JodaBeanUtils.equal(strikes, other.strikes) &&
JodaBeanUtils.equal(strikeType, other.strikeType) &&
JodaBeanUtils.equal(data, other.data) &&
JodaBeanUtils.equal(error, other.error) &&
JodaBeanUtils.equal(dataType, other.dataType) &&
JodaBeanUtils.equal(shift, other.shift);
}
return false;
}
@Override
public int hashCode() {
int hash = getClass().hashCode();
hash = hash * 31 + JodaBeanUtils.hashCode(expiries);
hash = hash * 31 + JodaBeanUtils.hashCode(strikes);
hash = hash * 31 + JodaBeanUtils.hashCode(strikeType);
hash = hash * 31 + JodaBeanUtils.hashCode(data);
hash = hash * 31 + JodaBeanUtils.hashCode(error);
hash = hash * 31 + JodaBeanUtils.hashCode(dataType);
hash = hash * 31 + JodaBeanUtils.hashCode(shift);
return hash;
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(256);
buf.append("RawOptionData{");
buf.append("expiries").append('=').append(JodaBeanUtils.toString(expiries)).append(',').append(' ');
buf.append("strikes").append('=').append(JodaBeanUtils.toString(strikes)).append(',').append(' ');
buf.append("strikeType").append('=').append(JodaBeanUtils.toString(strikeType)).append(',').append(' ');
buf.append("data").append('=').append(JodaBeanUtils.toString(data)).append(',').append(' ');
buf.append("error").append('=').append(JodaBeanUtils.toString(error)).append(',').append(' ');
buf.append("dataType").append('=').append(JodaBeanUtils.toString(dataType)).append(',').append(' ');
buf.append("shift").append('=').append(JodaBeanUtils.toString(shift));
buf.append('}');
return buf.toString();
}
//-------------------------- AUTOGENERATED END --------------------------
}