Java tutorial
/*********************************************************************************** * AlgoTrader Enterprise Trading Framework * * Copyright (C) 2015 AlgoTrader GmbH - All rights reserved * * All information contained herein is, and remains the property of AlgoTrader GmbH. * The intellectual and technical concepts contained herein are proprietary to * AlgoTrader GmbH. Modification, translation, reverse engineering, decompilation, * disassembly or reproduction of this material is strictly forbidden unless prior * written permission is obtained from AlgoTrader GmbH * * Fur detailed terms and conditions consult the file LICENSE.txt or contact * * AlgoTrader GmbH * Aeschstrasse 6 * 8834 Schindellegi ***********************************************************************************/ package ch.algotrader.cache; import java.math.BigDecimal; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.io.Charsets; import org.hibernate.Hibernate; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.proxy.HibernateProxy; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.mockito.Mockito; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ClassPathResource; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory; import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; import org.springframework.transaction.support.TransactionTemplate; import ch.algotrader.dao.NamedParam; import ch.algotrader.dao.security.StockDao; import ch.algotrader.entity.Account; import ch.algotrader.entity.AccountImpl; import ch.algotrader.entity.Position; import ch.algotrader.entity.PositionImpl; import ch.algotrader.entity.exchange.Exchange; import ch.algotrader.entity.exchange.ExchangeImpl; import ch.algotrader.entity.property.Property; import ch.algotrader.entity.property.PropertyImpl; import ch.algotrader.entity.security.Combination; import ch.algotrader.entity.security.Forex; import ch.algotrader.entity.security.ForexImpl; import ch.algotrader.entity.security.Security; import ch.algotrader.entity.security.SecurityFamily; import ch.algotrader.entity.security.SecurityFamilyImpl; import ch.algotrader.entity.security.SecurityImpl; import ch.algotrader.entity.security.Stock; import ch.algotrader.entity.strategy.Strategy; import ch.algotrader.entity.strategy.StrategyImpl; import ch.algotrader.entity.trade.LimitOrderVOBuilder; import ch.algotrader.entity.trade.OrderVO; import ch.algotrader.enumeration.CombinationType; import ch.algotrader.enumeration.Currency; import ch.algotrader.enumeration.FeedType; import ch.algotrader.enumeration.OrderServiceType; import ch.algotrader.enumeration.QueryType; import ch.algotrader.enumeration.Side; import ch.algotrader.enumeration.TransactionType; import ch.algotrader.esper.Engine; import ch.algotrader.esper.EngineManager; import ch.algotrader.esper.NoopEngine; import ch.algotrader.service.CombinationService; import ch.algotrader.service.ExternalMarketDataService; import ch.algotrader.service.LookupService; import ch.algotrader.service.OrderService; import ch.algotrader.service.PropertyService; import ch.algotrader.service.TransactionService; import ch.algotrader.service.noop.NoopHistoricalDataServiceImpl; import ch.algotrader.wiring.DefaultConfigTestBase; import ch.algotrader.wiring.common.CommonConfigWiring; import ch.algotrader.wiring.common.EventDispatchPostInitWiring; import ch.algotrader.wiring.common.EventDispatchWiring; import ch.algotrader.wiring.core.CacheWiring; import ch.algotrader.wiring.core.CoreConfigWiring; import ch.algotrader.wiring.core.DaoWiring; import ch.algotrader.wiring.core.HibernateWiring; import ch.algotrader.wiring.core.ServiceWiring; import ch.algotrader.wiring.core.SimulationWiring; /** * @author <a href="mailto:aflury@algotrader.ch">Andy Flury</a> */ public class CacheTest extends DefaultConfigTestBase { private static final String ACCOUNT_NAME = "TEST_ACCOUNT"; private static final String PROPERTY_NAME = "TEST_PROPERTY"; private static final String STRATEGY_NAME = "TEST_STRATEGY"; private static CacheManager cache; private static AnnotationConfigApplicationContext context; private static TransactionTemplate txTemplate; private static EmbeddedDatabase database; private static long securityFamilyId1; // NON_TRADEABLE private static long securityFamilyId2; // NON_TRADEABLE private static long strategyId1; private static long securityId1; // EUR.USD private static long securityId2; // USD.CHF private static long accountId1; @BeforeClass public static void beforeClass() { context = new AnnotationConfigApplicationContext(); context.getEnvironment().setActiveProfiles("embeddedDataSource", "simulation"); // register in-memory db EmbeddedDatabaseFactory dbFactory = new EmbeddedDatabaseFactory(); dbFactory.setDatabaseType(EmbeddedDatabaseType.H2); dbFactory.setDatabaseName("testdb;MODE=MYSQL;DATABASE_TO_UPPER=FALSE"); database = dbFactory.getDatabase(); context.getDefaultListableBeanFactory().registerSingleton("dataSource", database); EngineManager engineManager = Mockito.mock(EngineManager.class); Mockito.when(engineManager.getCurrentEPTime()).thenReturn(new Date()); Mockito.when(engineManager.getCurrentEPTime()).thenReturn(new Date()); context.getDefaultListableBeanFactory().registerSingleton("engineManager", engineManager); AtomicReference<TransactionService> transactionService = new AtomicReference<>(); Engine engine = new NoopEngine(StrategyImpl.SERVER); context.getDefaultListableBeanFactory().registerSingleton("serverEngine", engine); ExternalMarketDataService externalMarketDataService = Mockito.mock(ExternalMarketDataService.class); context.getDefaultListableBeanFactory().registerSingleton("externalMarketDataService", externalMarketDataService); context.getDefaultListableBeanFactory().registerSingleton("historicalDataService", new NoopHistoricalDataServiceImpl()); Mockito.when(externalMarketDataService.getFeedType()).thenReturn(FeedType.IB.name()); // register Wirings context.register(CommonConfigWiring.class, CoreConfigWiring.class, EventDispatchWiring.class, EventDispatchPostInitWiring.class, HibernateWiring.class, CacheWiring.class, DaoWiring.class, ServiceWiring.class, SimulationWiring.class); context.refresh(); transactionService.set(context.getBean(TransactionService.class)); cache = context.getBean(CacheManager.class); txTemplate = context.getBean(TransactionTemplate.class); // create the database ResourceDatabasePopulator dbPopulator = new ResourceDatabasePopulator(); dbPopulator.addScript(new ClassPathResource("/db/h2/h2.sql")); DatabasePopulatorUtils.execute(dbPopulator, database); // populate the database SessionFactory sessionFactory = context.getBean(SessionFactory.class); Session session = sessionFactory.openSession(); Exchange exchange1 = new ExchangeImpl(); exchange1.setName("IDEALPRO"); exchange1.setCode("IDEALPRO"); exchange1.setTimeZone("US/Eastern"); session.save(exchange1); SecurityFamily family1 = new SecurityFamilyImpl(); family1.setName("FX"); family1.setTickSizePattern("0<0.1"); family1.setCurrency(Currency.USD); family1.setExchange(exchange1); family1.setTradeable(true); family1.setContractSize(1.0); securityFamilyId1 = (Long) session.save(family1); SecurityFamily family2 = new SecurityFamilyImpl(); family2.setName("NON_TRADEABLE"); family2.setTickSizePattern("0<0.1"); family2.setCurrency(Currency.USD); family2.setTradeable(false); family2.setContractSize(1.0); securityFamilyId2 = (Long) session.save(family2); Forex security1 = new ForexImpl(); security1.setSymbol("EUR.USD"); security1.setBaseCurrency(Currency.EUR); security1.setSecurityFamily(family1); securityId1 = (Long) session.save(security1); Forex security2 = new ForexImpl(); security2.setSymbol("GBP.USD"); security2.setBaseCurrency(Currency.GBP); security2.setSecurityFamily(family1); security2.setUnderlying(security1); securityId2 = (Long) session.save(security2); Strategy strategy1 = new StrategyImpl(); strategy1.setName(STRATEGY_NAME); strategyId1 = (Long) session.save(strategy1); Position position1 = new PositionImpl(); position1.setQuantity(222); position1.setStrategy(strategy1); position1.setSecurity(security2); position1.setCost(new BigDecimal(0.0)); position1.setRealizedPL(new BigDecimal(0.0)); session.save(position1); Property property1 = new PropertyImpl(); property1.setName(PROPERTY_NAME); property1.setDoubleValue(10.0); property1.setPropertyHolder(strategy1); session.save(property1); strategy1.getProps().put(PROPERTY_NAME, property1); Account account1 = new AccountImpl(); account1.setName("TEST"); account1.setBroker("TEST"); account1.setOrderServiceType(OrderServiceType.SIMULATION.toString()); accountId1 = (Long) session.save(account1); session.flush(); session.close(); } @AfterClass public static void afterClass() { // cleanup the database ResourceDatabasePopulator dbPopulator = new ResourceDatabasePopulator(); dbPopulator.addScript(new ByteArrayResource("DROP ALL OBJECTS".getBytes(Charsets.US_ASCII))); DatabasePopulatorUtils.execute(dbPopulator, database); context.close(); net.sf.ehcache.CacheManager ehCacheManager = net.sf.ehcache.CacheManager.getInstance(); ehCacheManager.shutdown(); } @Test public void testSecurity() { Security security = cache.get(SecurityImpl.class, securityId2); Assert.assertNotNull(security); Assert.assertNotNull(security.getSecurityFamily()); Assert.assertFalse(security.getSecurityFamily() instanceof HibernateProxy); Assert.assertNotNull(security.getUnderlying()); Assert.assertFalse(security.getUnderlying() instanceof HibernateProxy); } @Test public void testStock() { SecurityFamily securityFamily = cache.get(SecurityFamilyImpl.class, securityFamilyId1); Stock stock = cache.findUnique(Stock.class, "from StockImpl where symbol = :symbol", QueryType.HQL, new NamedParam("symbol", "AAPL")); Assert.assertNull(stock); net.sf.ehcache.CacheManager.getInstance().clearAll(); StockDao stockDao = context.getBean(StockDao.class); txTemplate.execute(txStatus -> { Set<Stock> stocks = new HashSet<>(); Stock stock1 = Stock.Factory.newInstance(); stock1.setSymbol("AAPL"); stock1.setDescription("AAPL Inc"); stock1.setSecurityFamily(securityFamily); stocks.add(stock1); stockDao.saveAll(stocks); return null; }); Stock stock2 = cache.findUnique(Stock.class, "from StockImpl where symbol = :symbol", QueryType.HQL, new NamedParam("symbol", "AAPL")); Assert.assertNotNull(stock2); } @Test public void testPosition() { TransactionService transactionService = context.getBean(TransactionService.class); String queryString = "select p from PositionImpl as p join p.strategy as s where p.security.id = :securityId and s.name = :strategyName"; Position position1 = cache.findUnique(Position.class, queryString, QueryType.HQL, new NamedParam("strategyName", STRATEGY_NAME), new NamedParam("securityId", securityId2)); Position position2 = cache.get(PositionImpl.class, position1.getId()); Assert.assertEquals(222, position1.getQuantity()); Assert.assertNotNull(position2); Assert.assertEquals(position1, position2); Assert.assertSame(position1, position2); txTemplate.execute(txStatus -> { transactionService.createTransaction(securityId2, STRATEGY_NAME, null, new Date(), 10000, new BigDecimal(1.0), null, null, null, Currency.USD, TransactionType.BUY, ACCOUNT_NAME, null); return null; }); Position position3 = cache.findUnique(Position.class, queryString, QueryType.HQL, new NamedParam("strategyName", STRATEGY_NAME), new NamedParam("securityId", securityId2)); Position position4 = cache.get(PositionImpl.class, position3.getId()); Assert.assertEquals(10222, position3.getQuantity()); Assert.assertNotNull(position4); Assert.assertEquals(position3, position4); Assert.assertSame(position3, position4); txTemplate.execute(txStatus -> { transactionService.createTransaction(securityId2, STRATEGY_NAME, null, new Date(), 10000, new BigDecimal(1.0), null, null, null, Currency.USD, TransactionType.SELL, ACCOUNT_NAME, null); return null; }); Position position5 = cache.findUnique(Position.class, queryString, QueryType.HQL, new NamedParam("strategyName", STRATEGY_NAME), new NamedParam("securityId", securityId2)); Position position6 = cache.get(PositionImpl.class, position5.getId()); Assert.assertEquals(222, position5.getQuantity()); Assert.assertNotNull(position6); Assert.assertEquals(position5, position6); Assert.assertSame(position5, position6); } @Test public void testOrder() { OrderService orderService = context.getBean(OrderService.class); LookupService lookupService = context.getBean(LookupService.class); List<Position> positions1 = lookupService.getOpenPositionsByStrategy(STRATEGY_NAME); Assert.assertEquals(1, positions1.size()); OrderVO order1 = LimitOrderVOBuilder.create() // .setLimit(new BigDecimal(10.0)) // .setAccountId(accountId1) // .setSecurityId(securityId1) // .setStrategyId(strategyId1) // .setQuantity(1000) // .setSide(Side.BUY) // .build(); orderService.sendOrder(order1); List<Position> positions2 = lookupService.getOpenPositionsByStrategy(STRATEGY_NAME); Assert.assertEquals(2, positions2.size()); String queryString = "select p from PositionImpl as p join p.strategy as s where p.security.id = :securityId and s.name = :strategyName"; Position position1 = cache.findUnique(Position.class, queryString, QueryType.HQL, new NamedParam("strategyName", STRATEGY_NAME), new NamedParam("securityId", securityId1)); Assert.assertNotNull(position1); Assert.assertEquals(1000, position1.getQuantity()); OrderVO order2 = LimitOrderVOBuilder.create() // .setLimit(new BigDecimal(20.0)) // .setAccountId(accountId1) // .setSecurityId(securityId1) // .setStrategyId(strategyId1) // .setQuantity(1000) // .setSide(Side.SELL) // .build(); orderService.sendOrder(order2); Position position2 = lookupService.getPositionBySecurityAndStrategy(securityId1, STRATEGY_NAME); Assert.assertEquals(0, position2.getQuantity()); Assert.assertEquals(new BigDecimal("10000.00"), position2.getRealizedPL()); Assert.assertEquals(position1, position2); Assert.assertSame(position1, position2); } @Test public void testHQL() { String queryString = "from PositionImpl as p join fetch p.security as s where s.id = :id"; NamedParam namedParam = new NamedParam("id", securityId2); Position position2 = cache.find(Position.class, queryString, QueryType.HQL, namedParam).iterator().next(); Assert.assertNotNull(position2); Position position3 = cache.find(Position.class, queryString, QueryType.HQL, namedParam).iterator().next(); Assert.assertNotNull(position2); Assert.assertEquals(position2, position3); Assert.assertSame(position2, position3); } @Test public void testRefresh() { LookupService lookupService = context.getBean(LookupService.class); // expect SecurityFamily with Exchange proxied SecurityFamily securityFamily = cache.get(SecurityFamilyImpl.class, securityFamilyId1); Assert.assertFalse(Hibernate.isInitialized(securityFamily.getExchange())); // expect Security / SecurityFamily / Exchange fully initialized Security security1 = lookupService.findUnique(SecurityImpl.class, "from SecurityImpl as s " + // "left join fetch s.underlying as ul " + // "join fetch s.securityFamily as f " + // "join fetch f.exchange as ex " + // "where s.id = :id", // QueryType.HQL, true, new NamedParam("id", securityId1)); Assert.assertTrue(Hibernate.isInitialized(security1.getSecurityFamily())); Assert.assertTrue(Hibernate.isInitialized(security1.getSecurityFamily().getExchange())); } @Test public void testCombination() { CombinationService combinationService = context.getBean(CombinationService.class); // combination / component modification long combinationId = txTemplate.execute(txStatus -> { return combinationService.createCombination(CombinationType.BUTTERFLY, securityFamilyId2).getId(); }); Combination combination1 = (Combination) cache.get(SecurityImpl.class, combinationId); Assert.assertNotNull(combination1); Combination combination2 = txTemplate.execute(txStatus -> { return combinationService.addComponentQuantity(combinationId, securityId1, 1000); }); Assert.assertEquals(1, combination1.getComponentCount()); Assert.assertEquals(1000, combination1.getComponents().iterator().next().getQuantity()); Assert.assertEquals(1, combination2.getComponentCount()); Assert.assertEquals(1000, combination2.getComponents().iterator().next().getQuantity()); Combination combination3 = txTemplate.execute(txStatus -> { return combinationService.addComponentQuantity(combinationId, securityId2, 5000); }); Assert.assertEquals(2, combination1.getComponentCount()); Assert.assertEquals(6000, combination1.getComponentTotalQuantity()); Assert.assertEquals(2, combination3.getComponentCount()); Assert.assertEquals(6000, combination3.getComponentTotalQuantity()); Combination combination4 = txTemplate.execute(txStatus -> { return combinationService.removeComponent(combinationId, securityId1); }); Assert.assertEquals(1, combination1.getComponentCount()); Assert.assertEquals(1, combination4.getComponentCount()); txTemplate.execute(txStatus -> { combinationService.deleteCombination(combinationId); return null; }); Combination combination5 = (Combination) cache.get(SecurityImpl.class, combinationId); Assert.assertNull(combination5); } @Test public void testProperty() { PropertyService propertyService = context.getBean(PropertyService.class); // property Strategy strategy = cache.get(StrategyImpl.class, strategyId1); Assert.assertEquals(1, strategy.getProps().size()); txTemplate.execute(txStatus -> { return propertyService.addProperty(strategyId1, "test", 12, false); }); // Assert.assertEquals(2, strategy.getProps().size()); // Assert.assertEquals(12, strategy.getIntProperty("test")); txTemplate.execute(txStatus -> { return propertyService.removeProperty(strategyId1, "test"); }); // Assert.assertEquals(1, strategy.getProps().size()); } }