package org.marketcetera.event.util;
import static java.math.BigDecimal.ONE;
import static java.math.BigDecimal.TEN;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.marketcetera.event.util.BookPriceComparator.askComparator;
import static org.marketcetera.event.util.BookPriceComparator.bidComparator;
import java.math.BigDecimal;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.marketcetera.event.QuoteEvent;
import org.marketcetera.event.impl.QuoteEventBuilder;
import org.marketcetera.marketdata.DateUtils;
import org.marketcetera.module.ExpectedFailure;
import org.marketcetera.options.ExpirationType;
import org.marketcetera.trade.Equity;
import org.marketcetera.trade.Instrument;
import org.marketcetera.trade.Option;
import org.marketcetera.trade.OptionType;
/* $License$ */
/**
* Tests {@link BookPriceComparator} and {@link PriceAndSizeComparator}.
*
* @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a>
* @version $Id: PriceComparatorsTest.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
public class PriceComparatorsTest
{
/**
* Run before each test.
*
* @throws Exception if an unexpected error occurs
*/
@Before
public void before()
throws Exception
{
doOption = false;
}
/**
* Tests {@link BookPriceComparator} and {@link PriceAndSizeComparator}.
*
* @throws Exception if an error occurs
*/
@Test
public void testComparators()
throws Exception
{
Option option = new Option("METC",
"201001",
BigDecimal.TEN,
OptionType.Put);
Equity equity = new Equity("METC");
doBookPriceComparatorTest(QuoteEventBuilder.equityAskEvent(),
equity);
doBookPriceComparatorTest(QuoteEventBuilder.equityBidEvent(),
equity);
doPriceAndSizeComparatorTest(QuoteEventBuilder.equityAskEvent(),
equity);
doPriceAndSizeComparatorTest(QuoteEventBuilder.equityBidEvent(),
equity);
doOption = true;
doBookPriceComparatorTest(QuoteEventBuilder.optionAskEvent(),
option);
doBookPriceComparatorTest(QuoteEventBuilder.optionBidEvent(),
option);
doPriceAndSizeComparatorTest(QuoteEventBuilder.optionAskEvent(),
option);
doPriceAndSizeComparatorTest(QuoteEventBuilder.optionBidEvent(),
option);
}
/**
* Tests {@link PriceAndSizeComparator}.
*
* @param inBuilder a <code>QuoteEventBuilder<E></code> value
* @param inBuilder an <code>Instrument</code> value
* @throws Exception if an unexpected error occurs
*/
private <E extends QuoteEvent> void doPriceAndSizeComparatorTest(QuoteEventBuilder<E> inBuilder,
Instrument inInstrument)
throws Exception
{
final E quote1 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(new Date())
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(ONE)
.withSize(TEN).create();
// check nulls first
new ExpectedFailure<NullPointerException>() {
@Override
protected void run()
throws Exception
{
PriceAndSizeComparator.instance.compare(null,
quote1);
}
};
new ExpectedFailure<NullPointerException>() {
@Override
protected void run()
throws Exception
{
PriceAndSizeComparator.instance.compare(quote1,
null);
}
};
// this null-only case is OK
assertEquals(0,
PriceAndSizeComparator.instance.compare(null,
null));
// comparator works on price then size
E quote2 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(new Date())
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(quote1.getPrice().add(ONE))
.withSize(TEN).create();
assertTrue(quote2.getPrice().intValue() > quote1.getPrice().intValue());
// e1 price < e2 price (remember that bid and ask are opposite sorts)
assertEquals(-1,
PriceAndSizeComparator.instance.compare(quote1,
quote2));
// invert the test
assertEquals(1,
PriceAndSizeComparator.instance.compare(quote2,
quote1));
// e1 price == e2 price (and size)
quote2 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(new Date())
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(quote1.getPrice())
.withSize(quote1.getSize()).create();
assertEquals(quote1.getPrice(),
quote2.getPrice());
assertEquals(quote1.getSize(),
quote2.getSize());
assertEquals(0,
PriceAndSizeComparator.instance.compare(quote1,
quote2));
// invert the test
assertEquals(0,
PriceAndSizeComparator.instance.compare(quote2,
quote1));
// e1 size < e2 size
quote2 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(new Date())
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(quote1.getPrice())
.withSize(quote1.getSize().add(TEN)).create();
assertEquals(quote1.getPrice(),
quote2.getPrice());
assertTrue(quote2.getSize().intValue() > quote1.getSize().intValue());
assertEquals(-1,
PriceAndSizeComparator.instance.compare(quote1,
quote2));
// invert the test
assertEquals(1,
PriceAndSizeComparator.instance.compare(quote2,
quote1));
}
/**
* Tests {@link BookPriceComparator}.
*
* @param inBuilder a <code>QuoteEventBuilder<E></code> value
* @param inBuilder an <code>Instrument</code> value
* @throws Exception if an unexpected error occurs
*/
private <E extends QuoteEvent> void doBookPriceComparatorTest(QuoteEventBuilder<E> inBuilder,
Instrument inInstrument)
throws Exception
{
final E quote1 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(new Date())
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(ONE)
.withSize(TEN).create();
// check nulls first
new ExpectedFailure<NullPointerException>() {
@Override
protected void run()
throws Exception
{
askComparator.compare(null,
quote1);
}
};
new ExpectedFailure<NullPointerException>() {
@Override
protected void run()
throws Exception
{
bidComparator.compare(null,
quote1);
}
};
new ExpectedFailure<NullPointerException>() {
@Override
protected void run()
throws Exception
{
askComparator.compare(quote1,
null);
}
};
new ExpectedFailure<NullPointerException>() {
@Override
protected void run()
throws Exception
{
bidComparator.compare(quote1,
null);
}
};
// this null-only case is OK
assertEquals(0,
askComparator.compare(null,
null));
assertEquals(0,
bidComparator.compare(null,
null));
// comparator works on price then timestamp
E quote2 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(new Date())
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(quote1.getPrice().add(ONE))
.withSize(TEN).create();
assertTrue("Expected " + quote2.getPrice() + " > " + quote1.getPrice(),
quote2.getPrice().intValue() > quote1.getPrice().intValue());
// e1 price < e2 price (remember that bid and ask are opposite sorts)
assertEquals(-1,
askComparator.compare(quote1,
quote2));
assertEquals(1,
bidComparator.compare(quote1,
quote2));
// invert the test
assertEquals(1,
askComparator.compare(quote2,
quote1));
assertEquals(-1,
bidComparator.compare(quote2,
quote1));
// e1 price == e2 price (and timestamp)
quote2 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(quote1.getTimestamp())
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(quote1.getPrice())
.withSize(TEN).create();
assertEquals(quote1.getPrice(),
quote2.getPrice());
assertEquals(0,
askComparator.compare(quote1,
quote2));
assertEquals(0,
bidComparator.compare(quote1,
quote2));
// invert the test
assertEquals(0,
askComparator.compare(quote2,
quote1));
assertEquals(0,
bidComparator.compare(quote2,
quote1));
// e1 timestamp < e2 timestamp
quote2 = doOption(inBuilder).withMessageId(System.nanoTime())
.withTimestamp(new Date(quote1.getTimeMillis() + 1000))
.withQuoteDate(DateUtils.dateToString(new Date()))
.withInstrument(inInstrument)
.withExchange("Q")
.withPrice(quote1.getPrice())
.withSize(TEN).create();
assertEquals(quote1.getPrice(),
quote2.getPrice());
assertTrue(quote1.getTimeMillis() < quote2.getTimeMillis());
assertEquals(-1,
askComparator.compare(quote1,
quote2));
assertEquals(1,
bidComparator.compare(quote1,
quote2));
// invert the test
assertEquals(1,
askComparator.compare(quote2,
quote1));
assertEquals(-1,
bidComparator.compare(quote2,
quote1));
}
/**
* Modifies the given <code>QuoteEventBuilder</code> with option attributes if necessary.
*
* @param inBuilder a <code>QuoteEventBuilder<? extends QuoteEvent></code> value
* @return a <code>QuoteEventBuilder<? extends QuoteEvent></code> value
*/
private <E extends QuoteEvent> QuoteEventBuilder<E> doOption(QuoteEventBuilder<E> inBuilder)
{
if(doOption) {
return inBuilder.withExpirationType(ExpirationType.AMERICAN)
.withMultiplier(BigDecimal.ZERO)
.withUnderlyingInstrument(new Equity("METC"));
}
return inBuilder;
}
/**
* if set, for some tests, will cause option characteristics to be activated
*/
private boolean doOption = false;
}