package org.marketcetera.core.instruments;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.math.BigDecimal;
import org.junit.BeforeClass;
import org.junit.Test;
import org.marketcetera.core.LoggerConfiguration;
import org.marketcetera.module.ExpectedFailure;
import org.marketcetera.quickfix.FIXDataDictionaryManager;
import org.marketcetera.quickfix.FIXVersion;
import org.marketcetera.trade.*;
import org.marketcetera.trade.Currency;
import org.marketcetera.util.log.SLF4JLoggerProxy;
import org.marketcetera.util.misc.ClassVersion;
import quickfix.*;
import quickfix.field.*;
import quickfix.field.SecurityType;
/* $License$ */
/**
* Tests {@link InstrumentFromMessage} and its subclasses.
*
* @author anshul@marketcetera.com
* @version $Id: InstrumentFromMessageTest.java 16841 2014-02-20 19:59:04Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: InstrumentFromMessageTest.java 16841 2014-02-20 19:59:04Z colin $")
public class InstrumentFromMessageTest {
@BeforeClass
public static void logSetup() throws Exception {
LoggerConfiguration.logSetup();
FIXDataDictionaryManager.initialize(FIX_VERSION,
FIX_VERSION.getDataDictionaryURL());
}
@Test
public void unhandledType() throws Exception {
Message msg = FIX_VERSION.getMessageFactory().newBasicOrder();
//unknown security type
msg.setField(new SecurityType(SecurityType.BANK_NOTES));
verifyNoHandlerFailure(msg);
//null CFI code
msg.setField(new CFICode());
verifyNoHandlerFailure(msg);
//empty CFI code
msg.setField(new CFICode(""));
verifyNoHandlerFailure(msg);
//Invalid CFI code
msg.setField(new CFICode("S"));
verifyNoHandlerFailure(msg);
//Invalid CFI code
msg.setField(new CFICode("SO"));
verifyNoHandlerFailure(msg);
//remove security type field and test
msg.removeField(SecurityType.FIELD);
verifyNoHandlerFailure(msg);
}
@Test
public void equity() throws Exception {
//no security type, no symbol
Message msg = FIX_VERSION.getMessageFactory().newBasicOrder();
assertEquals(false, msg.isSetField(SecurityType.FIELD));
assertNull(InstrumentFromMessage.SELECTOR.forValue(msg).extract(msg));
// no security type, symbol set
msg.setField(new Symbol("PQR"));
assertEquals(new Equity("PQR"), InstrumentFromMessage.SELECTOR.forValue(msg).extract(msg));
//security type set, symbol set
msg.setField(new SecurityType(SecurityType.COMMON_STOCK));
assertEquals(new Equity("PQR"), InstrumentFromMessage.SELECTOR.forValue(msg).extract(msg));
}
@Test
public void currency() throws Exception {
//no security type, no symbol
Message msg = FIX_VERSION.getMessageFactory().newBasicOrder();
assertEquals(false, msg.isSetField(SecurityType.FIELD));
assertNull(InstrumentFromMessage.SELECTOR.forValue(msg).extract(msg));
// no security type, symbol set
msg.setField(new Symbol("GBP/USD"));
//security type set, symbol set
msg.setField(new SecurityType(SecurityType.FOREIGN_EXCHANGE_CONTRACT));
assertEquals(new Currency("GBP/USD"), InstrumentFromMessage.SELECTOR.forValue(msg).extract(msg));
}
/**
* Tests creating <code>ConvertibleBond</code> instruments from <code>Message</code> objects.
*
* @throws Exception if an unexpected error occurs
*/
@Test
public void convertibleBond()
throws Exception
{
//no security type, no symbol
Message msg = FIX_VERSION.getMessageFactory().newBasicOrder();
assertEquals(false, msg.isSetField(SecurityType.FIELD));
assertNull(InstrumentFromMessage.SELECTOR.forValue(msg).extract(msg));
// security type set, symbol set
msg.setField(new Symbol("US013817AT86"));
msg.setField(new SecurityType(SecurityType.CONVERTIBLE_BOND));
assertEquals(new ConvertibleBond("US013817AT86"),
InstrumentFromMessage.SELECTOR.forValue(msg).extract(msg));
}
@Test
public void option() throws Exception {
String expectedSymbol = "PQR";
String expectedMY = "201010";
String expectedDay = "10";
String expectedExpiry = expectedMY + expectedDay;
BigDecimal expectedStrike = BigDecimal.TEN;
//Test all permutations of fields.
for (Field<?> secType : new Field[]{null, new SecurityType(SecurityType.OPTION), new CFICode("O")}) {
for (Field<?> symbol : new Field[]{null, new Symbol(expectedSymbol)}) {
for (Field<?> optType : new Field[]{null, new PutOrCall(), new PutOrCall(PutOrCall.CALL), new PutOrCall(PutOrCall.PUT), new CFICode("O"), new CFICode("OC"), new CFICode("OP")}) {
for (Field<?> strikePrice : new Field[]{null, new StrikePrice(expectedStrike)}) {
for (Field<?> expiry : new Field[]{null, new MaturityMonthYear(expectedMY), new MaturityDate(expectedExpiry)}) {
for(Field<?> expiryDay: new Field[]{null, new MaturityDay(expectedDay)}) {
Message m = FIX_VERSION.getMessageFactory().newBasicOrder();
setFields(m, secType, symbol, optType, strikePrice, expiry, expiryDay);
SLF4JLoggerProxy.debug(this,"{},{},{},{},{},{}",secType,symbol,optType,strikePrice,expiry,expiryDay);
//figure out if we expect a value.
boolean isNotOption = (secType == null && (optType == null || (!(optType instanceof CFICode)))) ||
symbol == null ||
optType == null ||
(optType instanceof CFICode && ((String)optType.getObject()).length() < 2) ||
strikePrice == null ||
expiry == null;
Instrument instrument = InstrumentFromMessage.SELECTOR.forValue(m).extract(m);
if(isNotOption) {
assertThat(instrument, anyOf(nullValue(), not(instanceOf(Option.class))));
} else {
Option option = (Option) instrument;
assertEquals(org.marketcetera.trade.SecurityType.Option, option.getSecurityType());
assertEquals(expectedSymbol, option.getSymbol());
assertEquals(expectedStrike, option.getStrikePrice());
if (expiry.getTag() == MaturityMonthYear.FIELD) {
assertEquals(expiryDay == null? expectedMY: expectedExpiry, option.getExpiry());
} else {
assertEquals(expectedExpiry, option.getExpiry());
}
OptionType oType;
if(optType.getTag() == PutOrCall.FIELD) {
oType = OptionType.getInstanceForFIXValue((Integer) optType.getObject());
} else {
oType = CFICodeUtils.getOptionType((String)optType.getObject());
}
assertEquals(oType, option.getType());
}
}
}
}
}
}
}
}
@Test
public void future()
throws Exception
{
String expectedSymbol = "CLF";
FutureExpirationMonth expectedExpirationMonth = FutureExpirationMonth.JANUARY;
int expectedExpirationYear = 2015;
String expectedMY = "201501";
//Test all permutations of fields.
for(Field<?> secType : new Field[]{null, new SecurityType(SecurityType.FUTURE), new CFICode("F")}) {
for(Field<?> symbol : new Field[]{null, new Symbol(expectedSymbol)}) {
for(Field<?> expiry : new Field[]{null, new MaturityMonthYear(expectedMY)}) {
for(Field<?> day : new Field[] { null, new MaturityDay("10") }) {
Message m = FIX_VERSION.getMessageFactory().newBasicOrder();
setFields(m,
secType,
symbol,
expiry,
day);
SLF4JLoggerProxy.debug(this,
"{} - {},{},{},{}",
m,
secType,
symbol,
expiry,
day);
//figure out if we expect a value.
boolean isNotFuture = (secType == null ||
symbol == null ||
expiry == null);
Instrument instrument = InstrumentFromMessage.SELECTOR.forValue(m).extract(m);
if(isNotFuture) {
assertThat(instrument,
anyOf(nullValue(),
not(instanceOf(Future.class))));
} else {
Future future = (Future)instrument;
assertEquals(org.marketcetera.trade.SecurityType.Future,
future.getSecurityType());
assertEquals(expectedSymbol,
future.getSymbol());
if(expiry != null) {
assertEquals(expectedMY,
future.getExpiryAsMaturityMonthYear().getValue());
assertEquals(expectedExpirationMonth,
future.getExpirationMonth());
assertEquals(expectedExpirationYear,
future.getExpirationYear());
}
if(day != null) {
assertEquals(10,
future.getExpirationDay());
}
}
}
}
}
}
}
private static void setFields(Message inMessage, Field<?>... inFields) {
for(Field<?> field:inFields) {
if(field != null) {
if (field instanceof StringField) {
inMessage.setField((StringField) field);
} else if(field instanceof IntField) {
inMessage.setField((IntField) field);
} else if(field instanceof DecimalField) {
inMessage.setField((DecimalField) field);
} else {
fail("unhandled field:" + field);
}
}
}
}
private void verifyNoHandlerFailure(final Message inMsg) throws Exception {
new ExpectedFailure<IllegalArgumentException>(
Messages.NO_HANDLER_FOR_VALUE.getText(inMsg,
InstrumentFromMessage.class.getName())){
@Override
protected void run() throws Exception {
InstrumentFromMessage.SELECTOR.forValue(inMsg);
}
};
}
private static final FIXVersion FIX_VERSION = FIXVersion.FIX44;
}