package org.marketcetera.messagehistory; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.sameInstance; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicLong; import junit.framework.Test; import org.marketcetera.core.AccessViolator; import org.marketcetera.core.FIXVersionTestSuite; import org.marketcetera.core.FIXVersionedTestCase; import org.marketcetera.core.instruments.InstrumentToMessage; import org.marketcetera.core.instruments.MockUnderlyingSymbolSupport; import org.marketcetera.core.instruments.UnderlyingSymbolSupport; import org.marketcetera.quickfix.FIXVersion; import org.marketcetera.trade.BrokerID; import org.marketcetera.trade.Currency; import org.marketcetera.trade.Equity; import org.marketcetera.trade.ExecutionReport; import org.marketcetera.trade.ExecutionReportImpl; import org.marketcetera.trade.Factory; import org.marketcetera.trade.Future; import org.marketcetera.trade.FutureExpirationMonth; import org.marketcetera.trade.Instrument; import org.marketcetera.trade.MessageCreationException; import org.marketcetera.trade.Option; import org.marketcetera.trade.OptionType; import org.marketcetera.trade.OrderCancelReject; import org.marketcetera.trade.OrderStatus; import org.marketcetera.trade.Originator; import org.marketcetera.trade.ReportBase; import org.marketcetera.trade.ReportBaseImpl; import org.marketcetera.trade.ReportID; import quickfix.FieldNotFound; import quickfix.Message; import quickfix.field.AvgPx; import quickfix.field.ClOrdID; import quickfix.field.CumQty; import quickfix.field.CxlRejReason; import quickfix.field.CxlRejResponseTo; import quickfix.field.ExecID; import quickfix.field.ExecTransType; import quickfix.field.ExecType; import quickfix.field.LastPx; import quickfix.field.LastShares; import quickfix.field.LeavesQty; import quickfix.field.MsgType; import quickfix.field.OrdStatus; import quickfix.field.OrderID; import quickfix.field.OrderQty; import quickfix.field.OrigClOrdID; import quickfix.field.Price; import quickfix.field.SendingTime; import quickfix.field.Side; import quickfix.field.Symbol; import quickfix.field.TimeInForce; import ca.odell.glazedlists.EventList; import ca.odell.glazedlists.event.ListEvent; import ca.odell.glazedlists.event.ListEventListener; import com.google.common.collect.Lists; /* $License$ */ /** * Test {@link TradeReportsHistory}. * * @author <a href="mailto:will@marketcetera.com">Will Horn</a> * @version $Id: TradeReportsHistoryTest.java 16888 2014-04-22 18:32:36Z colin $ * @since 1.0.0 */ public class TradeReportsHistoryTest extends FIXVersionedTestCase { public TradeReportsHistoryTest(String inName, FIXVersion version) { super(inName, version); } public static Test suite() { return new FIXVersionTestSuite(TradeReportsHistoryTest.class, FIXVersion.values()); } protected TradeReportsHistory createMessageHistory() { return new TradeReportsHistory(FIXVersion.FIX_SYSTEM.getMessageFactory(), new MockUnderlyingSymbolSupport()); } public void testAddIncomingMessage() throws Exception { TradeReportsHistory history = createMessageHistory(); String orderID1 = "1"; //$NON-NLS-1$ String clOrderID1 = "2"; //$NON-NLS-1$ String execID = "3"; //$NON-NLS-1$ char execType = ExecType.PARTIAL_FILL; char ordStatus = OrdStatus.PARTIALLY_FILLED; char side = Side.SELL_SHORT; BigDecimal orderQty = new BigDecimal(1000); BigDecimal orderPrice = new BigDecimal(789); BigDecimal lastQty = new BigDecimal(100); BigDecimal lastPrice = new BigDecimal("12.3"); //$NON-NLS-1$ BigDecimal cumQty = new BigDecimal(100); BigDecimal avgPrice = new BigDecimal("12.3"); //$NON-NLS-1$ Instrument instrument = new Equity("ASDF"); //$NON-NLS-1$ Message message = msgFactory.newExecutionReport(orderID1, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); { history.addIncomingMessage(createServerReport(message)); EventList<ReportHolder> historyList = history.getAllMessagesList(); assertEquals(1, historyList.size()); ReportHolder holder = historyList.get(0); Message historyMessage = holder.getMessage(); assertEquals(orderID1, historyMessage.getString(OrderID.FIELD)); assertEquals(clOrderID1, historyMessage.getString(ClOrdID.FIELD)); assertEquals(execID, historyMessage.getString(ExecID.FIELD)); if (historyMessage.isSetField(ExecType.FIELD)) { // in case of FIX 4.0 where ExecType doesn't exist assertEquals( "" + execType, historyMessage.getString(ExecType.FIELD)); //$NON-NLS-1$ } assertEquals( "" + ordStatus, historyMessage.getString(OrdStatus.FIELD)); //$NON-NLS-1$ assertEquals("" + side, historyMessage.getString(Side.FIELD)); //$NON-NLS-1$ assertEquals(orderQty, historyMessage.getDecimal(OrderQty.FIELD)); assertEquals(lastQty, historyMessage.getDecimal(LastShares.FIELD)); assertEquals(lastPrice, historyMessage.getDecimal(LastPx.FIELD)); assertEquals(cumQty, historyMessage.getDecimal(CumQty.FIELD)); assertEquals(avgPrice, historyMessage.getDecimal(AvgPx.FIELD)); assertEquals(instrument.getSymbol(), historyMessage .getString(Symbol.FIELD)); } { String orderID2 = "1001"; //$NON-NLS-1$ String clOrderID2 = "1002"; //$NON-NLS-1$ Message message2 = msgFactory.newExecutionReport(orderID2, clOrderID2, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); history.addIncomingMessage(createServerReport(message2)); EventList<ReportHolder> historyList = history.getAllMessagesList(); assertEquals(2, historyList.size()); ReportHolder holder = historyList.get(1); Message historyMessage = holder.getMessage(); assertEquals(orderID2, historyMessage.getString(OrderID.FIELD)); assertEquals(clOrderID2, historyMessage.getString(ClOrdID.FIELD)); assertEquals(execID, historyMessage.getString(ExecID.FIELD)); if (historyMessage.isSetField(ExecType.FIELD)) { // in case of FIX 4.0 where ExecType doesn't exist assertEquals( "" + execType, historyMessage.getString(ExecType.FIELD)); //$NON-NLS-1$ } assertEquals( "" + ordStatus, historyMessage.getString(OrdStatus.FIELD)); //$NON-NLS-1$ assertEquals("" + side, historyMessage.getString(Side.FIELD)); //$NON-NLS-1$ assertEquals(orderQty, historyMessage.getDecimal(OrderQty.FIELD)); assertEquals(lastQty, historyMessage.getDecimal(LastShares.FIELD)); assertEquals(lastPrice, historyMessage.getDecimal(LastPx.FIELD)); assertEquals(cumQty, historyMessage.getDecimal(CumQty.FIELD)); assertEquals(avgPrice, historyMessage.getDecimal(AvgPx.FIELD)); assertEquals(instrument.getSymbol(), historyMessage .getString(Symbol.FIELD)); } } public void testGetLatestExecutionReports() throws Exception { long currentTime = System.currentTimeMillis(); TradeReportsHistory history = createMessageHistory(); Message executionReportForOrder1 = msgFactory .newExecutionReport( "1001", "1", "2001", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null); executionReportForOrder1.getHeader().setField( new SendingTime(new Date(currentTime - 10000))); Message order2 = msgFactory .newLimitOrder( "3", Side.SELL, new BigDecimal(2000), new Equity("QWER"), new BigDecimal("12.3"), TimeInForce.DAY, "1"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ Message executionReportForOrder2 = msgFactory .newExecutionReport( "1003", "3", "2003", OrdStatus.NEW, Side.SELL, new BigDecimal(2000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("QWER"), null, null); executionReportForOrder2.getHeader().setField( new SendingTime(new Date(currentTime - 8000))); Message secondExecutionReportForOrder1 = msgFactory .newExecutionReport( "1001", "1", "2004", OrdStatus.PARTIALLY_FILLED, Side.BUY, new BigDecimal(1000), new BigDecimal(789), new BigDecimal(100), new BigDecimal("11.5"), new BigDecimal(100), new BigDecimal("11.5"), new Equity("ASDF"), null, null); secondExecutionReportForOrder1.getHeader().setField( new SendingTime(new Date(currentTime - 7000))); history.addIncomingMessage(createServerReport(executionReportForOrder1)); history.addIncomingMessage(createServerReport(executionReportForOrder2)); history .addIncomingMessage(createServerReport(secondExecutionReportForOrder1)); ExecutionReport historyExecutionReportForOrder1 = (ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( "1")); //$NON-NLS-1$ assertNotNull(historyExecutionReportForOrder1); ExecutionReport historyExecutionReportForOrder2 = (ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( "3")); //$NON-NLS-1$ assertNotNull(historyExecutionReportForOrder2); assertEquals("1001", historyExecutionReportForOrder1 .getBrokerOrderID()); assertEquals("2004", historyExecutionReportForOrder1.getExecutionID()); //$NON-NLS-1$ assertEquals(executionReportForOrder1.getString(ClOrdID.FIELD), historyExecutionReportForOrder1.getOrderID().getValue()); assertSame(org.marketcetera.trade.Side.Buy, historyExecutionReportForOrder1.getSide()); assertEquals(executionReportForOrder1.getString(OrderQty.FIELD), historyExecutionReportForOrder1.getOrderQuantity().toString()); assertEquals(executionReportForOrder1.getString(Symbol.FIELD), historyExecutionReportForOrder1.getInstrument().getSymbol()); assertEquals("1003", historyExecutionReportForOrder2 .getBrokerOrderID()); assertEquals("2003", historyExecutionReportForOrder2.getExecutionID()); //$NON-NLS-1$ assertEquals(order2.getString(ClOrdID.FIELD), historyExecutionReportForOrder2.getOrderID().getValue()); assertSame(org.marketcetera.trade.Side.Sell, historyExecutionReportForOrder2.getSide()); assertEquals(order2.getString(OrderQty.FIELD), historyExecutionReportForOrder2.getOrderQuantity().toString()); assertEquals(order2.getString(Symbol.FIELD), historyExecutionReportForOrder2.getInstrument().getSymbol()); } public void testGetLatestMessage() throws Exception { long currentTime = System.currentTimeMillis(); TradeReportsHistory history = createMessageHistory(); Message executionReportForOrder1 = msgFactory .newExecutionReport( "1001", "1", "2001", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null); executionReportForOrder1.getHeader().setField( new SendingTime(new Date(currentTime - 10000))); Message order2 = msgFactory .newLimitOrder( "3", Side.SELL, new BigDecimal(2000), new Equity("QWER"), new BigDecimal("12.3"), TimeInForce.DAY, "1"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ Message executionReportForOrder2 = msgFactory .newExecutionReport( "1003", "3", "2003", OrdStatus.NEW, Side.SELL, new BigDecimal(2000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("QWER"), null, null); executionReportForOrder2.getHeader().setField( new SendingTime(new Date(currentTime - 8000))); Message secondExecutionReportForOrder1 = msgFactory .newExecutionReport( "1001", "1", "2004", OrdStatus.PARTIALLY_FILLED, Side.BUY, new BigDecimal(1000), new BigDecimal(789), new BigDecimal(100), new BigDecimal("11.5"), new BigDecimal(100), new BigDecimal("11.5"), new Equity("ASDF"), null, null); secondExecutionReportForOrder1.getHeader().setField( new SendingTime(new Date(currentTime - 7000))); Message aMessage = msgFactory.createMessage(MsgType.EXECUTION_REPORT); history.addIncomingMessage(createServerReport(aMessage)); history.addIncomingMessage(createServerReport(executionReportForOrder1)); history.addIncomingMessage(createServerReport(executionReportForOrder2)); history .addIncomingMessage(createServerReport(secondExecutionReportForOrder1)); Message historyExecutionReportForOrder1 = history .getLatestMessage(new org.marketcetera.trade.OrderID("1")); //$NON-NLS-1$ assertNotNull(historyExecutionReportForOrder1); Message historyExecutionReportForOrder2 = history .getLatestMessage(new org.marketcetera.trade.OrderID("3")); //$NON-NLS-1$ assertNotNull(historyExecutionReportForOrder2); assertEquals( "1001", historyExecutionReportForOrder1.getString(OrderID.FIELD)); //$NON-NLS-1$ assertEquals( "2004", historyExecutionReportForOrder1.getString(ExecID.FIELD)); //$NON-NLS-1$ assertEquals(executionReportForOrder1.getString(ClOrdID.FIELD), historyExecutionReportForOrder1.getString(ClOrdID.FIELD)); assertEquals(executionReportForOrder1.getString(Side.FIELD), historyExecutionReportForOrder1.getString(Side.FIELD)); assertEquals(executionReportForOrder1.getString(OrderQty.FIELD), historyExecutionReportForOrder1.getString(OrderQty.FIELD)); assertEquals(executionReportForOrder1.getString(Symbol.FIELD), historyExecutionReportForOrder1.getString(Symbol.FIELD)); assertEquals( "1003", historyExecutionReportForOrder2.getString(OrderID.FIELD)); //$NON-NLS-1$ assertEquals( "2003", historyExecutionReportForOrder2.getString(ExecID.FIELD)); //$NON-NLS-1$ assertEquals(order2.getString(ClOrdID.FIELD), historyExecutionReportForOrder2.getString(ClOrdID.FIELD)); assertEquals(order2.getString(Side.FIELD), historyExecutionReportForOrder2.getString(Side.FIELD)); assertEquals(order2.getString(OrderQty.FIELD), historyExecutionReportForOrder2.getString(OrderQty.FIELD)); assertEquals(order2.getString(Symbol.FIELD), historyExecutionReportForOrder2.getString(Symbol.FIELD)); } public void testOrderCancelReject() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOrderSingle(history, "1", Side.BUY, "10", "ASDF", "1"); simulateCancelReject(history, "2", "1"); // should still be new assertEquals(OrderStatus.New, history.getOpenOrdersList().get(0).getReport() .getOrderStatus()); } public void testOrderCancel() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOrderSingle(history, "1", Side.BUY, "10", "ASDF", "1"); simulateCancel(history, "2", "1"); assertThat(history.getOpenOrdersList().size(), is(0)); } public void testReplaceThenCancelWithOutOfOrderIDs() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOrderSingle(history, "7021", Side.BUY, "10", "ASDF", "10"); simulateReplace(history, "9002", "7021", Side.BUY, "10", "ASDF", "15"); simulateCancel(history, "7022", "9002"); assertThat(history.getOpenOrdersList().size(), is(0)); } public void testOutOfOrderSingle() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOutOfOrderOrderSingle(history, "1", Side.BUY, "10", "ASDF", "1"); assertEquals(OrderStatus.New, history.getOpenOrdersList().get(0).getReport() .getOrderStatus()); } public void testOutOfOrderCancelReject() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOrderSingle(history, "1", Side.BUY, "10", "ASDF", "1"); simulateOutOfOrderCancelReject(history, "2", "1"); assertThat(history.getOpenOrdersList().size(), is(0)); } public void testOrderReject() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOrderReject(history, "1", Side.BUY, "10", "ASDF", "1"); assertThat(history.getOpenOrdersList().size(), is(0)); } public void testOrderExpired() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOrderExpiry(history, "1", Side.BUY, "10", "ASDF", "1"); assertThat(history.getOpenOrdersList().size(), is(0)); } public void testReplaceRejected() throws Exception { TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "NONE", "1", "2001", OrdStatus.PENDING_NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); history.addIncomingMessage(createBrokerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // replace quantity to 900 and price to 800 Message pendingReplace = msgFactory.newExecutionReport( "1", "2", "2001", OrdStatus.PENDING_REPLACE, Side.BUY, new BigDecimal(900), new BigDecimal(800), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null); pendingReplace.setString(OrigClOrdID.FIELD, "1"); history.addIncomingMessage(createServerReport(pendingReplace)); assertEquals(OrderStatus.PendingReplace, ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( "1"))).getOrderStatus()); Message cancelReject = msgFactory .createMessage(MsgType.ORDER_CANCEL_REJECT); cancelReject.setField(new OrderID("1001")); cancelReject.setField(new ClOrdID("2")); cancelReject.setField(new OrigClOrdID("1")); cancelReject.setField(new OrdStatus(OrdStatus.NEW)); cancelReject.setField(new CxlRejResponseTo( CxlRejResponseTo.ORDER_CANCEL_REQUEST)); history.addIncomingMessage(createBrokerReject(cancelReject)); ExecutionReportImpl openOrder = (ExecutionReportImpl) history.getOpenOrdersList().get(0).getReport(); assertEquals(OrderStatus.New, openOrder.getOrderStatus()); assertEquals(new BigDecimal(1000), openOrder.getOrderQuantity()); assertEquals(new BigDecimal(789), openOrder.getMessage().getDecimal(Price.FIELD)); } public void testAddFIXMessageListener() throws Exception { TradeReportsHistory history = createMessageHistory(); Message executionReportForOrder1 = msgFactory .newExecutionReport( "1001", "1", "2001", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null); ListEventListener<ReportHolder> fixMessageListener = new ListEventListener<ReportHolder>() { @SuppressWarnings("unused") public int numIncomingMessages = 0; @SuppressWarnings("unchecked")//$NON-NLS-1$ public void listChanged(ListEvent<ReportHolder> event) { if (event.hasNext()) { event.next(); if (event.getType() == ListEvent.INSERT) { EventList<ReportHolder> source = (EventList<ReportHolder>) event .getSource(); int index = event.getIndex(); ReportHolder holder = source.get(index); try { assertEquals( "1001", holder.getMessage().getString(OrderID.FIELD)); //$NON-NLS-1$ numIncomingMessages++; } catch (FieldNotFound e) { fail(e.getMessage()); } } } } }; history.getAllMessagesList().addListEventListener(fixMessageListener); history.addIncomingMessage(createServerReport(executionReportForOrder1)); // just use the AccessViolator to get the fields out of the anon inner // class AccessViolator violator = new AccessViolator(fixMessageListener .getClass()); assertEquals(1, violator.getField( "numIncomingMessages", fixMessageListener)); //$NON-NLS-1$ } public void testRemovePortfolioListener() throws Exception { TradeReportsHistory history = createMessageHistory(); Message executionReportForOrder1 = msgFactory .newExecutionReport( "1", "1", "2001", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null); ListEventListener<ReportHolder> fixMessageListener = new ListEventListener<ReportHolder>() { @SuppressWarnings("unused") public int numIncomingMessages = 0; public void listChanged(ListEvent<ReportHolder> event) { if (event.getType() == ListEvent.INSERT) { ReportHolder source = (ReportHolder) event.getSource(); try { assertEquals( "1001", source.getMessage().getString(OrderID.FIELD)); //$NON-NLS-1$ numIncomingMessages++; } catch (FieldNotFound e) { fail(e.getMessage()); } } } }; history.getAllMessagesList().addListEventListener(fixMessageListener); history.getAllMessagesList() .removeListEventListener(fixMessageListener); history.addIncomingMessage(createServerReport(executionReportForOrder1)); // just use the AccessViolator to get the fields out of the anon inner // class AccessViolator violator = new AccessViolator(fixMessageListener .getClass()); assertEquals(0, violator.getField( "numIncomingMessages", fixMessageListener)); //$NON-NLS-1$ } public void testAveragePriceList() throws Exception { TradeReportsHistory messageHistory = createMessageHistory(); String orderID1 = "1"; //$NON-NLS-1$ String clOrderID1 = "1"; //$NON-NLS-1$ String execID = "300"; //$NON-NLS-1$ char ordStatus = OrdStatus.PARTIALLY_FILLED; char side = Side.SELL_SHORT; BigDecimal orderQty = new BigDecimal(1000); BigDecimal orderPrice = new BigDecimal(789); BigDecimal lastQty = new BigDecimal(100); BigDecimal lastPrice = new BigDecimal("12.3"); //$NON-NLS-1$ BigDecimal cumQty = new BigDecimal("100"); //$NON-NLS-1$ BigDecimal avgPrice = new BigDecimal("12.3"); //$NON-NLS-1$ Instrument instrument = new Equity("ASDF"); //$NON-NLS-1$ Message message = msgFactory.newExecutionReport(orderID1, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); messageHistory.addIncomingMessage(createServerReport(message)); orderID1 = "1"; //$NON-NLS-1$ clOrderID1 = "1"; //$NON-NLS-1$ execID = "301"; //$NON-NLS-1$ lastQty = new BigDecimal(900); lastPrice = new BigDecimal("12.4"); //$NON-NLS-1$ cumQty = new BigDecimal(900); avgPrice = new BigDecimal("12.4"); //$NON-NLS-1$ message = msgFactory.newExecutionReport(orderID1, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); messageHistory.addIncomingMessage(createServerReport(message)); EventList<ReportHolder> averagePriceList = messageHistory .getAveragePricesList(); assertEquals(0, averagePriceList.size()); orderID1 = "1"; //$NON-NLS-1$ clOrderID1 = "1"; //$NON-NLS-1$ execID = "302"; //$NON-NLS-1$ lastQty = new BigDecimal(900); lastPrice = new BigDecimal("12.4"); //$NON-NLS-1$ cumQty = new BigDecimal(900); avgPrice = new BigDecimal("12.4"); //$NON-NLS-1$ side = Side.BUY; message = msgFactory.newExecutionReport(orderID1, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); messageHistory.addIncomingMessage(createServerReport(message)); assertEquals(0, messageHistory.getAveragePricesList().size()); orderID1 = "1"; //$NON-NLS-1$ clOrderID1 = "1"; //$NON-NLS-1$ execID = "305"; //$NON-NLS-1$ lastQty = new BigDecimal(900); lastPrice = new BigDecimal("12.4"); //$NON-NLS-1$ cumQty = new BigDecimal(900); avgPrice = new BigDecimal("12.4"); //$NON-NLS-1$ side = Side.SELL_SHORT; message = msgFactory.newExecutionReport(orderID1, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); messageHistory.addIncomingMessage(createServerReport(message)); assertEquals(0, messageHistory.getAveragePricesList().size()); } public void testAveragePriceList2() throws Exception { TradeReportsHistory hist = createMessageHistory(); Message fill = msgFactory.newExecutionReport("clordid1", "clordid1", "execid1", OrdStatus.PARTIALLY_FILLED, Side.BUY, new BigDecimal(100), null, new BigDecimal(91), new BigDecimal( 82), new BigDecimal(91), new BigDecimal(3), new Equity("symbol1"), "account", "text"); fill.setField(new ExecTransType(ExecTransType.STATUS)); fill.setField(new ExecType(ExecType.PARTIAL_FILL)); fill.setField(new LeavesQty(909)); hist.addIncomingMessage(createServerReport(fill)); assertEquals(0, hist.getAveragePricesList().size()); fill = msgFactory.newExecutionReport("clordid1", "orderid2", "execid1", OrdStatus.PARTIALLY_FILLED, Side.BUY, new BigDecimal(1000), null, new BigDecimal(91), new BigDecimal(80), new BigDecimal(91), new BigDecimal(6), new Equity("symbol1"), "account", "text"); fill.setField(new ExecTransType(ExecTransType.STATUS)); fill.setField(new ExecType(ExecType.PARTIAL_FILL)); fill.setField(new LeavesQty(909)); hist.addIncomingMessage(createServerReport(fill)); assertEquals(0, hist.getAveragePricesList().size()); fill = msgFactory.newExecutionReport("clordid1", "orderid2", "execid2", OrdStatus.PARTIALLY_FILLED, Side.BUY, new BigDecimal(1000), null, new BigDecimal(909), new BigDecimal(808), new BigDecimal( 1000), new BigDecimal(6), new Equity("symbol3"), "account", "text"); fill.setField(new ExecTransType(ExecTransType.STATUS)); fill.setField(new ExecType(ExecType.PARTIAL_FILL)); fill.setField(new LeavesQty(909)); hist.addIncomingMessage(createServerReport(fill)); assertEquals(0, hist.getAveragePricesList().size()); } public void testExecutionReportOrder() throws Exception { String orderID1 = "1"; //$NON-NLS-1$ String clOrderID1 = "1"; //$NON-NLS-1$ String execID = "3"; //$NON-NLS-1$ char ordStatus = OrdStatus.PARTIALLY_FILLED; char side = Side.SELL_SHORT; BigDecimal orderQty = new BigDecimal(1000); BigDecimal orderPrice = new BigDecimal(789); BigDecimal lastQty = new BigDecimal(100); BigDecimal lastPrice = new BigDecimal("12.3"); //$NON-NLS-1$ BigDecimal cumQty = new BigDecimal(100); BigDecimal avgPrice = new BigDecimal("12.3"); //$NON-NLS-1$ Instrument instrument = new Equity("ASDF"); //$NON-NLS-1$ SendingTime stField = new SendingTime(new Date(10000000)); SendingTime stFieldLater = new SendingTime(new Date(10010000)); Message message1 = msgFactory.newExecutionReport(null, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); message1.getHeader().setField(stField); lastQty = new BigDecimal(200); Message message2 = msgFactory.newExecutionReport(orderID1, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); message2.getHeader().setField(stField); lastQty = new BigDecimal(300); Message message3 = msgFactory.newExecutionReport(orderID1, clOrderID1, execID, ordStatus, side, orderQty, orderPrice, lastQty, lastPrice, cumQty, avgPrice, instrument, null, null); message3.getHeader().setField(stFieldLater); TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(message1)); history.addIncomingMessage(createServerReport(message2)); assertEquals(new BigDecimal(200), ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getLastQuantity()); assertEquals(orderID1, ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getOrderID().getValue()); // execution reports come in out of order, use the one that has the // OrderID in it. history = createMessageHistory(); history.addIncomingMessage(createServerReport(message2)); history.addIncomingMessage(createServerReport(message1)); assertEquals(new BigDecimal(200), ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getLastQuantity()); assertNotNull(((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getOrderID()); // expecting 3, since it's later in order and later with sending time history = createMessageHistory(); history.addIncomingMessage(createServerReport(message1)); history.addIncomingMessage(createServerReport(message2)); history.addIncomingMessage(createServerReport(message3)); assertEquals(new BigDecimal(300), ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getLastQuantity()); assertEquals(orderID1, ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getOrderID().getValue()); // 3rd msg is later by time, but arrives first, so expect msg2 to come // through history = createMessageHistory(); history.addIncomingMessage(createServerReport(message3)); history.addIncomingMessage(createServerReport(message2)); history.addIncomingMessage(createServerReport(message1)); assertEquals(new BigDecimal(200), ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getLastQuantity()); assertEquals(orderID1, ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getOrderID().getValue()); // 3rd msg is later by time, but arrives first, so expect msg2 to come // through history = createMessageHistory(); history.addIncomingMessage(createServerReport(message1)); history.addIncomingMessage(createServerReport(message3)); history.addIncomingMessage(createServerReport(message2)); assertEquals(new BigDecimal(200), ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getLastQuantity()); assertEquals(orderID1, ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getOrderID().getValue()); // 3rd msg is later by time, but arrives first, so expect msg2 to come // through history = createMessageHistory(); history.addIncomingMessage(createServerReport(message3)); history.addIncomingMessage(createServerReport(message1)); history.addIncomingMessage(createServerReport(message2)); assertEquals(new BigDecimal(200), ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getLastQuantity()); assertEquals(orderID1, ((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID( clOrderID1))).getOrderID().getValue()); } String[] messageStrings = { "8=FIX.4.29=14135=86=011=1171508063701-server02/127.0.0.114=017=ZZ-INTERNAL20=\u000031=032=038=1039=044=1054=155=R60=20070215-02:54:27150=0151=1010=237", "8=FIX.4.29=20635=834=449=MRKTC-EXCH52=20070215-02:54:29.43056=sender-2026-ORS6=011=1171508063701-server02/127.0.0.114=017=1203720=331=032=037=732438=1039=044=1054=155=R60=20070215-02:54:29150=0151=1010=201", //$NON-NLS-1$ "8=FIX.4.29=14335=86=011=1171508063702-server02/127.0.0.114=017=ZZ-INTERNAL20=\u000031=032=038=1239=044=10.154=155=R60=20070215-02:55:06150=0151=1210=081", //$NON-NLS-1$ "8=FIX.4.29=20835=834=649=MRKTC-EXCH52=20070215-02:55:09.08456=sender-2026-ORS6=011=1171508063702-server02/127.0.0.114=017=1203820=331=032=037=732538=1239=044=10.154=155=R60=20070215-02:55:09150=0151=1210=054", //$NON-NLS-1$ "8=FIX.4.29=13535=86=011=1171508063703-server02/127.0.0.114=017=ZZ-INTERNAL20=\u000031=032=038=2239=054=555=R60=20070215-02:55:27150=0151=2210=246", //$NON-NLS-1$ "8=FIX.4.29=21535=834=749=MRKTC-EXCH52=20070215-02:55:29.37856=sender-2026-ORS6=10.111=1171508063702-server02/127.0.0.114=1217=1203920=331=10.132=1237=732538=1239=244=10.154=155=R60=20070215-02:55:29150=2151=010=151", //$NON-NLS-1$ "8=FIX.4.29=20835=834=849=MRKTC-EXCH52=20070215-02:55:29.37956=sender-2026-ORS6=10.111=1171508063703-server02/127.0.0.114=1217=1204020=331=10.132=1237=732638=2239=154=555=R60=20070215-02:55:29150=1151=1010=099", //$NON-NLS-1$ "8=FIX.4.29=20935=834=949=MRKTC-EXCH52=20070215-02:55:29.38056=sender-2026-ORS6=1011=1171508063701-server02/127.0.0.114=1017=1204120=331=1032=1037=732438=1039=244=1054=155=R60=20070215-02:55:29150=2151=010=105", //$NON-NLS-1$ "8=FIX.4.29=23735=834=1049=MRKTC-EXCH52=20070215-02:55:29.38156=sender-2026-ORS6=10.0545454545454545454545454545454511=1171508063703-server02/127.0.0.114=2217=1204220=331=1032=1037=732638=2239=254=555=R60=20070215-02:55:29150=2151=010=085", //$NON-NLS-1$ "8=FIX.4.29=14135=86=011=1171508063705-server02/127.0.0.114=017=ZZ-INTERNAL20=\u000031=032=038=1039=044=1054=155=T60=20070215-02:57:58150=0151=1010=250", //$NON-NLS-1$ "8=FIX.4.29=20735=834=1649=MRKTC-EXCH52=20070215-02:58:00.93056=sender-2026-ORS6=011=1171508063705-server02/127.0.0.114=017=1204320=331=032=037=732738=1039=044=1054=155=T60=20070215-02:58:00150=0151=1010=250", //$NON-NLS-1$ "8=FIX.4.29=20635=834=1749=MRKTC-EXCH52=20070215-02:58:09.39356=sender-2026-ORS6=011=1171508063705-server02/127.0.0.114=017=1204420=331=032=037=732738=1039=444=1054=155=T60=20070215-02:58:09150=4151=010=231" //$NON-NLS-1$ }; public void testStrandedOpenOrder() throws Exception { TradeReportsHistory history = createMessageHistory(); for (String aMessageString : messageStrings) { Message aMessage = new Message(aMessageString); history.addIncomingMessage(createServerReport(aMessage)); } EventList<ReportHolder> openOrdersList = history.getOpenOrdersList(); assertEquals(0, openOrdersList.size()); } public void testFirstReport() throws Exception { TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.NEW, Side.BUY, new BigDecimal( 1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // Only PENDING NEW or PENDING REPLACE should be considered the first // report assertNull(history.getFirstReport(new org.marketcetera.trade.OrderID( "1"))); Message report = msgFactory.newExecutionReport("1001", "1", "2001", OrdStatus.PENDING_NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null); history.addIncomingMessage(createServerReport(report)); assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.REPLACED, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null,null))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.PENDING_REPLACE, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.PENDING_NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.REJECTED, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createBrokerReject(msgFactory .newOrderCancelReject(new OrderID("1001"), new ClOrdID("1"), new OrigClOrdID("1"), "ABC", new CxlRejReason( CxlRejReason.TOO_LATE_TO_CANCEL)))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); } public void testFirstReportReplace() throws Exception { TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.REPLACED, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // Only PENDING NEW or PENDING REPLACE should be considered the first // report assertNull(history.getFirstReport(new org.marketcetera.trade.OrderID( "1"))); Message report = msgFactory.newExecutionReport("1001", "1", "2001", OrdStatus.PENDING_REPLACE, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null); history.addIncomingMessage(createServerReport(report)); assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.REPLACED, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.PENDING_NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport( "1001", "1", "2001", OrdStatus.REJECTED, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); history.addIncomingMessage(createBrokerReject(msgFactory .newOrderCancelReject(new OrderID("1001"), new ClOrdID("1"), new OrigClOrdID("1"), "ABC", new CxlRejReason( CxlRejReason.TOO_LATE_TO_CANCEL)))); // first report should not change assertSame(report, history.getFirstReport( new org.marketcetera.trade.OrderID("1")).getMessage()); } public void testVisitOpenExecReports() throws Exception { TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport("1001", "1", "2001", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ASDF"), null, null))); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport("1002", "2", "2002", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("LERA"), null, null))); history.addIncomingMessage(createServerReport(msgFactory.newExecutionReport("1003", "3", "2003", OrdStatus.NEW, Side.BUY, new BigDecimal(1000), new BigDecimal(789), null, null, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("FRED"), null, null))); final List<ReportBase> visited = Lists.newArrayList(); MessageVisitor visitor = new MessageVisitor() { @Override public void visitOpenOrderExecutionReports(ReportBase report) { visited.add(report); } }; history.visitOpenOrdersExecutionReports(visitor); assertEquals(3, visited.size()); } public void testOpenOrderDupes() throws Exception { String openOrder1String = "8=FIX.4.2\u00019=293\u000135=8\u000134=1624\u000149=VTRD1\u000152=20070926-18:23:56\u000156=VTrader\u000157=VTRD:TEST\u00011=VTRDT:VTRDM:VTRDS:VTRDC\u00016=0.0\u000111=bob95001\u000114=0\u000117=65002:1011722479.0:0.1\u000120=0\u000121=2\u000130=CBOE\u000137=RDC6688-20070926\u000138=10\u000139=0\u000140=2\u000144=7.0\u000154=1\u000155=MOT\u000159=0\u000160=20070926-18:23:56\u000177=O\u0001150=0\u0001151=10\u0001167=OPT\u0001200=200710\u0001201=1\u0001202=22.5\u000110=240\u0001"; //$NON-NLS-1$ String openOrder2String = "8=FIX.4.2\u00019=293\u000135=8\u000134=1625\u000149=VTRD1\u000152=20070926-18:24:10\u000156=VTrader\u000157=VTRD:TEST\u00011=VTRDT:VTRDM:VTRDS:VTRDC\u00016=0.0\u000111=bob95003\u000114=0\u000117=65002:1011722485.0:0.1\u000120=0\u000121=2\u000130=CBOE\u000137=RDC6689-20070926\u000138=20\u000139=0\u000140=2\u000144=7.0\u000154=1\u000155=MOT\u000159=0\u000160=20070926-18:24:10\u000177=O\u0001150=0\u0001151=20\u0001167=OPT\u0001200=200710\u0001201=1\u0001202=22.5\u000110=225\u0001"; //$NON-NLS-1$ String openOrder1PendingReplaceString = "8=FIX.4.2\u00019=305\u000135=8\u000134=1626\u000149=VTRD1\u000152=20070926-18:24:13\u000156=VTrader\u000157=VTRD:TEST\u00011=VTRDT:VTRDM:VTRDS:VTRDC\u00016=0.0\u000111=bob95005\u000114=0\u000117=65002:1011722479.37647492.0\u000120=0\u000121=2\u000130=CBOE\u000137=RDC6690-20070926\u000138=10\u000139=6\u000140=2\u000141=bob95001\u000144=7.0\u000154=1\u000155=MOT\u000159=0\u000160=20070926-18:24:13\u0001150=6\u0001151=10\u0001167=OPT\u0001200=200710\u0001201=1\u0001202=22.5\u000110=210\u0001"; //$NON-NLS-1$ Message openOrder1 = new Message(openOrder1String, fixDD .getDictionary()); Message openOrder2 = new Message(openOrder2String, fixDD .getDictionary()); Message openOrder1PendingReplace = new Message( openOrder1PendingReplaceString, fixDD.getDictionary()); TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(openOrder1)); history.addIncomingMessage(createServerReport(openOrder2)); assertEquals(2, history.getOpenOrdersList().size()); history.addIncomingMessage(createServerReport(openOrder1PendingReplace)); assertEquals(2, history.getOpenOrdersList().size()); } public void testChainReplaces() throws Exception { Message executionReportA = msgFactory .newExecutionReport( "ORD1", "A", "EXEC1", OrdStatus.NEW, Side.BUY, BigDecimal.TEN, BigDecimal.ONE, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ABC"), null, null); Message executionReportB = msgFactory .newExecutionReport( "ORD2", "B", "EXEC2", OrdStatus.NEW, Side.BUY, BigDecimal.TEN, BigDecimal.ONE, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ABC"), null, null); Message executionReportC = msgFactory .newExecutionReport( "ORD1", "C", "EXEC3", OrdStatus.REPLACED, Side.BUY, BigDecimal.TEN, BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ABC"), null, null); executionReportC.setField(new OrigClOrdID("A")); //$NON-NLS-1$ Message executionReportD = msgFactory .newExecutionReport( "ORD2", "D", "EXEC4", OrdStatus.REPLACED, Side.BUY, BigDecimal.TEN, BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ABC"), null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ executionReportD.setField(new OrigClOrdID("C")); //$NON-NLS-1$ TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(executionReportA)); assertEquals(1, history.getOpenOrdersList().size()); history.addIncomingMessage(createServerReport(executionReportB)); assertEquals(2, history.getOpenOrdersList().size()); history.addIncomingMessage(createServerReport(executionReportC)); assertEquals(2, history.getOpenOrdersList().size()); history.addIncomingMessage(createServerReport(executionReportD)); assertEquals(2, history.getOpenOrdersList().size()); assertEquals( "D", history.getOpenOrdersList().get(0).getMessage().getString(ClOrdID.FIELD)); //$NON-NLS-1$ assertEquals( "B", history.getOpenOrdersList().get(1).getMessage().getString(ClOrdID.FIELD)); //$NON-NLS-1$ } /** * This tests to see that we ignore LastShares and LastPx in ExecutionReport * messages with "finished" OrdStatus values. That is, PAX tells us that we * should only pay attention to LastShares and LastPx in ExecutionReports * with OrdStatus of PARTIALLY_FILLED, FILLED, or PENDING_CANCEL, so that's * what we do. * * @throws FieldNotFound */ public void testMerrillPAXIgnoreLastShares() throws Exception { Message executionReportA = msgFactory .newExecutionReport( "ORD1", "A", "EXEC1", OrdStatus.CANCELED, Side.BUY, BigDecimal.TEN, BigDecimal.ONE, BigDecimal.TEN, BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ABC"), null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ Message executionReportB = msgFactory .newExecutionReport( "ORD2", "B", "EXEC2", OrdStatus.FILLED, Side.BUY, BigDecimal.TEN, BigDecimal.ONE, BigDecimal.TEN, BigDecimal.TEN, BigDecimal.ZERO, BigDecimal.ZERO, new Equity("ABC"), null, null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(createServerReport(executionReportA)); assertEquals(0, history.getFillsList().size()); history.addIncomingMessage(createBrokerReport(executionReportB)); assertEquals(1, history.getFillsList().size()); } public void testDuplicateReports() throws Exception { ExecutionReport report1 = createServerReport(getTestableExecutionReport()); ReportBaseImpl.assignReportID((ReportBaseImpl) report1, new ReportID(12)); ExecutionReport report2 = createServerReport(getTestableExecutionReport()); ReportBaseImpl.assignReportID((ReportBaseImpl) report2, new ReportID(22)); TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(report1); assertEquals(1, history.size()); history.addIncomingMessage(report1); assertEquals(1, history.size()); history.addIncomingMessage(report2); assertEquals(2, history.size()); history.addIncomingMessage(report2); assertEquals(2, history.size()); history.addIncomingMessage(report1); assertEquals(2, history.size()); } public void testReplaceReports() throws Exception { ExecutionReport report1 = createServerReport(getTestableExecutionReport("1")); ExecutionReport report2 = createServerReport(getTestableExecutionReport("2")); Message report3Message = getTestableExecutionReport("1"); report3Message.setField(new OrdStatus(OrdStatus.PENDING_NEW)); final ExecutionReport report3 = createServerReport(report3Message); TradeReportsHistory history = createMessageHistory(); history.addIncomingMessage(report1); assertEquals(1, history.size()); history.addIncomingMessage(report2); assertEquals(2, history.size()); history.resetMessages(new Callable<ReportBase[]>() { @Override public ReportBase[] call() throws Exception { return new ReportBase[] { report3 }; } }); assertEquals(1, history.size()); assertSame(report3, history.getAllMessagesList().get(0).getReport()); assertNull(history.getLatestMessage(new org.marketcetera.trade.OrderID("2"))); assertThat(history.getLatestMessage(new org.marketcetera.trade.OrderID("1")), sameInstance(report3Message)); assertNull(history.getLatestExecutionReport(new org.marketcetera.trade.OrderID("2"))); assertThat((ExecutionReport) history .getLatestExecutionReport(new org.marketcetera.trade.OrderID("1")), sameInstance(report3)); assertNull(history.getFirstReport(new org.marketcetera.trade.OrderID("2"))); assertThat((ExecutionReport) history .getFirstReport(new org.marketcetera.trade.OrderID("1")).getReport(), sameInstance(report3)); } public void testOpenOrderSurvivesReplaceReject() throws Exception { TradeReportsHistory history = createMessageHistory(); simulateOrderSingle(history, "1", Side.BUY, "10", "GIB", "1"); simulateReplace(history, "2", "1", Side.BUY, "10", "GIB", "3"); simulateReplaceReject(history, "3", "1", Side.BUY, "11", "GIB", "1"); EventList<ReportHolder> openOrdersList = history.getOpenOrdersList(); assertThat(openOrdersList.size(), is(1)); ReportBase openOrder = openOrdersList.get(0).getReport(); assertThat(openOrder.getOrderStatus(), is(OrderStatus.Replaced)); assertThat(openOrder.getOrderID().getValue(), is("2")); } public void testUnderlyingSymbolSupportOption() throws Exception { // options not supported in FIX 4.0 if (fixVersion != FIXVersion.FIX40) { UnderlyingSymbolSupport mockSupport = mock(UnderlyingSymbolSupport.class); TradeReportsHistory history = new TradeReportsHistory(msgFactory, mockSupport); Message message = createSimpleMessage(Side.BUY, "1"); Option option = new Option("XYZ", "200910", new BigDecimal("2"), OptionType.Put); InstrumentToMessage.SELECTOR.forInstrument(option).set(option, fixVersion.toString(), message); when(mockSupport.getUnderlying(option)).thenReturn("ABC"); history.addIncomingMessage(createBrokerReport(message)); assertThat(history.getAllMessagesList().get(0).getUnderlying(), is("ABC")); } } public void testUnderlyingSymbolSupportFuture() throws Exception { // futures not supported in FIX 4.0 if (fixVersion != FIXVersion.FIX40) { UnderlyingSymbolSupport mockSupport = mock(UnderlyingSymbolSupport.class); TradeReportsHistory history = new TradeReportsHistory(msgFactory, mockSupport); Message message = createSimpleMessage(Side.BUY, "1"); Future future = new Future("XYZ", FutureExpirationMonth.AUGUST, 15); InstrumentToMessage.SELECTOR.forInstrument(future).set(future, fixVersion.toString(), message); when(mockSupport.getUnderlying(future)).thenReturn("ABC"); history.addIncomingMessage(createBrokerReport(message)); assertThat(history.getAllMessagesList().get(0).getUnderlying(), is("ABC")); } } public void testUnderlyingSymbolSupportCurrency() throws Exception { //FX not supported in FIX 4.0 if (fixVersion != FIXVersion.FIX40) { UnderlyingSymbolSupport mockSupport = mock(UnderlyingSymbolSupport.class); TradeReportsHistory history = new TradeReportsHistory(msgFactory, mockSupport); Message message = createSimpleMessage(Side.BUY, "1"); Currency currency = new Currency("USD/GBP"); InstrumentToMessage.SELECTOR.forInstrument(currency).set(currency, fixVersion.toString(), message); when(mockSupport.getUnderlying(currency)).thenReturn("USD/GBP"); history.addIncomingMessage(createBrokerReport(message)); assertThat(history.getAllMessagesList().get(0).getUnderlying(), is("USD/GBP")); } } public void testUnderlyingSymbolSupportEquity() throws Exception { UnderlyingSymbolSupport mockSupport = mock(UnderlyingSymbolSupport.class); TradeReportsHistory history = new TradeReportsHistory(msgFactory, mockSupport); Message message = createSimpleMessage(Side.BUY, "1"); Equity equity = new Equity("IBM"); InstrumentToMessage.SELECTOR.forInstrument(equity).set(equity, fixVersion.toString(), message); when(mockSupport.getUnderlying(equity)).thenReturn("DEF"); history.addIncomingMessage(createBrokerReport(message)); assertThat(history.getAllMessagesList().get(0).getUnderlying(), is("DEF")); } private void simulateOrderSingle(TradeReportsHistory history, String orderId, char side, String quantity, String symbol, String price) throws Exception { history.addIncomingMessage(createServerReport(createMessage(OrdStatus.PENDING_NEW, orderId, side, quantity, symbol, price))); history.addIncomingMessage(createBrokerReport(createMessage(OrdStatus.NEW, orderId, side, quantity, symbol, price))); } private void simulateOutOfOrderOrderSingle(TradeReportsHistory history, String orderId, char side, String quantity, String symbol, String price) throws Exception { history.addIncomingMessage(createBrokerReport(createMessage(OrdStatus.NEW, orderId, side, quantity, symbol, price))); history.addIncomingMessage(createServerReport(createMessage(OrdStatus.PENDING_NEW, orderId, side, quantity, symbol, price))); } private void simulateOrderReject(TradeReportsHistory history, String orderId, char side, String quantity, String symbol, String price) throws Exception { history.addIncomingMessage(createServerReport(createMessage(OrdStatus.PENDING_NEW, orderId, side, quantity, symbol, price))); history.addIncomingMessage(createBrokerReport(createMessage(OrdStatus.REJECTED, orderId, side, quantity, symbol, price))); } private void simulateOrderExpiry(TradeReportsHistory history, String orderId, char side, String quantity, String symbol, String price) throws Exception { history.addIncomingMessage(createServerReport(createMessage(OrdStatus.PENDING_NEW, orderId, side, quantity, symbol, price))); history.addIncomingMessage(createBrokerReport(createMessage(OrdStatus.NEW, orderId, side, quantity, symbol, price))); history.addIncomingMessage(createBrokerReport(createMessage(OrdStatus.EXPIRED, orderId, side, quantity, symbol, price))); } private void simulateReplace(TradeReportsHistory history, String orderId, String origOrdId, char side, String quantity, String symbol, String price) throws Exception { history.addIncomingMessage(createServerReport(addOrigOrdId(createMessage(OrdStatus.PENDING_REPLACE, orderId, side, quantity, symbol, price), origOrdId))); history.addIncomingMessage(createBrokerReport(addOrigOrdId(createMessage(OrdStatus.REPLACED, orderId, side, quantity, symbol, price), origOrdId))); } private void simulateReplaceReject(TradeReportsHistory history, String orderId, String origOrdId, char side, String quantity, String symbol, String price) throws Exception { history.addIncomingMessage(createServerReport(addOrigOrdId(createMessage(OrdStatus.PENDING_REPLACE, orderId, side, quantity, symbol, price), origOrdId))); history.addIncomingMessage(createBrokerReject(createCancelReject(orderId, origOrdId))); } private void simulateCancelReject(TradeReportsHistory history, String orderId, String origOrdId) throws Exception { history.addIncomingMessage(createServerReport(addOrigOrdId(createSimpleMessage(OrdStatus.PENDING_CANCEL, orderId), origOrdId))); history.addIncomingMessage(createBrokerReject(createCancelReject(orderId, origOrdId))); } private void simulateCancel(TradeReportsHistory history, String orderId, String origOrdId) throws Exception { history.addIncomingMessage(createServerReport(addOrigOrdId(createSimpleMessage(OrdStatus.PENDING_CANCEL, orderId), origOrdId))); history.addIncomingMessage(createBrokerReport(addOrigOrdId(createSimpleMessage(OrdStatus.CANCELED, orderId), origOrdId))); } private void simulateOutOfOrderCancelReject(TradeReportsHistory history, String orderId, String origOrdId) throws Exception { history.addIncomingMessage(createBrokerReport(addOrigOrdId(createSimpleMessage(OrdStatus.CANCELED, orderId), origOrdId))); history.addIncomingMessage(createServerReport(addOrigOrdId(createSimpleMessage(OrdStatus.PENDING_CANCEL, orderId), origOrdId))); } private Message createMessage(char type, String orderId, char side, String quantity, String symbol, String price) throws FieldNotFound { return msgFactory.newExecutionReport("brokerOrderId", orderId, "execId", type, side, new BigDecimal(quantity), new BigDecimal(price), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, new Equity(symbol), null, null); } private Message createSimpleMessage(char type, String orderId) throws FieldNotFound { Message cancel = msgFactory.newExecutionReportEmpty(); cancel.setField(new OrderID("brokerOrderId")); cancel.setField(new ClOrdID(orderId)); cancel.setField(new ExecID("execId")); cancel.setField(new OrdStatus(type)); return cancel; } private Message createCancelReject(String orderId, String origOrdId) { return msgFactory.newOrderCancelReject(new OrderID("orderId"), new ClOrdID(orderId), new OrigClOrdID(origOrdId), "", new CxlRejReason()); } private Message addOrigOrdId(Message message, String origOrdId) { message.setField(new OrigClOrdID(origOrdId)); return message; } private Message getTestableExecutionReport(String orderId) throws FieldNotFound { return msgFactory.newExecutionReport("456", orderId, "987", OrdStatus.PARTIALLY_FILLED, Side.BUY, new BigDecimal(1000), new BigDecimal("12.3"), new BigDecimal(500), new BigDecimal("12.3"), new BigDecimal(500), new BigDecimal("12.3"), new Equity("IBM"), null, null); } private Message getTestableExecutionReport() throws FieldNotFound { return getTestableExecutionReport("clordid"); } public static ExecutionReport createServerReport(Message message) throws MessageCreationException { return assignReportID(Factory.getInstance().createExecutionReport(message, new BrokerID("bogus"), Originator.Server, null, null)); } public static OrderCancelReject createBrokerReject(Message message) throws MessageCreationException { return assignReportID(Factory.getInstance().createOrderCancelReject(message, new BrokerID("bogus"), Originator.Broker, null, null)); } public static ExecutionReport createBrokerReport(Message message) throws MessageCreationException { return assignReportID(Factory.getInstance().createExecutionReport(message, new BrokerID("bogus"), Originator.Broker, null, null)); } public static <T extends ReportBase> T assignReportID(T report) { ReportBaseImpl impl = (ReportBaseImpl) report; ReportBaseImpl.assignReportID(impl, new ReportID(sCounter.incrementAndGet())); return report; } private static final AtomicLong sCounter = new AtomicLong(); }