package org.marketcetera.core.position.impl; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.marketcetera.core.position.impl.OrderingComparison.comparesEqualTo; import java.math.BigDecimal; import java.text.MessageFormat; import java.util.Random; import org.marketcetera.core.position.MockTrade; import org.marketcetera.core.position.PositionKeyFactory; import org.marketcetera.core.position.PositionMetrics; import org.marketcetera.core.position.Trade; import org.marketcetera.trade.Equity; import org.marketcetera.util.log.SLF4JLoggerProxy; /* $License$ */ /** * Template for verifying that 2 {@link PositionMetricsCalculator} * implementations produce the same results with random data. * * @author <a href="mailto:will@marketcetera.com">Will Horn</a> * @version $Id: PositionMetricsCalculatorTestTemplate.java 10804 2009-10-08 * 18:00:15Z will $ * @since 1.5.0 */ public abstract class PositionMetricsCalculatorTestTemplate implements Runnable { int numTests; public PositionMetricsCalculatorTestTemplate(int numTests) { this.numTests = numTests; } public void run() { Random random = new Random(1); BigDecimal incomingPosition = randomBigDecimal(random); BigDecimal closingPrice = randomBigDecimal(random); SLF4JLoggerProxy.debug(this, MessageFormat.format( "Incoming position is {0} and closing price is {1}.", incomingPosition, closingPrice)); PositionMetricsCalculator calculator = createCalculator( incomingPosition, closingPrice); PositionMetricsCalculator basicCalculator = createBenchmarkCalculator( incomingPosition, closingPrice); for (int i = 0; i < numTests; i++) { if (random.nextBoolean()) { BigDecimal tradePrice = randomBigDecimal(random); SLF4JLoggerProxy.debug(this, MessageFormat.format( "Iteration {0}: Tick of ${1}", i, tradePrice)); assertPositionMetrics(basicCalculator.tick(tradePrice), calculator.tick(tradePrice), i); } else { Trade<?> trade = createTrade(random.nextBoolean(), randomBigDecimal(random), randomBigDecimal(random)); SLF4JLoggerProxy.debug(this, MessageFormat.format( "Iteration {0}: Trade of {1} ${2}", i, trade .getQuantity(), trade.getPrice())); assertPositionMetrics(basicCalculator.trade(trade), calculator .trade(trade), i); } } } protected PositionMetricsCalculator createBenchmarkCalculator( BigDecimal incomingPosition, BigDecimal closingPrice) { return new BasicCalculator(incomingPosition, closingPrice); } private BigDecimal randomBigDecimal(Random random) { return new BigDecimal(random.nextInt(10000)).divide(new BigDecimal( "100")); } private Trade<?> createTrade(boolean buy, BigDecimal quantity, BigDecimal price) { return new MockTrade<Equity>(PositionKeyFactory.createEquityKey("ABC", "asdf", "Yoram"), buy ? quantity : quantity.negate(), price); } private void assertPositionMetrics(PositionMetrics expected, PositionMetrics actual, int i) { assertBigDecimal(expected.getPosition(), actual.getPosition(), i); assertBigDecimal(expected.getPositionPL(), actual.getPositionPL(), i); assertBigDecimal(expected.getTradingPL(), actual.getTradingPL(), i); assertBigDecimal(expected.getRealizedPL(), actual.getRealizedPL(), i); assertBigDecimal(expected.getUnrealizedPL(), actual.getUnrealizedPL(), i); assertBigDecimal(expected.getTotalPL(), actual.getTotalPL(), i); } private void assertBigDecimal(BigDecimal expected, BigDecimal actual, int i) { if (expected == null) { assertNull("Iteration " + i, actual); } else { assertThat("Iteration " + i, actual, comparesEqualTo(expected)); } } protected abstract PositionMetricsCalculator createCalculator( BigDecimal incomingPosition, BigDecimal closingPrice); }