com.opengamma.analytics.financial.model.option.definition.ComplexChooserOptionDefinition.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.option.definition.ComplexChooserOptionDefinition.java

Source

/**
 * 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 java.util.Collections;
import java.util.Set;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.Validate;
import org.threeten.bp.ZonedDateTime;

import com.opengamma.analytics.financial.greeks.Greek;
import com.opengamma.analytics.financial.model.option.pricing.analytic.AnalyticOptionModel;
import com.opengamma.analytics.financial.model.option.pricing.analytic.BlackScholesMertonModel;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.time.Expiry;

/**
 * A complex chooser option gives the holder the right to choose whether the
 * option is to be a standard call or put after a certain time. The exercise
 * style of the option, once the choice has been made, is European.
 * <p>
 * The payoff from the option with strike <i>K</i> and spot <i>S</i> is
 * <i>max(c<sub>BSM</i>(S, K, T<sub>C</sub>), p<sub>BSM</sub>(S, K,
 * T<sub>P</sub>)</i>, where <i>C<sub>BSM</sub></i> is the Black-Scholes-Merton
 * call price, <i>P<sub>BSM</sub></i> is the Black-Scholes-Merton put price,
 * <i>T<sub>C</sub></i> is the time to maturity of the call and
 * <i>T<sub>P</sub></i> is the time to maturity of the put.
 * 
 */
public class ComplexChooserOptionDefinition extends OptionDefinition {
    private final OptionPayoffFunction<StandardOptionDataBundle> _payoffFunction = new OptionPayoffFunction<StandardOptionDataBundle>() {

        @SuppressWarnings("synthetic-access")
        @Override
        public double getPayoff(final StandardOptionDataBundle data, final Double optionPrice) {
            final double callPrice = BSM.getGreeks(getCallDefinition(), data, GREEKS).get(Greek.FAIR_PRICE);
            final double putPrice = BSM.getGreeks(getPutDefinition(), data, GREEKS).get(Greek.FAIR_PRICE);
            return Math.max(callPrice, putPrice);
        }
    };
    private final OptionExerciseFunction<StandardOptionDataBundle> _exerciseFunction = new EuropeanExerciseFunction<>();
    private final double _callStrike;
    private final double _putStrike;
    private final Expiry _callExpiry;
    private final Expiry _putExpiry;
    private final OptionDefinition _callDefinition;
    private final OptionDefinition _putDefinition;
    private static final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> BSM = new BlackScholesMertonModel();
    private static final Set<Greek> GREEKS = Collections.singleton(Greek.FAIR_PRICE);

    /**
     * 
     * @param callStrike The strike of the potential call option
     * @param putStrike The strike of the potential put option
     * @param chooseDate The choice date (expiry) of the chooser option
     * @param callExpiry The expiry date of the potential call option
     * @param putExpiry The expiry date of the potential put option
     */
    public ComplexChooserOptionDefinition(final Expiry chooseDate, final double callStrike, final Expiry callExpiry,
            final double putStrike, final Expiry putExpiry) {
        super(null, chooseDate, null);
        Validate.notNull(callExpiry);
        Validate.notNull(putExpiry);
        ArgumentChecker.notNegative(callStrike, "call strike");
        ArgumentChecker.notNegative(putStrike, "put strike");
        if (callExpiry.getExpiry().isBefore(chooseDate.getExpiry())) {
            throw new IllegalArgumentException("Call expiry must be after the choose date");
        }
        if (putExpiry.getExpiry().isBefore(chooseDate.getExpiry())) {
            throw new IllegalArgumentException("Put expiry must be after the choose date");
        }
        _callStrike = callStrike;
        _putStrike = putStrike;
        _callExpiry = callExpiry;
        _putExpiry = putExpiry;
        _callDefinition = new EuropeanVanillaOptionDefinition(callStrike, callExpiry, true);
        _putDefinition = new EuropeanVanillaOptionDefinition(putStrike, putExpiry, false);
    }

    public double getCallStrike() {
        return _callStrike;
    }

    public double getPutStrike() {
        return _putStrike;
    }

    public Expiry getCallExpiry() {
        return _callExpiry;
    }

    public Expiry getPutExpiry() {
        return _putExpiry;
    }

    public double getTimeToCallExpiry(final ZonedDateTime date) {
        if (date.isAfter(getCallExpiry().getExpiry())) {
            throw new IllegalArgumentException("Date " + date + " is after call expiry " + getCallExpiry());
        }
        return DateUtils.getDifferenceInYears(date, getCallExpiry().getExpiry());
    }

    public double getTimeToPutExpiry(final ZonedDateTime date) {
        if (date.isAfter(getPutExpiry().getExpiry())) {
            throw new IllegalArgumentException("Date " + date + " is after put expiry " + getPutExpiry());
        }
        return DateUtils.getDifferenceInYears(date, getPutExpiry().getExpiry());
    }

    public OptionDefinition getCallDefinition() {
        return _callDefinition;
    }

    public OptionDefinition getPutDefinition() {
        return _putDefinition;
    }

    @Override
    public OptionExerciseFunction<StandardOptionDataBundle> getExerciseFunction() {
        return _exerciseFunction;
    }

    @Override
    public OptionPayoffFunction<StandardOptionDataBundle> getPayoffFunction() {
        return _payoffFunction;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + ((_callExpiry == null) ? 0 : _callExpiry.hashCode());
        long temp;
        temp = Double.doubleToLongBits(_callStrike);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        result = prime * result + ((_putExpiry == null) ? 0 : _putExpiry.hashCode());
        temp = Double.doubleToLongBits(_putStrike);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        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 ComplexChooserOptionDefinition other = (ComplexChooserOptionDefinition) obj;
        if (Double.doubleToLongBits(_callStrike) != Double.doubleToLongBits(other._callStrike)) {
            return false;
        }
        if (Double.doubleToLongBits(_putStrike) != Double.doubleToLongBits(other._putStrike)) {
            return false;
        }
        return ObjectUtils.equals(_callExpiry, other._callExpiry)
                && ObjectUtils.equals(_putExpiry, other._putExpiry);
    }

}