package org.marketcetera.core.instruments;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.trade.Instrument;
import org.marketcetera.trade.OptionType;
import org.marketcetera.trade.Option;
import quickfix.Message;
import quickfix.FieldNotFound;
import quickfix.field.*;
import java.math.BigDecimal;
/* $License$ */
/**
* Extracts option instrument from a FIX Message.
* <p>
* Returns a null value, if all the expected attributes for an option are not
* found in the message.
*
* @author anshul@marketcetera.com
* @version $Id: OptionFromMessage.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: OptionFromMessage.java 16154 2012-07-14 16:34:05Z colin $")
public class OptionFromMessage extends InstrumentFromMessage {
@Override
public Instrument extract(Message inMessage) {
String symbol = getSymbol(inMessage);
OptionType type = getOptionType(inMessage);
BigDecimal strike = getStrikePrice(inMessage);
String expiry = getExpiry(inMessage);
if(symbol == null || type == null || strike == null || expiry == null) {
return null;
}
return new Option(symbol, expiry, strike, type);
}
@Override
protected boolean isHandled(Message inValue) {
try {
return (inValue.isSetField(SecurityType.FIELD) &&
SecurityType.OPTION.equals(inValue.getString(SecurityType.FIELD))) ||
(inValue.isSetField(CFICode.FIELD) &&
CFICodeUtils.isOption(inValue.getString(CFICode.FIELD)));
} catch (FieldNotFound ignore) {
return false;
}
}
/**
* Returns the option type value from the specified FIX message.
* <p>
* This method looks into the <code>PutOrCall</code> and
* <code>CFICode</code> fields to determine the option type value,
* giving precedence to former.
*
* @param inMessage the FIX message.
*
* @return the option type value, if available, null otherwise.
*/
private static OptionType getOptionType(Message inMessage) {
//Check the value from PutOrCall field
if (inMessage.isSetField(quickfix.field.PutOrCall.FIELD)) {
try {
return OptionType.getInstanceForFIXValue(
inMessage.getInt(
quickfix.field.PutOrCall.FIELD));
} catch (FieldNotFound ignore) {
}
}
//Otherwise check the CFI code field
if(inMessage.isSetField(CFICode.FIELD)) {
try {
return CFICodeUtils.getOptionType(
inMessage.getString(CFICode.FIELD));
} catch (FieldNotFound ignore) {
}
}
return null;
}
/**
* Returns the strike price value for the specified FIX message.
*
* @param inMessage the FIX message.
*
* @return the strike price value, if available, null otherwise.
*/
private static BigDecimal getStrikePrice(Message inMessage) {
if (inMessage.isSetField(StrikePrice.FIELD)) {
try {
return inMessage.getDecimal(StrikePrice.FIELD);
} catch (FieldNotFound ignore) {
}
}
return null;
}
/**
* Returns the expiry value for the specified FIX message.
*
* @param inMessage the FIX message
*
* @return the expiry value, if available, null otherwise.
*/
static String getExpiry(Message inMessage) {
//FIX versions 4.1, 4.2, 4.3 use MaturityMonthYear
if (inMessage.isSetField(MaturityMonthYear.FIELD)) {
try {
String value = inMessage.getString(MaturityMonthYear.FIELD);
if (value != null) {
//FIX version 4.2 uses MaturityDay to specify the option's
//expiry day once OSI goes into effect.
if (value.length() == 6 && inMessage.isSetField(MaturityDay.FIELD)) {
try {
String day = inMessage.getString(MaturityDay.FIELD);
if (day != null) {
return value + day;
}
} catch (FieldNotFound ignore) {
}
}
return value;
}
} catch (FieldNotFound ignore) {
}
}
//FIX version 4.3 uses MaturityDate
if (inMessage.isSetField(MaturityDate.FIELD)) {
try {
return inMessage.getString(MaturityDate.FIELD);
} catch (FieldNotFound ignore) {
}
}
return null;
}
}