/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.option.pricing.tree; import org.apache.commons.lang.NotImplementedException; import com.google.common.primitives.Doubles; import com.opengamma.util.ArgumentChecker; /** * Option function provider for in(out) barrier option * In(Out) option comes into existence (becomes worthless) if the asset price hits the barrier */ public abstract class BarrierOptionFunctionProvider extends OptionFunctionProvider1D { /** * Use these strings to specify barrier option type. * DownAndIn and UpAndIn MUST be computed via in-out parity if the option is European */ public static enum BarrierTypes { /** * Down-and-out option */ DownAndOut, /** * Up-and-out option */ UpAndOut, /** * Down-and-in option, not implemented */ DownAndIn, /** * Up-and-in option, not implemented */ UpAndIn, /** * Up-and-Out-Down-and-Out */ DoubleKnockOut, /** * Up-and-In-Down-and-In, not implemented * Knock-in type should be priced by another model */ DoubleKnockIn } private double _barrier; private CrossBarrierChecker _checker; /** * Constructor * @param strike The strike price * @param timeToExpiry Time to expiry * @param steps The number of steps * @param isCall True if call option, false if put option * @param barrier The barrier price * @param typeName Type of barrier option */ public BarrierOptionFunctionProvider(final double strike, final double timeToExpiry, final int steps, final boolean isCall, final double barrier, final BarrierTypes typeName) { super(strike, timeToExpiry, steps, isCall); ArgumentChecker.isTrue(barrier > 0., "barrier should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(barrier), "barrier should be finite"); _barrier = barrier; switch (typeName) { case DownAndOut: _checker = new CrossLowerBarrier(); break; case UpAndOut: _checker = new CrossUpperBarrier(); break; default: throw new NotImplementedException(); } } /** * Access cross barrier checker * @return _checker */ public CrossBarrierChecker getChecker() { return _checker; } /** * Access barrier * @return _barrier */ public double getBarrier() { return _barrier; } /** * Barrier type * @return DownAndOut or UpAndOut */ public BarrierTypes getBarrierType() { return _checker instanceof CrossLowerBarrier ? BarrierTypes.DownAndOut : BarrierTypes.UpAndOut; } /** * The protected class checks barrier crossing */ protected abstract class CrossBarrierChecker { /** * @param priceTmp The asset price * @return True if asset price crosses the barrier */ public abstract boolean checkOut(final double priceTmp); /** * When strike is behind the barrier, payoff will never be in-the-money, depending on Call or Put * @return True if option price is trivially 0 */ public abstract boolean checkStrikeBehindBarrier(); } /** * The inherited class checks lower barrier crossing for down-and-out option */ @SuppressWarnings("synthetic-access") protected class CrossLowerBarrier extends CrossBarrierChecker { @Override public boolean checkOut(final double priceTmp) { return (priceTmp <= _barrier); } @Override public boolean checkStrikeBehindBarrier() { return getSign() == 1. ? false : (_barrier >= getStrike()); } @Override public int hashCode() { return 1; } @Override public boolean equals(Object obj) { if (!(obj instanceof CrossLowerBarrier)) { return false; } return true; } } /** * The inherited class checks upper barrier crossing for up-and-out option */ @SuppressWarnings("synthetic-access") protected class CrossUpperBarrier extends CrossBarrierChecker { @Override public boolean checkOut(final double priceTmp) { return priceTmp >= _barrier; } @Override public boolean checkStrikeBehindBarrier() { return getSign() == 1. ? (_barrier <= getStrike()) : false; } @Override public int hashCode() { return 2; } @Override public boolean equals(Object obj) { if (!(obj instanceof CrossUpperBarrier)) { return false; } return true; } } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); long temp; temp = Double.doubleToLongBits(_barrier); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((_checker == null) ? 0 : _checker.hashCode()); return result; } @Override public boolean equals(Object obj) { if (!super.equals(obj)) { return false; } if (!(obj instanceof BarrierOptionFunctionProvider)) { return false; } BarrierOptionFunctionProvider other = (BarrierOptionFunctionProvider) obj; if (Double.doubleToLongBits(_barrier) != Double.doubleToLongBits(other._barrier)) { return false; } if (!_checker.equals(other._checker)) { return false; } return true; } }