package org.marketcetera.strategy.util;
import java.math.BigDecimal;
import javax.annotation.concurrent.ThreadSafe;
import org.marketcetera.event.HasProviderSymbol;
import org.marketcetera.event.OptionEvent;
import org.marketcetera.trade.Option;
import org.marketcetera.trade.OptionType;
import org.marketcetera.util.misc.ClassVersion;
/* $License$ */
/**
* Represents the put and call of a specific option and their most recent market data, if available.
*
* <p>The put and the call in this pair are guaranteed to be for the same symbol, expiry, and strike.
*
* @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a>
* @version $Id: OptionContractPair.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ThreadSafe
@ClassVersion("$Id: OptionContractPair.java 16154 2012-07-14 16:34:05Z colin $")
public final class OptionContractPair
implements Comparable<OptionContractPair>
{
/**
* Gets the put <code>OptionContract</code> value.
*
* @return an <code>OptionContract</code> value or <code>null</code>
*/
public OptionContract getPut()
{
return put;
}
/**
* Gets the call <code>OptionContract</code> value.
*
* @return an <code>OptionContract</code> value or <code>null</code>
*/
public OptionContract getCall()
{
return call;
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(OptionContractPair inPair)
{
return getKey().compareTo(inPair.getKey());
}
/* (non-Javadoc)
* @see org.marketcetera.core.Pair#equals(java.lang.Object)
*/
@Override
public boolean equals(Object inOther)
{
if(inOther == null) {
return false;
}
if(!(inOther instanceof OptionContractPair)) {
return false;
}
return compareTo((OptionContractPair)inOther) == 0;
}
/* (non-Javadoc)
* @see org.marketcetera.core.Pair#hashCode()
*/
@Override
public int hashCode()
{
// this implementation must be kept in sync with OptionContractPair#compareTo
final int prime = 31;
int result = 1;
if(getPut() == null &&
getCall() == null) {
return prime * result + 0;
}
Option option = getPut() == null ? getCall().getInstrument() : getPut().getInstrument();
result = prime * result + ((option == null || option.getSymbol() == null) ? 0 : option.getSymbol().hashCode());
result = prime * result + ((option == null || option.getExpiry() == null) ? 0 : option.getExpiry().hashCode());
result = prime * result + ((option == null || option.getStrikePrice() == null) ? 0 : option.getStrikePrice().hashCode());
return result;
}
/**
* Create a new OptionContractPair instance.
*
* @param inOptionEvent an <code>OptionEvent</code> value
* @throws IllegalArgumentException if <code>Instrument</code> is <code>null</code>
* @throws IllegalArgumentException if <code>UnderlyingInstrument</code> is <code>null</code>
* @throws IllegalArgumentException if <code>ExpirationType</code> is <code>null</code>
*/
OptionContractPair(OptionEvent inOptionEvent)
{
key = getOptionContractPairKey(inOptionEvent.getInstrument());
process(inOptionEvent);
}
/**
* Process the given <code>OptionEvent</code> to update one side of the
* option pair or the other.
*
* <p>The given <code>OptionEvent</code> is assumed to apply to this contract pair. The caller
* must ascertain that this is the correct contract pair to apply the event to. No further validation
* will be done; the values of the given event will be applied to the appropriate side of the contract
* pair.
*
* @param inOptionEvent an <code>OptionEvent</code> that pertains to this option contract pair
*/
synchronized boolean process(OptionEvent inOptionEvent)
{
if(inOptionEvent.getInstrument().getType() == OptionType.Call) {
if(call == null) {
call = new OptionContract(inOptionEvent.getUnderlyingInstrument(),
inOptionEvent.getInstrument(),
inOptionEvent.getInstrument().getType(),
inOptionEvent.getExpirationType(),
inOptionEvent.hasDeliverable(),
inOptionEvent.getMultiplier(),
inOptionEvent instanceof HasProviderSymbol ? ((HasProviderSymbol)inOptionEvent).getProviderSymbol() : null);
}
return call.process(inOptionEvent);
}
if(inOptionEvent.getInstrument().getType() == OptionType.Put) {
if(put == null) {
put = new OptionContract(inOptionEvent.getUnderlyingInstrument(),
inOptionEvent.getInstrument(),
inOptionEvent.getInstrument().getType(),
inOptionEvent.getExpirationType(),
inOptionEvent.hasDeliverable(),
inOptionEvent.getMultiplier(),
inOptionEvent instanceof HasProviderSymbol ? ((HasProviderSymbol)inOptionEvent).getProviderSymbol() : null);
}
return put.process(inOptionEvent);
}
throw new UnsupportedOperationException();
}
/**
* Gets an <code>OptionContractPairKey</code> corresponding to the given <code>Option</code>.
*
* @param inOption an <code>Option</code> value
* @return an <code>OptionContractPairKey</code> value
*/
static OptionContractPairKey getOptionContractPairKey(Option inOption)
{
return new OptionContractPairKey(inOption.getSymbol(),
inOption.getExpiry(),
inOption.getStrikePrice());
}
/**
* Gets the key for this object.
*
* @return an <code>OptionContractPairKey</code> value
*/
private OptionContractPairKey getKey()
{
return key;
}
/**
* the put contract, may be null
*/
private volatile OptionContract put;
/**
* the call contract, may be null
*/
private volatile OptionContract call;
/**
* the key of this object is the essential components of the {@link OptionContract} pair
*/
private final OptionContractPairKey key;
/**
* Encapsulates the components of an <code>OptionContractPair</code> that correspond to
* the unique key.
*
* @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a>
* @version $Id: OptionContractPair.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: OptionContractPair.java 16154 2012-07-14 16:34:05Z colin $")
static class OptionContractPairKey
implements Comparable<OptionContractPairKey>
{
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((symbol == null) ? 0 : symbol.hashCode());
result = prime * result + ((expiry == null) ? 0 : expiry.hashCode());
result = prime * result + ((strike == null) ? 0 : strike.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof OptionContractPairKey)) {
return false;
}
OptionContractPairKey other = (OptionContractPairKey) obj;
if (!symbol.equals(other.symbol)) {
return false;
}
if (!expiry.equals(other.expiry)) {
return false;
}
if (!strike.equals(other.strike)) {
return false;
}
return true;
}
/* (non-Javadoc)
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo(OptionContractPairKey inOther)
{
// this method must be kept in sync with OptionContractPair#hashCode
// key is option symbol, expiry, strike
int result = getSymbol().compareTo(inOther.getSymbol());
if(result != 0) {
return result;
}
result = getExpiry().compareTo(inOther.getExpiry());
if(result != 0) {
return result;
}
return getStrike().compareTo(inOther.getStrike());
}
/**
* Create a new OptionContrctPairKey instance.
*
* @param inSymbol a <code>String</code> value
* @param inExpiry a <code>String</code> value
* @param inStrike a <code>BigDecimal</code> value
*/
private OptionContractPairKey(String inSymbol,
String inExpiry,
BigDecimal inStrike)
{
symbol = inSymbol;
expiry = inExpiry;
strike = inStrike;
}
/**
* Get the symbol value.
*
* @return a <code>String</code> value
*/
private String getSymbol()
{
return symbol;
}
/**
* Get the expiry value.
*
* @return a <code>String</code> value
*/
private String getExpiry()
{
return expiry;
}
/**
* Get the strike value.
*
* @return a <code>BigDecimal</code> value
*/
private BigDecimal getStrike()
{
return strike;
}
/**
* the symbol
*/
private final String symbol;
/**
* the expiry
*/
private final String expiry;
/**
* the strike
*/
private final BigDecimal strike;
}
}