com.sumzerotrading.eod.trading.strategy.ReportGeneratorTest.java Source code

Java tutorial

Introduction

Here is the source code for com.sumzerotrading.eod.trading.strategy.ReportGeneratorTest.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.sumzerotrading.eod.trading.strategy;

import com.sumzerotrading.broker.order.OrderEvent;
import com.sumzerotrading.broker.order.OrderStatus;
import com.sumzerotrading.broker.order.TradeDirection;
import com.sumzerotrading.broker.order.TradeOrder;
import com.sumzerotrading.data.StockTicker;
import com.sumzerotrading.data.Ticker;
import com.sumzerotrading.eod.trading.strategy.TradeReferenceLine.Direction;
import static com.sumzerotrading.eod.trading.strategy.TradeReferenceLine.Direction.LONG;
import static com.sumzerotrading.eod.trading.strategy.TradeReferenceLine.Direction.SHORT;
import com.sumzerotrading.eod.trading.strategy.TradeReferenceLine.Side;
import static com.sumzerotrading.eod.trading.strategy.TradeReferenceLine.Side.ENTRY;
import static com.sumzerotrading.eod.trading.strategy.TradeReferenceLine.Side.EXIT;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.AfterClass;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

/**
 *
 * @author RobTerpilowski
 */
public class ReportGeneratorTest {

    protected ReportGenerator reportGenerator;
    protected TradeOrder order;
    protected String tmpDir;
    protected String partialDir;

    public ReportGeneratorTest() {
    }

    @BeforeClass
    public static void setUpClass() {
    }

    @AfterClass
    public static void tearDownClass() {
    }

    @Before
    public void setUp() throws Exception {
        reportGenerator = spy(ReportGenerator.class);
        order = new TradeOrder("123", new StockTicker("QQQ"), 100, TradeDirection.BUY);
        String systemTmpDir = System.getProperty("java.io.tmpdir");
        if (!systemTmpDir.endsWith("/")) {
            systemTmpDir += "/";
        }

        System.out.println("System tmp dir is: " + systemTmpDir);
        tmpDir = systemTmpDir + "rg-test/";
        partialDir = tmpDir + "partial/";
        FileUtils.deleteDirectory(new File(tmpDir));
    }

    @After
    public void tearDown() {
    }

    @Test
    public void testConstructor_NoSlashInPath() {
        MockGenerator generator = new MockGenerator(tmpDir);
        assertEquals(tmpDir + "report.csv", generator.outputFile);
        assertEquals(tmpDir, generator.outputDir);
        assertEquals(tmpDir + "partial/", generator.partialDir);
        assertTrue(Files.exists(Paths.get(generator.outputDir)));
        assertTrue(Files.exists(Paths.get(generator.partialDir)));
        assertTrue(generator.loadPartialCalled);

    }

    @Test
    public void testLoadSaveDeletePartial() throws Exception {
        ReportGenerator generator = new ReportGenerator(tmpDir);

        RoundTrip roundTrip = new RoundTrip();
        TradeReferenceLine tradeReferenceLine = buildReferenceLine("123", LONG, ENTRY);
        tradeReferenceLine.correlationId = "123";
        tradeReferenceLine.direction = TradeReferenceLine.Direction.LONG;
        tradeReferenceLine.side = TradeReferenceLine.Side.ENTRY;
        roundTrip.addTradeReference(order, tradeReferenceLine);

        order.setCurrentStatus(OrderStatus.Status.FILLED);
        OrderEvent orderEvent = new OrderEvent(order,
                new OrderStatus(OrderStatus.Status.NEW, "", "", new StockTicker("QQQ"), ZonedDateTime.now()));

        TradeReferenceLine longExitLine = buildReferenceLine("123", LONG, EXIT);
        TradeReferenceLine shortEntryLine = buildReferenceLine("123", SHORT, ENTRY);
        TradeReferenceLine shortExitLine = buildReferenceLine("123", SHORT, EXIT);

        roundTrip.addTradeReference(order, longExitLine);
        roundTrip.addTradeReference(order, shortEntryLine);

        File[] files = new File(partialDir).listFiles();
        assertEquals(0, files.length);

        generator.savePartial("123", roundTrip);

        files = new File(partialDir).listFiles();
        assertEquals(1, files.length);

        generator.roundTripMap.clear();
        assertTrue(generator.roundTripMap.isEmpty());

        generator.loadPartialRoundTrips();
        assertEquals(1, generator.roundTripMap.size());
        assertEquals(roundTrip, generator.roundTripMap.get("123"));

        generator.deletePartial("123");
        files = new File(partialDir).listFiles();
        assertEquals(0, files.length);

    }

