package org.marketcetera.trade; import java.math.BigDecimal; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import org.marketcetera.util.misc.ClassVersion; import org.marketcetera.options.OptionUtils; /* $License$ */ /** * Identifies an option. * <p> * Note that if the option expiry specifies the expiry date in the format * YYYYMM, an augmented form of the expiry is also stored as an attribute * of the option. The {@link #getAugmentedExpiry() augmented expiry} is used * for {@link #hashCode()} and {@link #equals(Object)} methods in preference * to the specified {@link #getExpiry() expiry}. * <p> * See {@link OptionUtils#normalizeEquityOptionExpiry(String)} for details * on how the expiry value is augmented. * * @author <a href="mailto:will@marketcetera.com">Will Horn</a> * @version $Id: Option.java 16604 2013-06-26 14:49:42Z colin $ * @since 2.0.0 */ @ClassVersion("$Id: Option.java 16604 2013-06-26 14:49:42Z colin $") @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Option extends Instrument { private final String mSymbol; private final OptionType mType; private final String mExpiry; private final String mAugmentedExpiry; private final BigDecimal mStrikePrice; /** * Constructor. Note that trailing zeros are stripped from strikePrice. * * @param symbol * the option root symbol * @param expiry * the option expiry * @param strikePrice * the option strike price * @param type * the option type * @throws IllegalArgumentException * if any argument is null, or if symbol or expiry is whitespace */ public Option(String symbol, String expiry, BigDecimal strikePrice, OptionType type) { symbol = StringUtils.trimToNull(symbol); expiry = StringUtils.trimToNull(expiry); Validate.notNull(symbol); Validate.notNull(type); Validate.notNull(expiry); Validate.notNull(strikePrice); mSymbol = symbol; mType = type; mExpiry = expiry; mAugmentedExpiry = OptionUtils.normalizeEquityOptionExpiry(mExpiry); strikePrice = strikePrice.stripTrailingZeros(); if(strikePrice.scale() < 0) { //reset the scale if the number is a multiple of 10 strikePrice = strikePrice.setScale(0); } mStrikePrice = strikePrice; } /** * Parameterless constructor for use only by JAXB. */ protected Option() { mSymbol = null; mType = null; mExpiry = null; mAugmentedExpiry = null; mStrikePrice = null; } /** * Returns the option root symbol. * * @return the option root symbol, never null */ @Override public String getSymbol() { return mSymbol; } /* (non-Javadoc) * @see org.marketcetera.trade.Instrument#getFullSymbol() */ @Override public String getFullSymbol() { return OptionUtils.getOsiSymbolFromOption(this); } /** * Always returns {@link SecurityType#Option}. * * @return {@link SecurityType#Option} */ @Override public SecurityType getSecurityType() { return SecurityType.Option; } /** * Returns the option expiry. * * @return the option expiry, never null */ public String getExpiry() { return mExpiry; } /** * Returns the augmented option expiry. * <p> * The augmented expiry is available if the supplied option * expiry doesn't include the expiry day, otherwise it is null. * * @return the augmented expiry, if the expiry was augmented, null otherwise. * * @see OptionUtils#normalizeEquityOptionExpiry(String) */ public String getAugmentedExpiry() { return mAugmentedExpiry; } /** * Returns the option strike price. * * @return the option strike price, never null */ public BigDecimal getStrikePrice() { return mStrikePrice; } /** * Returns the option type. * * @return the option type, never null */ public OptionType getType() { return mType; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + (mAugmentedExpiry == null ? mExpiry.hashCode() : mAugmentedExpiry.hashCode()); result = prime * result + mStrikePrice.hashCode(); result = prime * result + mSymbol.hashCode(); result = prime * result + mType.hashCode(); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof Option)) { return false; } Option other = (Option) obj; String expiry = mAugmentedExpiry == null ? mExpiry : mAugmentedExpiry; String otherExpiry = other.mAugmentedExpiry == null ? other.mExpiry : other.mAugmentedExpiry; return mSymbol.equals(other.mSymbol) && mType.equals(other.mType) && mStrikePrice.equals(other.mStrikePrice) && expiry.equals(otherExpiry); } @Override public String toString() { ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) .append("symbol", mSymbol) //$NON-NLS-1$ .append("type", mType) //$NON-NLS-1$ .append("expiry", mExpiry) //$NON-NLS-1$ .append("strikePrice", mStrikePrice); //$NON-NLS-1$ if(mAugmentedExpiry != null) { builder.append("augmentedExpiry", mAugmentedExpiry); //$NON-NLS-1$ } return builder.toString(); } private static final long serialVersionUID = 1L; }