/* =========================================================== * TradeManager : a application to trade strategies for the Java(tm) platform * =========================================================== * * (C) Copyright 2011-2011, by Simon Allen and Contributors. * * Project Info: org.trade * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * [Java is a trademark or registered trademark of Oracle, Inc. * in the United States and other countries.] * * (C) Copyright 2011-2011, by Simon Allen and Contributors. * * Original Author: Simon Allen; * Contributor(s): -; * * Changes * ------- * */ package org.trade.broker; import static org.junit.Assert.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.time.ZonedDateTime; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import javax.swing.Timer; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.trade.core.dao.Aspect; import org.trade.core.dao.Aspects; import org.trade.core.factory.ClassFactory; import org.trade.core.properties.ConfigProperties; import org.trade.core.util.TradingCalendar; import org.trade.persistent.PersistentModel; import org.trade.persistent.PersistentModelException; import org.trade.persistent.dao.Candle; import org.trade.persistent.dao.Contract; import org.trade.persistent.dao.TradeOrder; import org.trade.persistent.dao.TradePosition; import org.trade.persistent.dao.Tradestrategy; import org.trade.persistent.dao.Tradingday; import org.trade.persistent.dao.Tradingdays; import org.trade.ui.TradeAppLoadConfig; import org.trade.ui.base.BasePanel; /** * Some tests for the {@link DataUtilities} class. * * @author Simon Allen * @version $Revision: 1.0 $ */ public class TWSBrokerModelTest implements BrokerChangeListener { private final static Logger _log = LoggerFactory.getLogger(TWSBrokerModelTest.class); @Rule public TestName name = new TestName(); private Tradingdays tradingdays = null; private BrokerModel tWSBrokerModel; private PersistentModel tradePersistentModel = null; private static Integer clientId; private static Integer port = null; private static String host = null; private static int testCaseGrandTotal = 0; private static Timer timer = null; private boolean connectionFailed = false; private static AtomicInteger timerRunning = null; private final static Object lockCoreUtilsTest = new Object(); private final static String _broker = BrokerModel._broker; private BrokerDataRequestMonitor brokerDataRequestProgressMonitor = null; /** * Method setUpBeforeClass. * * @throws java.lang.Exception */ @BeforeClass public static void setUpBeforeClass() throws Exception { try { TradeAppLoadConfig.loadAppProperties(); clientId = ConfigProperties.getPropAsInt("trade.tws.clientId"); port = new Integer(ConfigProperties.getPropAsString("trade.tws.port")); host = ConfigProperties.getPropAsString("trade.tws.host"); timer = new Timer(250, new ActionListener() { public void actionPerformed(ActionEvent e) { synchronized (lockCoreUtilsTest) { timerRunning.addAndGet(250); lockCoreUtilsTest.notifyAll(); } } }); } catch (Exception e) { fail("Error on setup " + e.getMessage()); } } /** * Method setUp. Try to connect to the Broker for these tests that but * candle data from the broker and test the throtle monitor. * * @throws java.lang.Exception */ @Before public void setUp() throws Exception { try { tradePersistentModel = (PersistentModel) ClassFactory .getServiceForInterface(PersistentModel._persistentModel, this); tWSBrokerModel = (BrokerModel) ClassFactory.getServiceForInterface(_broker, this); tWSBrokerModel.addMessageListener(this); tWSBrokerModel.onConnect(host, port, clientId); timerRunning = new AtomicInteger(0); timer.start(); synchronized (lockCoreUtilsTest) { while (!tWSBrokerModel.isConnected() && !connectionFailed) { lockCoreUtilsTest.wait(); } } timer.stop(); if (!tWSBrokerModel.isConnected()) _log.warn("Could not connect to TWS test will be ignored.", tWSBrokerModel.isConnected()); } catch (InterruptedException e) { _log.info("Thread interrupt: " + e.getMessage()); } } /** * Method tearDown. * * @throws java.lang.Exception */ @After public void tearDown() throws Exception { deleteData(); if (tWSBrokerModel.isConnected()) tWSBrokerModel.onDisconnect(); /* * Wait 10min between each test run to avoid pacing violations. */ if (((Math.floor(testCaseGrandTotal / 58d) == (testCaseGrandTotal / 58d)) && (testCaseGrandTotal > 0)) && tWSBrokerModel.isConnected()) { timerRunning = new AtomicInteger(0); timer.start(); synchronized (lockCoreUtilsTest) { while (timerRunning.get() / 1000 < 601) { if ((timerRunning.get() % 60000) == 0) { String message = "Please wait " + (10 - (timerRunning.get() / 1000 / 60)) + " minutes as there are more than 60 data requests."; _log.warn(message); } lockCoreUtilsTest.wait(); } } timer.stop(); } } /** * Method tearDownAfterClass. * * @throws java.lang.Exception */ @AfterClass public static void tearDownAfterClass() throws Exception { } @Test public void testOneSymbolTodayOnBrokerData() { tradingdays = new Tradingdays(); try { if (tWSBrokerModel.isConnected()) { String fileName = "trade/test/org/trade/broker/OneSymbolToday.csv"; ZonedDateTime tradingDay = TradingCalendar.getDateTimeNowMarketTimeZone(); tradingDay = TradingCalendar.getPrevTradingDay(tradingDay); Tradingday tradingday = new Tradingday(TradingCalendar.getTradingDayStart(tradingDay), TradingCalendar.getTradingDayEnd(tradingDay)); tradingdays.populateDataFromFile(fileName, tradingday); for (Tradingday item : tradingdays.getTradingdays()) { tradePersistentModel.persistTradingday(item); } brokerDataRequestProgressMonitor = new BrokerDataRequestMonitor(tWSBrokerModel, tradePersistentModel, tradingdays); brokerDataRequestProgressMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); String message = String.format("Completed %d%%.", progress); _log.warn(message); } else if ("information".equals(evt.getPropertyName())) { _log.warn("Information message: " + (String) evt.getNewValue()); if (brokerDataRequestProgressMonitor.isDone()) { String message = String.format("Completed %d%%.", 100); _log.warn(message); } } else if ("error".equals(evt.getPropertyName())) { _log.error("Error getting history data." + ((Exception) evt.getNewValue()).getMessage()); } } }); brokerDataRequestProgressMonitor.execute(); synchronized (lockCoreUtilsTest) { while (tWSBrokerModel.isConnected() && !connectionFailed && !brokerDataRequestProgressMonitor.isDone()) { lockCoreUtilsTest.wait(1000); } } } } catch (Exception | AssertionError ex) { String msg = "Error running " + name.getMethodName() + " msg: " + ex.getMessage(); _log.error(msg); fail(msg); } } @Test public void testOneMonthContractsOnBrokerData() { tradingdays = new Tradingdays(); try { if (tWSBrokerModel.isConnected()) { String fileName = "trade/test/org/trade/broker/OneMonthContracts.csv"; ZonedDateTime tradingDay = TradingCalendar.getDateTimeNowMarketTimeZone(); tradingDay = TradingCalendar.getPrevTradingDay(tradingDay); Tradingday tradingday = new Tradingday(TradingCalendar.getTradingDayStart(tradingDay), TradingCalendar.getTradingDayEnd(tradingDay)); tradingdays.populateDataFromFile(fileName, tradingday); for (Tradingday item : tradingdays.getTradingdays()) { tradePersistentModel.persistTradingday(item); } brokerDataRequestProgressMonitor = new BrokerDataRequestMonitor(tWSBrokerModel, tradePersistentModel, tradingdays); brokerDataRequestProgressMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); String message = String.format("Completed %d%%.", progress); _log.warn(message); } else if ("information".equals(evt.getPropertyName())) { _log.warn("Information message: " + (String) evt.getNewValue()); if (brokerDataRequestProgressMonitor.isDone()) { String message = String.format("Completed %d%%.", 100); _log.warn(message); } } else if ("error".equals(evt.getPropertyName())) { _log.error("Error getting history data." + ((Exception) evt.getNewValue()).getMessage()); } } }); brokerDataRequestProgressMonitor.execute(); synchronized (lockCoreUtilsTest) { while (tWSBrokerModel.isConnected() && !connectionFailed && !brokerDataRequestProgressMonitor.isDone()) { lockCoreUtilsTest.wait(1000); } } } } catch (Exception | AssertionError ex) { String msg = "Error running " + name.getMethodName() + " msg: " + ex.getMessage(); _log.error(msg); fail(msg); } } @Test public void testOneSymbolTwoMthsOnBrokerData() { tradingdays = new Tradingdays(); try { if (tWSBrokerModel.isConnected()) { String fileName = "trade/test/org/trade/broker/OneSymbolTwoMths.csv"; ZonedDateTime tradingDay = TradingCalendar.getDateTimeNowMarketTimeZone(); tradingDay = TradingCalendar.getPrevTradingDay(tradingDay); Tradingday tradingday = new Tradingday(TradingCalendar.getTradingDayStart(tradingDay), TradingCalendar.getTradingDayEnd(tradingDay)); tradingdays.populateDataFromFile(fileName, tradingday); /* * Set the chart days to one day so no over lap. */ for (Tradingday item : tradingdays.getTradingdays()) { for (Tradestrategy tradestrategy : item.getTradestrategies()) { tradestrategy.setChartDays(1); } } for (Tradingday item : tradingdays.getTradingdays()) { tradePersistentModel.persistTradingday(item); } brokerDataRequestProgressMonitor = new BrokerDataRequestMonitor(tWSBrokerModel, tradePersistentModel, tradingdays); brokerDataRequestProgressMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); String message = String.format("Completed %d%%.", progress); _log.warn(message); } else if ("information".equals(evt.getPropertyName())) { _log.warn("Information message: " + (String) evt.getNewValue()); if (brokerDataRequestProgressMonitor.isDone()) { String message = String.format("Completed %d%%.", 100); _log.warn(message); } } else if ("error".equals(evt.getPropertyName())) { _log.error("Error getting history data." + ((Exception) evt.getNewValue()).getMessage()); } } }); brokerDataRequestProgressMonitor.execute(); synchronized (lockCoreUtilsTest) { while (tWSBrokerModel.isConnected() && !connectionFailed && !brokerDataRequestProgressMonitor.isDone()) { lockCoreUtilsTest.wait(1000); } } } } catch (Exception | AssertionError ex) { String msg = "Error running " + name.getMethodName() + " msg: " + ex.getMessage(); _log.error(msg); fail(msg); } } @Test public void testMultiContractsMultiDaysOnBrokerData() { tradingdays = new Tradingdays(); try { if (tWSBrokerModel.isConnected()) { String fileName = "trade/test/org/trade/broker/MultiContractsMultiDays.csv"; ZonedDateTime tradingDay = TradingCalendar.getDateTimeNowMarketTimeZone(); tradingDay = TradingCalendar.getPrevTradingDay(tradingDay); Tradingday tradingday = new Tradingday(TradingCalendar.getTradingDayStart(tradingDay), TradingCalendar.getTradingDayEnd(tradingDay)); tradingdays.populateDataFromFile(fileName, tradingday); /* * Set the chart days to one day so no over lap. */ for (Tradingday item : tradingdays.getTradingdays()) { for (Tradestrategy tradestrategy : item.getTradestrategies()) { tradestrategy.setChartDays(1); } } for (Tradingday item : tradingdays.getTradingdays()) { tradePersistentModel.persistTradingday(item); } brokerDataRequestProgressMonitor = new BrokerDataRequestMonitor(tWSBrokerModel, tradePersistentModel, tradingdays); brokerDataRequestProgressMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (Integer) evt.getNewValue(); String message = String.format("Completed %d%%.", progress); _log.warn(message); } else if ("information".equals(evt.getPropertyName())) { _log.warn("Information message: " + (String) evt.getNewValue()); if (brokerDataRequestProgressMonitor.isDone()) { String message = String.format("Completed %d%%.", 100); _log.warn(message); } } else if ("error".equals(evt.getPropertyName())) { _log.error("Error getting history data." + ((Exception) evt.getNewValue()).getMessage()); } } }); brokerDataRequestProgressMonitor.execute(); synchronized (lockCoreUtilsTest) { while (tWSBrokerModel.isConnected() && !connectionFailed && !brokerDataRequestProgressMonitor.isDone()) { lockCoreUtilsTest.wait(1000); } } } } catch (Exception | AssertionError ex) { String msg = "Error running " + name.getMethodName() + " msg: " + ex.getMessage(); _log.error(msg); fail(msg); } } /** * Method deleteData. Clean the test data added. * * */ private void deleteData() { try { Aspects candles = tradePersistentModel.findAspectsByClassName(Candle.class.getName()); for (Aspect item : candles.getAspect()) { tradePersistentModel.removeAspect(item); } Aspects tradestrategies = tradePersistentModel.findAspectsByClassName(Tradestrategy.class.getName()); for (Aspect item : tradestrategies.getAspect()) { tradePersistentModel.removeAspect(item); } Aspects contracts = tradePersistentModel.findAspectsByClassName(Contract.class.getName()); for (Aspect item : contracts.getAspect()) { tradePersistentModel.removeAspect(item); } Aspects tradingdays = tradePersistentModel.findAspectsByClassName(Tradingday.class.getName()); for (Aspect item : tradingdays.getAspect()) { tradePersistentModel.removeAspect(item); } } catch (Exception e) { fail("Error deleteData Msg: " + e.getMessage()); } finally { _log.info("All data deleted"); } } public void connectionOpened() { _log.info("Connection opened"); } public void connectionClosed(boolean forced) { connectionFailed = true; _log.info("Connection closed"); } /** * Method executionDetailsEnd. * * @param execDetails * ConcurrentHashMap<Integer,TradeOrder> */ public void executionDetailsEnd(ConcurrentHashMap<Integer, TradeOrder> execDetails) { } /** * Method historicalDataComplete. * * @param tradestrategy * Tradestrategy */ public void historicalDataComplete(Tradestrategy tradestrategy) { try { _log.info("Symbol: " + tradestrategy.getContract().getSymbol() + " Candles saved: " + tradePersistentModel.findCandleCount(tradestrategy.getTradingday().getIdTradingDay(), tradestrategy.getContract().getIdContract())); } catch (PersistentModelException ex) { _log.error("Error historicalDataComplete Msg: " + ex.getMessage()); } } /** * Method managedAccountsUpdated. * * @param accountNumber * String */ public void managedAccountsUpdated(String accountNumber) { } /** * Method fAAccountsCompleted. Notifies all registered listeners that the * brokerManagerModel has received all FA Accounts information. * */ public void fAAccountsCompleted() { } /** * Method updateAccountTime. * * @param accountNumber * String */ public void updateAccountTime(String accountNumber) { } /** * Method brokerError. * * @param brokerError * BrokerModelException */ public void brokerError(BrokerModelException ex) { if (502 == ex.getErrorCode()) { _log.info("TWS is not running test will not be run"); return; } if (ex.getErrorId() == 1) { _log.error("Error: " + ex.getErrorCode(), ex.getMessage(), ex); } else if (ex.getErrorId() == 2) { _log.warn("Warning: " + ex.getMessage(), BasePanel.WARNING); } else if (ex.getErrorId() == 3) { _log.info("Information: " + ex.getMessage(), BasePanel.INFORMATION); } else { _log.error("Unknown Error Id Code: " + ex.getErrorCode(), ex.getMessage(), ex); } } /** * Method tradeOrderFilled. * * @param tradeOrder * TradeOrder */ public void tradeOrderFilled(TradeOrder tradeOrder) { } /** * Method tradeOrderCancelled. * * @param tradeOrder * TradeOrder */ public void tradeOrderCancelled(TradeOrder tradeOrder) { } /** * Method tradeOrderStatusChanged. * * @param tradeOrder * TradeOrder */ public void tradeOrderStatusChanged(TradeOrder tradeOrder) { } /** * Method positionClosed. * * @param trade * Trade */ public void positionClosed(TradePosition trade) { } /** * Method openOrderEnd. * * @param openOrders * ConcurrentHashMap<Integer,TradeOrder> */ public void openOrderEnd(ConcurrentHashMap<Integer, TradeOrder> openOrders) { } }