    @Test
    public void testOrderEvent_NotFilled() {
        order.setCurrentStatus(OrderStatus.Status.NEW);
        OrderEvent orderEvent = new OrderEvent(order,
                new OrderStatus(OrderStatus.Status.NEW, "", "", new StockTicker("QQQ"), ZonedDateTime.now()));
        reportGenerator.orderEvent(orderEvent);

        verify(reportGenerator, never()).writeRoundTripToFile(any(RoundTrip.class));
    }

    @Test
    public void testOrderEvent_FirstRoundTrip() throws Exception {
        TradeReferenceLine tradeReferenceLine = new TradeReferenceLine();
        tradeReferenceLine.correlationId = "123";
        order.setCurrentStatus(OrderStatus.Status.FILLED);
        OrderEvent orderEvent = new OrderEvent(order,
                new OrderStatus(OrderStatus.Status.NEW, "", "", new StockTicker("QQQ"), ZonedDateTime.now()));

        doReturn(tradeReferenceLine).when(reportGenerator).getTradeReferenceLine(any(String.class));
        doNothing().when(reportGenerator).savePartial(any(String.class), any(RoundTrip.class));
        assertTrue(reportGenerator.roundTripMap.isEmpty());

        reportGenerator.orderEvent(orderEvent);

        verify(reportGenerator).savePartial(eq("123"), any(RoundTrip.class));
        verify(reportGenerator, never()).writeRoundTripToFile(any(RoundTrip.class));
        assertEquals(1, reportGenerator.roundTripMap.size());
    }

    @Test
    public void testOrderEvent_RoundTripExists_ButNotComplete() throws Exception {
        RoundTrip roundTrip = new RoundTrip();
        TradeReferenceLine tradeReferenceLine = new TradeReferenceLine();
        tradeReferenceLine.correlationId = "123";
        tradeReferenceLine.direction = TradeReferenceLine.Direction.LONG;
        tradeReferenceLine.side = TradeReferenceLine.Side.ENTRY;
        roundTrip.addTradeReference(order, tradeReferenceLine);

        order.setCurrentStatus(OrderStatus.Status.FILLED);
        OrderEvent orderEvent = new OrderEvent(order,
                new OrderStatus(OrderStatus.Status.NEW, "", "", new StockTicker("QQQ"), ZonedDateTime.now()));

        TradeReferenceLine longExitLine = new TradeReferenceLine();
        longExitLine.correlationId = "123";
        longExitLine.direction = TradeReferenceLine.Direction.LONG;
        longExitLine.side = TradeReferenceLine.Side.EXIT;

        reportGenerator.roundTripMap.put("123", roundTrip);

        doReturn(longExitLine).when(reportGenerator).getTradeReferenceLine(any(String.class));
        doNothing().when(reportGenerator).savePartial(any(String.class), any(RoundTrip.class));
        assertEquals(1, reportGenerator.roundTripMap.size());

        reportGenerator.orderEvent(orderEvent);

        verify(reportGenerator).savePartial("123", roundTrip);
        verify(reportGenerator, never()).writeRoundTripToFile(any(RoundTrip.class));

        assertEquals(1, reportGenerator.roundTripMap.size());
    }

