/**
* 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;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.model.option.pricing.analytic.BlackScholesMertonModel;
import com.opengamma.util.time.Expiry;
/**
*
*/
public class EuropeanOptionOnEuropeanVanillaOptionDefinition extends OptionDefinition {
private static final BlackScholesMertonModel UNDERLYING_MODEL = new BlackScholesMertonModel();
private final OptionExerciseFunction<StandardOptionDataBundle> _exerciseFunction = new EuropeanExerciseFunction<>();
private final OptionPayoffFunction<StandardOptionDataBundle> _payoffFunction = new OptionPayoffFunction<StandardOptionDataBundle>() {
@SuppressWarnings("synthetic-access")
@Override
public double getPayoff(final StandardOptionDataBundle data, final Double optionPrice) {
Validate.notNull(data, "data");
final double underlyingPrice = UNDERLYING_MODEL.getPricingFunction(_underlyingOption).evaluate(data);
return isCall() ? Math.max(underlyingPrice - getStrike(), 0) : Math.max(getStrike() - underlyingPrice, 0);
}
};
private final EuropeanVanillaOptionDefinition _underlyingOption;
public EuropeanOptionOnEuropeanVanillaOptionDefinition(final double strike, final Expiry expiry, final boolean isCall, final double underlyingStrike, final Expiry underlyingExpiry,
final boolean isUnderlyingCall) {
this(strike, expiry, isCall, new EuropeanVanillaOptionDefinition(underlyingStrike, underlyingExpiry, isUnderlyingCall));
}
public EuropeanOptionOnEuropeanVanillaOptionDefinition(final double strike, final Expiry expiry, final boolean isCall, final EuropeanVanillaOptionDefinition underlyingOption) {
super(strike, expiry, isCall);
Validate.notNull(underlyingOption, "underlying definition");
if (expiry.getExpiry().isAfter(underlyingOption.getExpiry().getExpiry())) {
throw new IllegalArgumentException("Underlying option expiry must be after option expiry");
}
_underlyingOption = underlyingOption;
}
@Override
public OptionExerciseFunction<StandardOptionDataBundle> getExerciseFunction() {
return _exerciseFunction;
}
@Override
public OptionPayoffFunction<StandardOptionDataBundle> getPayoffFunction() {
return _payoffFunction;
}
public OptionDefinition getUnderlyingOption() {
return _underlyingOption;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + ((_underlyingOption == null) ? 0 : _underlyingOption.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final EuropeanOptionOnEuropeanVanillaOptionDefinition other = (EuropeanOptionOnEuropeanVanillaOptionDefinition) obj;
return ObjectUtils.equals(_underlyingOption, other._underlyingOption);
}
}