/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.option.definition.twoasset; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.Validate; import org.threeten.bp.ZonedDateTime; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.model.volatility.surface.VolatilitySurface; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.DoublesPair; /** * The standard data required to price two-asset options. */ public class StandardTwoAssetOptionDataBundle { private final YieldAndDiscountCurve _interestRateCurve; private final VolatilitySurface _volatilitySurface1; private final VolatilitySurface _volatilitySurface2; private final double _b1; private final double _b2; private final double _spot1; private final double _spot2; private final double _rho; private final ZonedDateTime _date; /** * * @param interestRateCurve The interest rate curve (expects the x-axis to be time and the y-axis to be rate) * @param b1 The cost-of-carry of the first asset * @param b2 The cost-of-carry of the second asset * @param volatilitySurface1 The volatility surface for the option on the first underlying (expects the x-axis to be time, the y-axis to be strike and the z-axis to be volatility) * @param volatilitySurface2 The volatility surface for the option on the second underlying (expects the x-axis to be time, the y-axis to be strike and the z-axis to be volatility) * @param spot1 The spot value of the first underlying * @param spot2 The spot value of the second underlying * @param rho The correlation between the spot rates of the underlying * @param date The date of this data * @throws IllegalArgumentException If $\rho < -1$ or $\rho > 1$ */ public StandardTwoAssetOptionDataBundle(final YieldAndDiscountCurve interestRateCurve, final double b1, final double b2, final VolatilitySurface volatilitySurface1, final VolatilitySurface volatilitySurface2, final double spot1, final double spot2, final double rho, final ZonedDateTime date) { if (!ArgumentChecker.isInRangeInclusive(-1, 1, rho)) { throw new IllegalArgumentException("Correlation must be between -1 and 1"); } _interestRateCurve = interestRateCurve; _b1 = b1; _b2 = b2; _volatilitySurface1 = volatilitySurface1; _volatilitySurface2 = volatilitySurface2; _spot1 = spot1; _spot2 = spot2; _rho = rho; _date = date; } /** * Copies the data from another two-asset option data bundle * @param other The data bundle * @throws IllegalArgumentException If the other data bundle is null */ public StandardTwoAssetOptionDataBundle(final StandardTwoAssetOptionDataBundle other) { Validate.notNull(other, "data bundle"); _interestRateCurve = other.getInterestRateCurve(); _b1 = other.getFirstCostOfCarry(); _b2 = other.getSecondCostOfCarry(); _volatilitySurface1 = other.getFirstVolatilitySurface(); _volatilitySurface2 = other.getSecondVolatilitySurface(); _spot1 = other.getFirstSpot(); _spot2 = other.getSecondSpot(); _rho = other.getCorrelation(); _date = other.getDate(); } /** * Gets the interest rate as a decimal * @param t The time to expiry * @return The interest rate */ public double getInterestRate(final double t) { return getInterestRateCurve().getInterestRate(t); } /** * Gets the cost of carry of the first asset as a decimal * @return The cost of carry */ public double getFirstCostOfCarry() { return _b1; } /** * Gets the cost of carry of the second asset as a decimal * @return The cost of carry */ public double getSecondCostOfCarry() { return _b2; } /** * Gets the volatility of the first asset as a decimal * @param timeToExpiry The time to expiry * @param strike The strike * @return The volatility */ public double getFirstVolatility(final double timeToExpiry, final double strike) { return getFirstVolatilitySurface().getVolatility(DoublesPair.of(timeToExpiry, strike)); } /** * Gets the volatility of the second asset as a decimal * @param timeToExpiry The time to expiry * @param strike The strike * @return The volatility */ public double getSecondVolatility(final double timeToExpiry, final double strike) { return getSecondVolatilitySurface().getVolatility(DoublesPair.of(timeToExpiry, strike)); } /** * * @return The spot value of the first asset */ public double getFirstSpot() { return _spot1; } /** * * @return The spot value of the second asset */ public double getSecondSpot() { return _spot2; } /** * * @return The interest rate curve */ public YieldAndDiscountCurve getInterestRateCurve() { return _interestRateCurve; } /** * * @return The volatility surface for the first asset */ public VolatilitySurface getFirstVolatilitySurface() { return _volatilitySurface1; } /** * * @return The volatility surface for the second asset */ public VolatilitySurface getSecondVolatilitySurface() { return _volatilitySurface2; } /** * * @return The correlation of the spot prices of the first and second asset */ public double getCorrelation() { return _rho; } /** * * @return The date for which the data are valid */ public ZonedDateTime getDate() { return _date; } /** * Returns a new data bundle with the interest rate curve replaced by the argument * @param interestRateCurve The new interest rate curve * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withInterestRateCurve(final YieldAndDiscountCurve interestRateCurve) { return new StandardTwoAssetOptionDataBundle(interestRateCurve, getFirstCostOfCarry(), getSecondCostOfCarry(), getFirstVolatilitySurface(), getSecondVolatilitySurface(), getFirstSpot(), getSecondSpot(), getCorrelation(), getDate()); } /** * Returns a new data bundle with the cost of carry of the first asset replaced by the argument * @param costOfCarry The new cost of carry * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withFirstCostOfCarry(final double costOfCarry) { return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), costOfCarry, getSecondCostOfCarry(), getFirstVolatilitySurface(), getSecondVolatilitySurface(), getFirstSpot(), getSecondSpot(), getCorrelation(), getDate()); } /** * Returns a new data bundle with the cost of carry of the second asset replaced by the argument * @param costOfCarry The new cost of carry * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withSecondCostOfCarry(final double costOfCarry) { return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), getFirstCostOfCarry(), costOfCarry, getFirstVolatilitySurface(), getSecondVolatilitySurface(), getFirstSpot(), getSecondSpot(), getCorrelation(), getDate()); } /** * Returns a new data bundle with the volatility surface of the first asset replaced by the argument * @param volatilitySurface The new volatility surface * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withFirstVolatilitySurface(final VolatilitySurface volatilitySurface) { return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), getFirstCostOfCarry(), getSecondCostOfCarry(), volatilitySurface, getSecondVolatilitySurface(), getFirstSpot(), getSecondSpot(), getCorrelation(), getDate()); } /** * Returns a new data bundle with the volatility surface of the second asset replaced by the argument * @param volatilitySurface The new volatility surface * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withSecondVolatilitySurface(final VolatilitySurface volatilitySurface) { return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), getFirstCostOfCarry(), getSecondCostOfCarry(), getFirstVolatilitySurface(), volatilitySurface, getFirstSpot(), getSecondSpot(), getCorrelation(), getDate()); } /** * Returns a new data bundle with the spot value of the first asset replaced by the argument * @param spot The new spot * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withFirstSpot(final double spot) { return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), getFirstCostOfCarry(), getSecondCostOfCarry(), getFirstVolatilitySurface(), getSecondVolatilitySurface(), spot, getSecondSpot(), getCorrelation(), getDate()); } /** * Returns a new data bundle with the spot value of the second asset replaced by the argument * @param spot The new spot * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withSecondSpot(final double spot) { return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), getFirstCostOfCarry(), getSecondCostOfCarry(), getFirstVolatilitySurface(), getSecondVolatilitySurface(), getFirstSpot(), spot, getCorrelation(), getDate()); } /** * Returns a new data bundle with the correlation between the two spot prices replaced by the argument * @param correlation The correlation * @return The new data bundle * @throws IllegalArgumentException If $\rho < -1$ or $\rho > 1$ */ public StandardTwoAssetOptionDataBundle withCorrelation(final double correlation) { if (!ArgumentChecker.isInRangeInclusive(-1, 1, correlation)) { throw new IllegalArgumentException("Correlation must be between 0 and 1"); } return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), getFirstCostOfCarry(), getSecondCostOfCarry(), getFirstVolatilitySurface(), getSecondVolatilitySurface(), getFirstSpot(), getSecondSpot(), correlation, getDate()); } /** * Returns a new data bundle with the date replaced by the argument * @param date The date * @return The new data bundle */ public StandardTwoAssetOptionDataBundle withDate(final ZonedDateTime date) { return new StandardTwoAssetOptionDataBundle(getInterestRateCurve(), getFirstCostOfCarry(), getSecondCostOfCarry(), getFirstVolatilitySurface(), getSecondVolatilitySurface(), getFirstSpot(), getSecondSpot(), getCorrelation(), date); } @Override public int hashCode() { final int prime = 31; int result = 1; long temp; temp = Double.doubleToLongBits(_b1); result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(_b2); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((_date == null) ? 0 : _date.hashCode()); result = prime * result + ((_interestRateCurve == null) ? 0 : _interestRateCurve.hashCode()); temp = Double.doubleToLongBits(_rho); result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(_spot1); result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(_spot2); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((_volatilitySurface1 == null) ? 0 : _volatilitySurface1.hashCode()); result = prime * result + ((_volatilitySurface2 == null) ? 0 : _volatilitySurface2.hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final StandardTwoAssetOptionDataBundle other = (StandardTwoAssetOptionDataBundle) obj; if (Double.doubleToLongBits(_b1) != Double.doubleToLongBits(other._b1)) { return false; } if (Double.doubleToLongBits(_b2) != Double.doubleToLongBits(other._b2)) { return false; } if (!ObjectUtils.equals(_date, other._date)) { return false; } if (!ObjectUtils.equals(_interestRateCurve, other._interestRateCurve)) { return false; } if (Double.doubleToLongBits(_rho) != Double.doubleToLongBits(other._rho)) { return false; } if (Double.doubleToLongBits(_spot1) != Double.doubleToLongBits(other._spot1)) { return false; } if (Double.doubleToLongBits(_spot2) != Double.doubleToLongBits(other._spot2)) { return false; } if (!ObjectUtils.equals(_volatilitySurface1, other._volatilitySurface1)) { return false; } if (!ObjectUtils.equals(_volatilitySurface2, other._volatilitySurface2)) { return false; } return true; } }