    @Test
    public void testOrderEvent_RoundTripComplete() throws Exception {
        RoundTrip roundTrip = new RoundTrip();
        TradeReferenceLine tradeReferenceLine = buildReferenceLine("123", LONG, ENTRY);
        tradeReferenceLine.correlationId = "123";
        tradeReferenceLine.direction = TradeReferenceLine.Direction.LONG;
        tradeReferenceLine.side = TradeReferenceLine.Side.ENTRY;
        roundTrip.addTradeReference(order, tradeReferenceLine);

        order.setCurrentStatus(OrderStatus.Status.FILLED);
        OrderEvent orderEvent = new OrderEvent(order,
                new OrderStatus(OrderStatus.Status.NEW, "", "", new StockTicker("QQQ"), ZonedDateTime.now()));

        TradeReferenceLine longExitLine = buildReferenceLine("123", LONG, EXIT);
        TradeReferenceLine shortEntryLine = buildReferenceLine("123", SHORT, ENTRY);
        TradeReferenceLine shortExitLine = buildReferenceLine("123", SHORT, EXIT);

        roundTrip.addTradeReference(order, longExitLine);
        roundTrip.addTradeReference(order, shortEntryLine);

        reportGenerator.roundTripMap.put("123", roundTrip);

        doReturn(shortExitLine).when(reportGenerator).getTradeReferenceLine(any(String.class));
        doNothing().when(reportGenerator).writeRoundTripToFile(any(RoundTrip.class));
        doNothing().when(reportGenerator).deletePartial("123");
        assertEquals(1, reportGenerator.roundTripMap.size());

        reportGenerator.orderEvent(orderEvent);

        verify(reportGenerator).deletePartial("123");
        verify(reportGenerator).writeRoundTripToFile(roundTrip);
        assertTrue(reportGenerator.roundTripMap.isEmpty());

    }

    @Test
    public void testWriteRoundTrip() throws Exception {
        Path path = Files.createTempFile("ReportGeneratorUnitTest", ".txt");
        reportGenerator.outputFile = path.toString();
        String expected = "2016-03-19T07:01:10,Long,ABC,100,100.23,0,2016-03-20T06:01:10,101.23,0,Short,XYZ,50,250.34,0,251.34,0";

        Ticker longTicker = new StockTicker("ABC");
        Ticker shortTicker = new StockTicker("XYZ");
        int longSize = 100;
        int shortSize = 50;
        double longEntryFillPrice = 100.23;
        double longExitFillPrice = 101.23;
        double shortEntryFillPrice = 250.34;
        double shortExitFillPrice = 251.34;
        ZonedDateTime entryTime = ZonedDateTime.of(2016, 3, 19, 7, 1, 10, 0, ZoneId.systemDefault());
        ZonedDateTime exitTime = ZonedDateTime.of(2016, 3, 20, 6, 1, 10, 0, ZoneId.systemDefault());

        TradeOrder longEntry = new TradeOrder("123", longTicker, longSize, TradeDirection.BUY);
        longEntry.setFilledPrice(longEntryFillPrice);
        longEntry.setOrderFilledTime(entryTime);

        TradeOrder longExit = new TradeOrder("123", longTicker, longSize, TradeDirection.SELL);
        longExit.setFilledPrice(longExitFillPrice);
        longExit.setOrderFilledTime(exitTime);

        TradeOrder shortEntry = new TradeOrder("123", shortTicker, shortSize, TradeDirection.SELL);
        shortEntry.setFilledPrice(shortEntryFillPrice);
        shortEntry.setOrderFilledTime(entryTime);

        TradeOrder shortExit = new TradeOrder("123", shortTicker, shortSize, TradeDirection.BUY);
        shortExit.setFilledPrice(shortExitFillPrice);
        shortExit.setOrderFilledTime(exitTime);

        RoundTrip roundTrip = new RoundTrip();
        roundTrip.longEntry = longEntry;
        roundTrip.longExit = longExit;
        roundTrip.shortEntry = shortEntry;
        roundTrip.shortExit = shortExit;

        System.out.println("Writing out to file: " + path);

        reportGenerator.writeRoundTripToFile(roundTrip);

        List<String> lines = Files.readAllLines(path);
        assertEquals(1, lines.size());
        assertEquals(expected, lines.get(0));

        Files.deleteIfExists(path);

    }

    @Test
    public void testReportGeneratorEndToEnd() throws Exception {
        StockTicker longTicker = new StockTicker("ABC");
        StockTicker shortTicker = new StockTicker("XYZ");

        ZonedDateTime entryOrderTime = ZonedDateTime.of(2016, 3, 25, 6, 18, 35, 0, ZoneId.systemDefault());
        ZonedDateTime exitOrderTime = ZonedDateTime.of(2016, 3, 25, 6, 19, 35, 0, ZoneId.systemDefault());

        String directory = System.getProperty("java.io.tmpdir");
        if (!directory.endsWith("/")) {
            directory += "/";
        }
        Path reportPath = Paths.get(directory + "report.csv");
        Files.deleteIfExists(reportPath);
        System.out.println("Creating directory at: " + directory);
        ReportGenerator generator = new ReportGenerator(directory);

        TradeOrder longEntryOrder = new TradeOrder("123", longTicker, 100, TradeDirection.BUY);
        longEntryOrder.setFilledPrice(100.00);
        longEntryOrder.setReference("EOD-Pair-Strategy:guid-123:Entry:Long*");
        longEntryOrder.setCurrentStatus(OrderStatus.Status.FILLED);
        longEntryOrder.setOrderFilledTime(entryOrderTime);

        TradeOrder shortEntryOrder = new TradeOrder("234", shortTicker, 50, TradeDirection.SELL);
        shortEntryOrder.setFilledPrice(50.00);
        shortEntryOrder.setReference("EOD-Pair-Strategy:guid-123:Entry:Short*");
        shortEntryOrder.setCurrentStatus(OrderStatus.Status.FILLED);
        shortEntryOrder.setOrderFilledTime(entryOrderTime);

        generator.orderEvent(new OrderEvent(longEntryOrder, null));
        assertFalse(Files.exists(reportPath));

        generator.orderEvent(new OrderEvent(shortEntryOrder, null));
        assertFalse(Files.exists(reportPath));

        TradeOrder longExitOrder = new TradeOrder("1234", longTicker, 100, TradeDirection.SELL);
        longExitOrder.setFilledPrice(105.00);
        longExitOrder.setReference("EOD-Pair-Strategy:guid-123:Exit:Long*");
        longExitOrder.setCurrentStatus(OrderStatus.Status.FILLED);
        longExitOrder.setOrderFilledTime(exitOrderTime);

        TradeOrder shortExitOrder = new TradeOrder("2345", shortTicker, 50, TradeDirection.BUY);
        shortExitOrder.setFilledPrice(40.00);
        shortExitOrder.setReference("EOD-Pair-Strategy:guid-123:Exit:Short*");
        shortExitOrder.setCurrentStatus(OrderStatus.Status.FILLED);
        shortExitOrder.setOrderFilledTime(exitOrderTime);

        generator.orderEvent(new OrderEvent(longExitOrder, null));
        assertFalse(Files.exists(reportPath));

        generator.orderEvent(new OrderEvent(shortExitOrder, null));
        assertTrue(Files.exists(reportPath));

        List<String> lines = Files.readAllLines(reportPath);
        assertEquals(1, lines.size());

        String line = lines.get(0);
        String expected = "2016-03-25T06:18:35,Long,ABC,100,100.0,0,2016-03-25T06:19:35,105.0,0,Short,XYZ,50,50.0,0,40.0,0";
        assertEquals(expected, line);

        generator.orderEvent(new OrderEvent(longEntryOrder, null));
        generator.orderEvent(new OrderEvent(longExitOrder, null));
        generator.orderEvent(new OrderEvent(shortEntryOrder, null));
        generator.orderEvent(new OrderEvent(shortExitOrder, null));

        lines = Files.readAllLines(reportPath);
        assertEquals(2, lines.size());
        assertEquals(expected, lines.get(0));
        assertEquals(expected, lines.get(1));

    }

    protected TradeReferenceLine buildReferenceLine(String id, Direction direction, Side side) {
        TradeReferenceLine line = new TradeReferenceLine();
        line.correlationId = id;
        line.direction = direction;
        line.side = side;

        return line;
    }

    private static class MockGenerator extends ReportGenerator {

        boolean loadPartialCalled;

        public MockGenerator(String dir) {
            super(dir);
        }

        @Override
        public void loadPartialRoundTrips() throws IOException {
            loadPartialCalled = true;
        }

    }

}