package org.marketcetera.strategy; import static org.junit.Assert.*; import static org.marketcetera.event.LogEventLevel.DEBUG; import static org.marketcetera.event.LogEventLevel.ERROR; import static org.marketcetera.event.LogEventLevel.INFO; import static org.marketcetera.event.LogEventLevel.WARN; import static org.marketcetera.module.Messages.MODULE_NOT_STARTED_STATE_INCORRECT; import static org.marketcetera.module.Messages.MODULE_NOT_STOPPED_STATE_INCORRECT; import static org.marketcetera.strategy.Status.*; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.Future; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.Test; import org.marketcetera.client.Client; import org.marketcetera.client.brokers.BrokerStatus; import org.marketcetera.client.brokers.BrokersStatus; import org.marketcetera.core.notifications.Notification; import org.marketcetera.core.position.PositionKey; import org.marketcetera.event.Event; import org.marketcetera.event.EventTestBase; import org.marketcetera.event.LogEvent; import org.marketcetera.event.TradeEvent; import org.marketcetera.marketdata.*; import org.marketcetera.marketdata.MarketDataModuleTestBase.DataSink; import org.marketcetera.marketdata.bogus.BogusFeedModuleFactory; import org.marketcetera.module.CopierModule.SynchronousRequest; import org.marketcetera.module.*; import org.marketcetera.quickfix.FIXVersion; import org.marketcetera.strategy.StrategyTestBase.MockRecorderModule.DataReceived; import org.marketcetera.trade.*; import org.marketcetera.trade.Currency; import org.marketcetera.util.log.SLF4JLoggerProxy; import org.marketcetera.util.misc.NamedThreadFactory; import quickfix.Message; import quickfix.field.TransactTime; /* $License$ */ /** * Provides a set of tests for a script language. * * <p>Each new script language to support should extend this class. * * @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a> * @version $Id: LanguageTestBase.java 16864 2014-03-20 19:39:48Z colin $ * @since 1.0.0 */ public abstract class LanguageTestBase extends StrategyTestBase { /** * Tests a strategy that should compile and make sure its enclosing module can start up. * * @throws Exception if an error occurs */ @Test public void compilesAndTestsCallbacks() throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); ModuleURN strategyModule = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); verifyPropertyNonNull("onStart"); doSuccessfulStartTest(strategyModule); stopStrategy(strategyModule); assertFalse(moduleManager.getModuleInfo(strategyModule).getState().isStarted()); verifyPropertyNonNull("onStop"); } /** * Tests a strategy that will not start due to a compilation error. * * @throws Exception if an error occurs. */ @Test public void doesNotCompile() throws Exception { new ExpectedFailure<ModuleException>(FAILED_TO_START) { @Override protected void run() throws Exception { StrategyCoordinates strategy = getStrategyWillNotCompile(); verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); } }; } /** * Tests that the script won't compile if the wrong language is specified. * * @throws Exception if an error occurs */ @Test public void wrongLanguage() throws Exception { // this picks a language that is *not* the one we are testing, doesn't really matter which one final Language wrongLanguage = Language.values()[(getLanguage().ordinal() + 1) % Language.values().length]; new ExpectedFailure<ModuleException>(FAILED_TO_START) { @Override protected void run() throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); verifyStrategyStartsAndStops(strategy.getName(), wrongLanguage, strategy.getFile(), null, null, null); } }; } /** * Tests that the script won't execute if it does not contain a class that subclasses Strategy. * * @throws Exception if an error occurs */ @Test public void noStrategySubclass() throws Exception { new ExpectedFailure<ModuleException>(FAILED_TO_START) { @Override protected void run() throws Exception { StrategyCoordinates strategy = getStrategyWrongClass(); verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); } }; } /** * Verifies that a strategy can contain multiple classes. * * @throws Exception if an error occurs */ @Test public void multipleClasses() throws Exception { StrategyCoordinates strategy = getStrategyMultipleClasses(); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null)); } /** * Tests the scenario where the name of the strategy does not match * a class in the script. * * @throws Exception if an error occurs */ @Test public void noMatchingName() throws Exception { final StrategyCoordinates strategy2 = getStrategyCompiles(); new ExpectedFailure<ModuleException>(FAILED_TO_START) { @Override protected void run() throws Exception { verifyStrategyStartsAndStops("SomeNameThatDoesNotMatch", getLanguage(), strategy2.getFile(), null, null, null); } }; } /** * Tests a strategy that overrides only {@link RunningStrategy#onAsk(org.marketcetera.event.AskEvent)}. * * <p>This test makes sure that a strategy that selectively overrides call-backs does not fail when * the non-overridden call-backs are executed. * * @throws Exception if an error occurs */ @Test public void almostEmptyStrategy() throws Exception { StrategyCoordinates strategy = getEmptyStrategy(); // need to piece this together manually as only "onAsk" will be set ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); verifyNullProperties(); // create an emitter module that will emit the types of data that the strategy must be able to process ModuleURN dataEmitterURN = createModule(StrategyTestBase.StrategyDataEmissionModule.Factory.PROVIDER_URN); // plumb the emitter together with the strategy (the data is transmitted when the request is made) DataFlowID dataFlowID = moduleManager.createDataFlow(new DataRequest[] { new DataRequest(dataEmitterURN, null), new DataRequest(strategyURN) }, false); // shut down the flow moduleManager.cancel(dataFlowID); // verify the data was received verifyPropertyNonNull("onAsk"); } /** * Tests a scenario's ability to retrieve parameters. * * @throws Exception if an error occurs */ @Test public void parameterStrategy() throws Exception { StrategyCoordinates strategy = getParameterStrategy(); Properties parameters = new Properties(); parameters.setProperty("onAsk", "onAskValue"); parameters.setProperty("onBid", "onBidValue"); parameters.setProperty("onExecutionReport", "onExecutionReportValue"); parameters.setProperty("onTrade", "onTradeValue"); // onOther deliberately omitted in order to test request for non-existent parameter ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); verifyNullProperties(); // create an emitter module that will emit the types of data that the strategy must be able to process ModuleURN dataEmitterURN = createModule(StrategyTestBase.StrategyDataEmissionModule.Factory.PROVIDER_URN); // plumb the emitter together with the strategy (the data is transmitted when the request is made) DataFlowID dataFlowID = moduleManager.createDataFlow(new DataRequest[] { new DataRequest(dataEmitterURN, null), new DataRequest(strategyURN) }, false); // shut down the flow moduleManager.cancel(dataFlowID); // verify the data was received verifyPropertyNonNull("onAsk"); verifyPropertyNonNull("onBid"); verifyPropertyNonNull("onTrade"); verifyPropertyNonNull("onExecutionReport"); } /** * Tests what happens if a runtime error occurs in the strategy script. * * @throws Exception if an error occurs */ @Test public void runtimeError() throws Exception { // runtime error in onStart final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldFailOnStart", "true"); final ModuleURN strategyURN = moduleManager.createModule(StrategyModuleFactory.PROVIDER_URN, null, strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); // failed "onStart" means that the strategy is in error status and will not receive any data new ExpectedFailure<ModuleException>(FAILED_TO_START) { @Override protected void run() throws Exception { moduleManager.start(strategyURN); } }; // "onStart" has completed, but verify that the last statement in the strategy was never executed verifyPropertyNull("onStart"); // verify the status of the strategy verifyStrategyStatus(strategyURN, FAILED); setPropertiesToNull(); parameters.clear(); AbstractRunningStrategy.setProperty("shouldFailOnStop", "true"); // runtime error in onStop ModuleURN strategyURN2 = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); doSuccessfulStartTest(strategyURN2); stopStrategy(strategyURN2); AbstractRunningStrategy.setProperty("shouldFailOnStop", null); // runtime error in each callback doCallbackFailsTest("shouldFailOnAsk", new String[] { "onBid", "onCancel", "onExecutionReport", "onTrade", "onOther", "onDividend" }); doCallbackFailsTest("shouldFailOnBid", new String[] { "onAsk", "onCancel", "onExecutionReport", "onTrade", "onOther", "onDividend" }); doCallbackFailsTest("shouldFailOnExecutionReport", new String[] { "onAsk", "onBid", "onCancel", "onTrade", "onOther", "onDividend" }); doCallbackFailsTest("shouldFailOnTrade", new String[] { "onAsk", "onBid", "onCancel", "onExecutionReport", "onOther", "onDividend" }); doCallbackFailsTest("shouldFailOnOther", new String[] { "onAsk", "onBid", "onCancel", "onExecutionReport", "onTrade", "onDividend" }); doCallbackFailsTest("shouldFailOnDividend", new String[] { "onAsk", "onBid", "onCancel", "onExecutionReport", "onTrade", "onOther" }); } /** * Tests a strategy with an arbitrarily long onStart. * * @throws Exception if an error occurs */ @Test public void longRunningStart() throws Exception { final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldLoopOnStart", "true"); assertNull(AbstractRunningStrategy.getProperty("loopDone")); // need to manually start the strategy because it will be in "STARTING" status for a long long time final ModuleURN strategyURN = moduleManager.createModule(StrategyModuleFactory.PROVIDER_URN, null, strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); // start the strategy in another thread Future<ModuleURN> future = doAsynchronous(new Callable<ModuleURN>() { @Override public ModuleURN call() throws Exception { moduleManager.start(strategyURN); return strategyURN; } }); // wait until the strategy enters "STARTING" MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { try { return getStatus(strategyURN).equals(STARTING); } catch (Exception e) { return false; } } }); // take a little snooze - long enough that the strategy "onStart" will have completed if it was going to Thread.sleep(5000); // verify the status hasn't changed and that "onStart" hasn't completed assertNull(AbstractRunningStrategy.getProperty("loopDone")); verifyStrategyStatus(strategyURN, STARTING); // tell the loop to stop AbstractRunningStrategy.setProperty("shouldStopLoop", "true"); future.get(); // wait until the strategy has time to complete MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { return getStatus(strategyURN).equals(RUNNING); } }); // verify that the "onStart" loop completed assertNotNull(AbstractRunningStrategy.getProperty("loopDone")); moduleManager.stop(strategyURN); } /** * Tests a strategy with an arbitrarily long onStop. * * @throws Exception if an error occurs */ @Test public void longRunningStop() throws Exception { final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldLoopOnStop", "true"); final ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); // begin stop process assertNull(AbstractRunningStrategy.getProperty("loopDone")); final List<Throwable> thrownExceptions = new ArrayList<Throwable>(); // stop the strategy in another thread Future<ModuleURN> future = doAsynchronous(new Callable<ModuleURN>() { @Override public ModuleURN call() throws Exception { moduleManager.stop(strategyURN); return strategyURN; } }); // wait until the strategy enters "STOPPING" status MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { return getStatus(strategyURN).equals(STOPPING); } }); // take a little snooze - long enough that the strategy "onStop" will have completed if it was going to Thread.sleep(5000); // verify the status hasn't changed and that "onStop" hasn't completed assertNull(AbstractRunningStrategy.getProperty("loopDone")); verifyStrategyStatus(strategyURN, STOPPING); // tell the loop to stop AbstractRunningStrategy.setProperty("shouldStopLoop", "true"); future.get(); // wait until the strategy has time to complete MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { return getStatus(strategyURN).equals(STOPPED); } }); // verify that the "onStop" loop completed assertNotNull(AbstractRunningStrategy.getProperty("loopDone")); assertTrue(thrownExceptions.isEmpty()); } /** * This test makes sure that data cannot be requested or sent after stop has begun. * * @throws Exception if an error occurs */ @Test public void restrictedActionsDuringStop() throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); // set up stop loop to request data *and* to delay stopping long enough for the request to be honored (if it were allowed) parameters.setProperty("shouldRequestDataOnStop", "bogus"); parameters.setProperty("symbols", "METC"); parameters.setProperty("shouldLoopOnStop", "true"); final ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); // strategy is in running state // nothing received verifyNullProperties(); // no market data request made yet verifyPropertyNull("requestID"); // the stop loop marker is not present verifyPropertyNull("loopDone"); // stop the strategy in another thread Future<ModuleURN> future = doAsynchronous(new Callable<ModuleURN>() { @Override public ModuleURN call() throws Exception { moduleManager.stop(strategyURN); return strategyURN; } }); // wait until the strategy enters "STOPPING" status MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { return getStatus(strategyURN).equals(STOPPING); } }); // strategy will wait in this status until we tell it to stop // wait long enough for some data to have leaked through Thread.sleep(5000); // tell the loop to complete its stop AbstractRunningStrategy.setProperty("shouldStopLoop", "true"); // wait until strategy stops future.get(); verifyStrategyStopped(strategyURN); // make sure the loop completed normally verifyPropertyNonNull("loopDone"); // make sure that no data was received and that the request failed verifyNullProperties(); assertEquals("0", verifyPropertyNonNull("requestID")); } /** * Tests receipt of market data from a valid, started market data provider. * * @throws Exception if an error occurs */ @Test public void marketDataRequests() throws Exception { for(int apiStringCounter=0;apiStringCounter<=0;apiStringCounter++) { getMarketData(BogusFeedModuleFactory.IDENTIFIER, "GOOG,YHOO,MSFT,METC", (apiStringCounter == 0), new Properties()); // strategy is now receiving data Thread.sleep(2500); // verify that bid/ask/trades have been received // TODO substitute a market data provider that provides a known script of events verifyPropertyNonNull("onAsk"); verifyPropertyNonNull("onBid"); // TODO almost certainly Bogus will provide a trade within 5 seconds, but it's nonetheless // not deterministic. the fix is to implement the deterministic provider described above verifyPropertyNonNull("onTrade"); setPropertiesToNull(); } } /** * Tests a market data request from a market data provider that does not exist. * * @throws Exception if an error occurs */ @Test public void marketDataRequestFromNonexistentSource() throws Exception { for(int apiStringCounter=0;apiStringCounter<=0;apiStringCounter++) { verifyNullProperties(); getMarketData("provider-does-not-exist", "GOOG,YHOO,MSFT,METC", (apiStringCounter == 0), new Properties()); // TODO same note as above: create a market data provider that deterministically produces data Thread.sleep(2500); // the script does not fail, but no market data was provided verifyNullProperties(); } } /** * Tests a market data request from a market data provider that exists but has not been started. * * @throws Exception if an error occurs */ @Test public void marketDataRequestFromUnstartedSource() throws Exception { for(int apiStringCounter=0;apiStringCounter<=0;apiStringCounter++) { // stop the bogus provider assertTrue(moduleManager.getModuleInfo(BogusFeedModuleFactory.INSTANCE_URN).getState().isStarted()); moduleManager.stop(BogusFeedModuleFactory.INSTANCE_URN); assertFalse(moduleManager.getModuleInfo(BogusFeedModuleFactory.INSTANCE_URN).getState().isStarted()); // request market data from the stopped provider getMarketData(BogusFeedModuleFactory.IDENTIFIER, "GOOG,YHOO,MSFT,METC", (apiStringCounter == 0), new Properties()); // TODO same note as above: create a market data provider that deterministically produces data Thread.sleep(2500); // the script does not fail, but no market data was provided verifyNullProperties(); // start the bogus module again moduleManager.start(BogusFeedModuleFactory.INSTANCE_URN); assertTrue(moduleManager.getModuleInfo(BogusFeedModuleFactory.INSTANCE_URN).getState().isStarted()); } } /** * Tests a strategy's ability to cancel a market data request. * * @throws Exception if an error occurs */ @Test public void cancelMarketDataRequest() throws Exception { for(int apiStringCounter=0;apiStringCounter<=0;apiStringCounter++) { ModuleURN strategyURN = getMarketData(BogusFeedModuleFactory.IDENTIFIER, "GOOG,YHOO,MSFT,METC", (apiStringCounter == 0), new Properties()); // TODO same note as above: create a market data provider that deterministically produces data Thread.sleep(5000); // market data request has produced some data, verify that now verifyPropertyNonNull("onAsk"); verifyPropertyNonNull("onBid"); // TODO almost certainly Bogus will provide a trade within 5 seconds, but it's nonetheless // not deterministic. the fix is to implement the deterministic provider described above verifyPropertyNonNull("onTrade"); // retrieve the id of the market data request verifyPropertyNonNull("requestID"); Properties properties = AbstractRunningStrategy.getProperties(); long id = Long.parseLong(properties.getProperty("requestID")); // reset properties to clear data received markers setPropertiesToNull(); // set the indicators back in the properties to tell the script what to cancel properties.setProperty("shouldCancel", "true"); properties.setProperty("requestID", Long.toString(id)); // execute the onCallback method in the running strategy to force the market data // request cancel getRunningStrategy(strategyURN).getRunningStrategy().onCallback(this); // collect more market data, or, give it the chance to, anyway Thread.sleep(2500); setPropertiesToNull(); Thread.sleep(2500); // make sure no more data was received verifyPropertyNull("onAsk"); verifyPropertyNull("onBid"); } } /** * Tests what happens when a strategy tries to cancel a non-existent market data request. * * @throws Exception if an error occurs */ @Test public void cancelNonExistentMarketDataRequest() throws Exception { final StrategyCoordinates strategy = getStrategyCompiles(); // create a strategy that does not request market data ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); verifyNullProperties(); // set the indicators to tell the script what to cancel Properties properties = new Properties(); properties.setProperty("shouldCancel", "true"); properties.setProperty("requestID", Long.toString(System.currentTimeMillis())); // execute the onCallback method in the running strategy to force the market data // request cancel getRunningStrategy(strategyURN).getRunningStrategy().onCallback(this); // no error should result from this // plumb the faux market data provider to the strategy to verify the strategy // is still working doSuccessfulStartTest(strategyURN); } /** * Tests a strategy's ability to request and receive a callback after a certain interval. * * @throws Exception if an error occurs */ @Test public void callbackAfter() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldRequestCallbackAfter", "1000"); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 1000ms after start Thread.sleep(2000); verifyPropertyNonNull("onCallback"); } /** * Tests a strategy's ability to request and receive a callback periodically. * * @throws Exception if an error occurs */ @Test public void callbackEvery() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldRequestCallbackEvery", "1000,2000"); // callback every 2s, initial delay 1s verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 5000ms after start Thread.sleep(4000); String numberOfCalls = verifyPropertyNonNull("onCallback"); assertEquals("2", numberOfCalls); // 2 callbacks expected } /** * Tests a strategy's ability to request and receive a callback at a certain time. * * @throws Exception if an error occurs */ @Test public void callbackAt() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); Date callbackAt = new Date(System.currentTimeMillis() + 2000); parameters.setProperty("shouldRequestCallbackAt", Long.toString(callbackAt.getTime())); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 2000ms after start Thread.sleep(2000); verifyPropertyNonNull("onCallback"); } /** * Tests a strategy's ability to request and receive a callback after an initial delay. * * @throws Exception if an error occurs */ @Test public void callbackAfterEarlier() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldRequestCallbackAfter", "-1000"); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 1000ms after start Thread.sleep(1000); String numberOfCalls = verifyPropertyNonNull("onCallback"); assertEquals("1", numberOfCalls); } /** * Tests a strategy's ability to request and receive a callback after an initial delay. * * @throws Exception if an error occurs */ @Test public void callbackEveryEarlier() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldRequestCallbackEvery", "-1000,2000"); // callback every 2s, initial delay 1s verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 5000ms after start Thread.sleep(3000); String numberOfCalls = verifyPropertyNonNull("onCallback"); assertEquals("2", numberOfCalls); // 2 callbacks expected } /** * Tests a strategy's ability to request and receive a callback before the current time. * * @throws Exception if an error occurs */ @Test public void callbackAtEarlier() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); Date callbackAt = new Date(System.currentTimeMillis() - 2000); parameters.setProperty("shouldRequestCallbackAt", Long.toString(callbackAt.getTime())); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // callback should happen immediately, but wait a second or so Thread.sleep(1000); String callbackTime = verifyPropertyNonNull("onCallback"); assertTrue(Long.parseLong(callbackTime) < System.currentTimeMillis()); } /** * Tests a strategy's ability to request and receive a callback after a zero interval. * * @throws Exception if an error occurs */ @Test public void callbackAfterZero() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldRequestCallbackAfter", "0"); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 1000ms after start Thread.sleep(1000); String numberOfCalls = verifyPropertyNonNull("onCallback"); assertEquals("1", numberOfCalls); } /** * Tests a strategy's ability to request and receive a callback after a zero interval. * * @throws Exception if an error occurs */ @Test public void callbackEveryZero() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldRequestCallbackEvery", "0,2000"); // callback every 2s, initial delay 1s verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 5000ms after start Thread.sleep(3000); String numberOfCalls = verifyPropertyNonNull("onCallback"); assertEquals("2", numberOfCalls); // 2 callbacks expected } /** * Tests a strategy's ability to request and receive a callback at the current time. * * @throws Exception if an error occurs */ @Test public void callbackAtZero() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); Date callbackAt = new Date(); parameters.setProperty("shouldRequestCallbackAt", Long.toString(callbackAt.getTime())); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // callback should happen immediately, but wait a second or so Thread.sleep(1000); String numberOfCalls = verifyPropertyNonNull("onCallback"); assertEquals("1", numberOfCalls); } /** * A strategy's callback request should fails if a negative interval is passed in. * * @throws Exception if an error occurs */ @Test public void callbackEveryNegativeInterval() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldRequestCallbackEvery", "1000,-2000"); // negative interval verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 5000ms after start Thread.sleep(3000); verifyPropertyNonNull("callbackEveryException"); // should cause IllegalArgumentException on request, no callback is run verifyPropertyNull("onCallback"); } /** * Tests what happens when a strategy commits a run-time error during a callback. * * @throws Exception if an error occurs */ @Test public void callbackFails() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldFailOnCallback", "true"); parameters.setProperty("shouldRequestCallbackAfter", "0"); verifyPropertyNull("onCallback"); ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); doSuccessfulStartTest(strategyURN); // callback should happen immediately, but wait a second or so Thread.sleep(1000); // strategy should not have completed onCallback loop, but should still be running verifyPropertyNull("onCallback"); setPropertiesToNull(); // make sure the strategy is still alive and kicking doSuccessfulStartTestNoVerification(strategyURN); verifyNonNullProperties(); } /** * Tests that a strategy can request and receive a null call-back payload without failing. * * @throws Exception if an error occurs */ @Test public void callbackAtWithNullPayload() throws Exception { final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); Date callbackAt = new Date(); parameters.setProperty("shouldRequestCallbackAt", Long.toString(callbackAt.getTime())); parameters.setProperty("callbackDataIsNull", "true"); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // callback should happen immediately, but wait a second or so Thread.sleep(1000); String numberOfCalls = verifyPropertyNonNull("onCallback"); assertEquals("1", numberOfCalls); } /** * Tests that simultaneous callbacks are executed properly. * * @throws Exception if an error occurs */ @Test public void simultaneousCallbacks() throws Exception { // start a strategy final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); Date callbackAt = new Date(System.currentTimeMillis()); parameters.setProperty("shouldRequestCallbackAt", Long.toString(callbackAt.getTime())); parameters.setProperty("shouldDoubleCallbacks", "true"); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 2000ms after start Thread.sleep(2000); // make sure 2 callbacks were received assertEquals("2", verifyPropertyNonNull("onCallback")); } /** * Tests that callbacks are not executed after the strategy is stopped. * * @throws Exception if an error occurs */ @Test public void callbacksAfterStop() throws Exception { final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); Date callbackAt = new Date(System.currentTimeMillis()+6000); parameters.setProperty("shouldRequestCallbackAt", Long.toString(callbackAt.getTime())); verifyPropertyNull("onCallback"); ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); doSuccessfulStartTest(strategyURN); stopStrategy(strategyURN); assertTrue("The strategy should have been stopped before the callback - increase the callback delay", System.currentTimeMillis() < callbackAt.getTime()); Thread.sleep(7500); // callback should have happened assertTrue(System.currentTimeMillis() > callbackAt.getTime()); verifyPropertyNull("onCallback"); } /** * Tests that sequential callbacks are executed properly. * * @throws Exception if an error occurs */ @Test public void sequentialCallbacks() throws Exception { final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); Date callbackAt = new Date(System.currentTimeMillis() + 1000); parameters.setProperty("shouldRequestCallbackAt", Long.toString(callbackAt.getTime())); parameters.setProperty("shouldDoubleCallbacks", "true"); Date callback2At = new Date(System.currentTimeMillis() + 1500); AbstractRunningStrategy.getProperties().setProperty("shouldRequestCallbackAt", Long.toString(callback2At.getTime())); verifyPropertyNull("onCallback"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); // make sure to wait until at least 2000ms after start Thread.sleep(2000); // make sure 4 callbacks were received (param + props * doubled) assertEquals("4", verifyPropertyNonNull("onCallback")); } /** * Tests a strategy's ability to suggest trades. * * @throws Exception if an error occurs */ @Test public void suggestions() throws Exception { Properties parameters = new Properties(); // null suggestion parameters.setProperty("orderShouldBeNull", "true"); doSuggestionTest(parameters, new OrderSingleSuggestion[0]); // null score parameters.clear(); doSuggestionTest(parameters, new OrderSingleSuggestion[0]); // null identifier parameters.setProperty("score", "1"); doSuggestionTest(parameters, new OrderSingleSuggestion[0]); // zero length identifier parameters.setProperty("identifier", ""); doSuggestionTest(parameters, new OrderSingleSuggestion[0]); // first complete suggestion parameters.setProperty("identifier", "some identifier"); OrderSingleSuggestion expectedSuggestion = Factory.getInstance().createOrderSingleSuggestion(); expectedSuggestion.setScore(new BigDecimal("1")); expectedSuggestion.setIdentifier("some identifier"); OrderSingle suggestedOrder = Factory.getInstance().createOrderSingle(); expectedSuggestion.setOrder(suggestedOrder); doSuggestionTest(parameters, new OrderSingleSuggestion[] { expectedSuggestion }); // add an account parameters.setProperty("account", "some account"); suggestedOrder.setAccount("some account"); expectedSuggestion.setOrder(suggestedOrder); doSuggestionTest(parameters, new OrderSingleSuggestion[] { expectedSuggestion }); // add order type parameters.setProperty("orderType", OrderType.Market.name()); suggestedOrder.setOrderType(OrderType.Market); expectedSuggestion.setOrder(suggestedOrder); doSuggestionTest(parameters, new OrderSingleSuggestion[] { expectedSuggestion }); // add price parameters.setProperty("price", "100.23"); suggestedOrder.setPrice(new BigDecimal("100.23")); expectedSuggestion.setOrder(suggestedOrder); doSuggestionTest(parameters, new OrderSingleSuggestion[] { expectedSuggestion }); // add quantity parameters.setProperty("quantity", "10000"); suggestedOrder.setQuantity(new BigDecimal("10000")); expectedSuggestion.setOrder(suggestedOrder); doSuggestionTest(parameters, new OrderSingleSuggestion[] { expectedSuggestion }); // add side parameters.setProperty("side", Side.Buy.name()); suggestedOrder.setSide(Side.Buy); expectedSuggestion.setOrder(suggestedOrder); doSuggestionTest(parameters, new OrderSingleSuggestion[] { expectedSuggestion }); // add symbol parameters.setProperty("symbol", "METC"); suggestedOrder.setInstrument(new Equity("METC")); expectedSuggestion.setOrder(suggestedOrder); doSuggestionTest(parameters, new OrderSingleSuggestion[] { expectedSuggestion }); } /** * Tests a strategy's ability to send <code>FIX</code> messages. * * @throws Exception if an error occurs */ @Test public void sendMessages() throws Exception { Properties parameters = new Properties(); Date messageDate = new Date(); parameters.setProperty("date", Long.toString(messageDate.getTime())); // null message parameters.setProperty("nullMessage", "true"); doMessageTest(parameters, new FIXOrder[0]); // null broker parameters.clear(); parameters.setProperty("date", Long.toString(messageDate.getTime())); parameters.setProperty("nullBroker", "true"); doMessageTest(parameters, new FIXOrder[0]); // send a valid message parameters.clear(); parameters.setProperty("date", Long.toString(messageDate.getTime())); Message msg = FIXVersion.FIX_SYSTEM.getMessageFactory().newBasicOrder(); msg.setField(new TransactTime(messageDate)); doMessageTest(parameters, new FIXOrder[] { Factory.getInstance().createOrder(msg, new BrokerID("some-broker")) } ); } /** * Takes a single strategy and starts and stops it many times. * * @throws Exception */ @PerformanceTest public void startStop() throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); ModuleURN strategyModule = moduleManager.createModule(StrategyModuleFactory.PROVIDER_URN, "MyStrategy", strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); int index = 0; while (index++ < 500) { startStrategy(strategyModule); stopStrategy(strategyModule); } } /** * Starts and stops many different strategies. * * @throws Exception */ @PerformanceTest public void manyStrategiesStartStop() throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); int index = 0; while (index++ < 500) { ModuleURN strategyModule = moduleManager.createModule(StrategyModuleFactory.PROVIDER_URN, "MyStrategy", strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); startStrategy(strategyModule); stopStrategy(strategyModule); moduleManager.deleteModule(strategyModule); } } /** * Starts and stops many different strategies. * * @throws Exception if an error occurs */ @PerformanceTest public void manyStrategiesStartWithoutStop() throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); int index = 0; while (index++ < 500) { ModuleURN strategyModule = moduleManager.createModule(StrategyModuleFactory.PROVIDER_URN, null, strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); moduleManager.start(strategyModule); } } /** * Tests the <code>MXBean</code> strategy interface. * * @throws Exception if an error occurs */ @Test public void mxBeanOperations() throws Exception { StrategyCoordinates strategy = getParameterStrategy(); // create a strategy with no parameters ModuleURN strategyURN = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // make sure the starting state is what we think it is verifyNullProperties(); final MockRecorderModule outputRecorder = MockRecorderModule.Factory.recorders.get(outputURN); assertNotNull("Must be able to find the recorder created", outputRecorder); assertTrue(outputRecorder.getDataReceived().isEmpty()); // fire events at the strategy doSuccessfulStartTestNoVerification(strategyURN); // nothing got through because the triggering parameters are not there verifyNullProperties(); assertTrue(outputRecorder.getDataReceived().isEmpty()); // set new parameters that will cause onAsk to be received StrategyMXBean strategyProxy = getMXProxy(strategyURN); strategyProxy.setParameters("onAsk=true:emitSuggestion=true:emitMessage=true"); doSuccessfulStartTestNoVerification(strategyURN); // nothing got through because the module was not restarted verifyNullProperties(); assertTrue(outputRecorder.getDataReceived().isEmpty()); // now cycle the strategy stopStrategy(strategyURN); startStrategy(strategyURN); doSuccessfulStartTestNoVerification(strategyURN); // onAsk got through, but there are still no destinations for the orders and suggestions verifyPropertyNonNull("onAsk"); assertTrue(outputRecorder.getDataReceived().isEmpty()); // reset setPropertiesToNull(); // now set the output destination strategyProxy.setOutputDestination(outputURN.getValue()); // fire the events doSuccessfulStartTestNoVerification(strategyURN); // onAsk still goes through, but the others won't until the strategy is cycled verifyPropertyNonNull("onAsk"); assertTrue(outputRecorder.getDataReceived().isEmpty()); // reset setPropertiesToNull(); // cycle the strategy again stopStrategy(strategyURN); startStrategy(strategyURN); // fire the events again doSuccessfulStartTestNoVerification(strategyURN); // onAsk set again verifyPropertyNonNull("onAsk"); // suggestion and order now gets through assertEquals(2, outputRecorder.getDataReceived().size()); // now make them all go away strategyProxy.setParameters(null); strategyProxy.setOutputDestination(null); // reset setPropertiesToNull(); outputRecorder.resetDataReceived(); // cycle stopStrategy(strategyURN); startStrategy(strategyURN); // fire doSuccessfulStartTestNoVerification(strategyURN); // verify verifyNullProperties(); assertTrue(outputRecorder.getDataReceived().isEmpty()); } /** * Makes sure that subscribers to output from one strategy are independent of subscribers to another strategy. * * @throws Exception if an error occurs */ @Test public void distinguishingSubscribers() throws Exception { ModuleURN alternateURN = createModule(MockRecorderModule.Factory.PROVIDER_URN); StrategyCoordinates strategy = getSuggestionStrategy(); Properties parameters = new Properties(); parameters.setProperty("score", "1"); parameters.setProperty("identifier", "some identifier"); // create two strategies that will emit a suggestion, but sign up a different receiver for each // strategy createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, outputURN); createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, alternateURN); // strategies have now emitted their suggestions, measure the results final MockRecorderModule strategy1Recorder = MockRecorderModule.Factory.recorders.get(outputURN); final MockRecorderModule strategy2Recorder = MockRecorderModule.Factory.recorders.get(alternateURN); // each strategy should have received one and only one suggestion assertEquals(1, strategy1Recorder.getDataReceived().size()); assertEquals(1, strategy2Recorder.getDataReceived().size()); } /** * Tests that a Ruby class may be dynamically redefined. * * @throws Exception if an error occurs */ @Test public void helperRedefinition() throws Exception { StrategyCoordinates strategy1 = getPart1Strategy(); doSuccessfulStartTestNoVerification(createStrategy(strategy1.getName(), getLanguage(), strategy1.getFile(), null, null, null)); StrategyCoordinates strategy2 = getPart2Strategy(); doSuccessfulStartTestNoVerification(createStrategy(strategy2.getName(), getLanguage(), strategy2.getFile(), null, null, null)); } /** * Tests a strategy's ability to emit notifications. * * @throws Exception if an error occurs */ @Test public void notifications() throws Exception { Level startingLevel = Logger.getLogger(Strategy.STRATEGY_MESSAGES).getLevel(); try { Logger.getLogger(Strategy.STRATEGY_MESSAGES).setLevel(Level.ALL); MockRecorderModule.shouldIgnoreLogMessages = false; // set up module to receive notifications final MockRecorderModule notificationSubscriber = MockRecorderModule.Factory.recorders.get(outputURN); assertTrue(notificationSubscriber.getDataReceived().isEmpty()); // create a strategy that can emit notifications StrategyCoordinates strategy = getStrategyCompiles(); Properties parameters = new Properties(); parameters.setProperty("shouldNotify", "true"); doSuccessfulStartTest(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, outputURN)); StrategyImpl runningStrategy = getRunningStrategy(theStrategy); MarketDataFeedTestBase.wait(new Callable<Boolean>() { @Override public Boolean call() throws Exception { return notificationSubscriber.getDataReceived().size() == 19; } }); assertEquals("low subject", ((Notification)(notificationSubscriber.getDataReceived().get(0).getData())).getSubject()); assertEquals("medium subject", ((Notification)(notificationSubscriber.getDataReceived().get(1).getData())).getSubject()); assertEquals("high subject", ((Notification)(notificationSubscriber.getDataReceived().get(2).getData())).getSubject()); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(3).getData(), WARN, null, INVALID_LOG, String.valueOf(runningStrategy)); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(4).getData(), DEBUG, null, MESSAGE_1P, ""); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(5).getData(), DEBUG, null, MESSAGE_1P, "Some statement"); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(7).getData(), WARN, null, INVALID_LOG, String.valueOf(runningStrategy)); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(8).getData(), INFO, null, MESSAGE_1P, ""); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(9).getData(), INFO, null, MESSAGE_1P, "Some statement"); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(11).getData(), WARN, null, INVALID_LOG, String.valueOf(runningStrategy)); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(12).getData(), WARN, null, MESSAGE_1P, ""); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(13).getData(), WARN, null, MESSAGE_1P, "Some statement"); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(15).getData(), WARN, null, INVALID_LOG, String.valueOf(runningStrategy)); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(16).getData(), ERROR, null, MESSAGE_1P, ""); verifyEvent((LogEvent)notificationSubscriber.getDataReceived().get(17).getData(), ERROR, null, MESSAGE_1P, "Some statement"); } finally { Logger.getLogger(Strategy.STRATEGY_MESSAGES).setLevel(startingLevel); MockRecorderModule.shouldIgnoreLogMessages = true; } } /** * Tests a strategy's ability to retrieve available brokers. * * @throws Exception if an error occurs */ @Test public void brokers() throws Exception { // call should fail MockClient.getBrokersFails = true; doBrokerTest(new BrokerStatus[0]); // succeeds and returns a non-empty list MockClient.getBrokersFails = false; doBrokerTest(brokers.getBrokers().toArray(new BrokerStatus[brokers.getBrokers().size()])); // succeeds and returns an empty list brokers=new BrokersStatus(new ArrayList<BrokerStatus>()); doBrokerTest(new BrokerStatus[0]); } /** * Test a strategy's ability to create and send orders. * * @throws Exception if an error occurs */ @Test public void orders() throws Exception { List<OrderSingle> cumulativeOrders = new ArrayList<OrderSingle>(); ModuleURN strategy = generateOrders(getOrdersStrategy(), outputURN); // null order AbstractRunningStrategy.setProperty("orderShouldBeNull", "true"); doOrderTest(strategy, new OrderSingle[0], cumulativeOrders); // reset the make-a-null-order flag AbstractRunningStrategy.getProperties().clear(); // create the expected order we'll use as a model for all the test OrderSingle expectedOrder = Factory.getInstance().createOrderSingle(); cumulativeOrders.add(expectedOrder); // add an account AbstractRunningStrategy.setProperty("account", "some account"); expectedOrder.setAccount("some account"); // add order type AbstractRunningStrategy.setProperty("orderType", OrderType.Market.name()); expectedOrder.setOrderType(OrderType.Market); // add price AbstractRunningStrategy.setProperty("price", "100.23"); expectedOrder.setPrice(new BigDecimal("100.23")); // add quantity AbstractRunningStrategy.setProperty("quantity", "10000"); expectedOrder.setQuantity(new BigDecimal("10000")); // add side AbstractRunningStrategy.setProperty("side", Side.Buy.name()); expectedOrder.setSide(Side.Buy); // add symbol AbstractRunningStrategy.setProperty("symbol", "METC"); expectedOrder.setInstrument(new Equity("METC")); doOrderTest(strategy, new OrderSingle[] { expectedOrder }, cumulativeOrders); // now do another couple of runs to test the order tracking feature OrderSingle expectedOrder2 = Factory.getInstance().createOrderSingle(); AbstractRunningStrategy.getProperties().clear(); AbstractRunningStrategy.setProperty("orderType", OrderType.Market.name()); AbstractRunningStrategy.setProperty("quantity", "10000"); AbstractRunningStrategy.setProperty("account", "some other account"); expectedOrder2.setAccount("some other account"); AbstractRunningStrategy.setProperty("price", "400.50"); expectedOrder2.setPrice(new BigDecimal("400.50")); AbstractRunningStrategy.setProperty("symbol", "GOOG"); expectedOrder2.setInstrument(new Equity("GOOG")); AbstractRunningStrategy.setProperty("side", Side.SellShort.name()); expectedOrder2.setSide(Side.SellShort); expectedOrder2.setOrderType(OrderType.Market); expectedOrder2.setQuantity(new BigDecimal("10000")); cumulativeOrders.add(expectedOrder2); doOrderTest(strategy, new OrderSingle[] { expectedOrder2 }, cumulativeOrders); // three time's a charm OrderSingle expectedOrder3 = Factory.getInstance().createOrderSingle(); AbstractRunningStrategy.getProperties().clear(); AbstractRunningStrategy.setProperty("orderType", OrderType.Market.name()); AbstractRunningStrategy.setProperty("quantity", "10000"); AbstractRunningStrategy.setProperty("account", "still another account"); expectedOrder3.setAccount("still another account"); AbstractRunningStrategy.setProperty("price", "10000.25"); expectedOrder3.setPrice(new BigDecimal("10000.25")); AbstractRunningStrategy.setProperty("symbol", "JAVA"); expectedOrder3.setInstrument(new Equity("JAVA")); AbstractRunningStrategy.setProperty("side", Side.Sell.name()); expectedOrder3.setSide(Side.Sell); expectedOrder3.setOrderType(OrderType.Market); expectedOrder3.setQuantity(new BigDecimal("10000")); cumulativeOrders.add(expectedOrder3); doOrderTest(strategy, new OrderSingle[] { expectedOrder3 }, cumulativeOrders); // cycle the strategy, proving that cumulative orders gets reset // this will prevent the strategy from sending an order when we next execute the test AbstractRunningStrategy.setProperty("orderShouldBeNull", "true"); // restart and make sure no orders are in this session stopStrategy(strategy); startStrategy(strategy); cumulativeOrders.clear(); doOrderTest(strategy, new OrderSingle[] { }, cumulativeOrders); // execute the test one more time making sure that orders can be sent while stopping AbstractRunningStrategy.setProperty("orderShouldBeNull", ""); AbstractRunningStrategy.setProperty("sendResult", ""); stopStrategy(strategy); assertEquals("true", AbstractRunningStrategy.getProperty("sendResult")); } /** * Tests a strategy's ability to send arbitrary objects. * * @throws Exception if an error occurs */ @Test public void other() throws Exception { theStrategy = createStrategy(getOtherStrategy().getName(), getLanguage(), getOtherStrategy().getFile(), null, null, outputURN); // run the strategy with nothing set setPropertiesToNull(); doOtherTest(theStrategy, new Object[0]); assertTrue("Expected properties to be empty, but was: " + AbstractRunningStrategy.getProperties().toString(), AbstractRunningStrategy.getProperties().isEmpty()); // have the strategy send null AbstractRunningStrategy.setProperty("sendNull", "true"); doOtherTest(theStrategy, new Object[0]); // make sure only the property we set above is set assertEquals(1, AbstractRunningStrategy.getProperties().size()); assertEquals(AbstractRunningStrategy.getProperty("sendNull"), "true"); // have the strategy send a string setPropertiesToNull(); AbstractRunningStrategy.setProperty("sendString", "true"); doOtherTest(theStrategy, new Object[] { "test string" }); assertEquals("Properties were " + AbstractRunningStrategy.getProperties(), 1, AbstractRunningStrategy.getProperties().size()); assertEquals(AbstractRunningStrategy.getProperty("sendString"), "true"); // have the strategy send two BigDecimals setPropertiesToNull(); AbstractRunningStrategy.setProperty("sendTwo", "true"); doOtherTest(theStrategy, new Object[] { BigDecimal.ONE, BigDecimal.TEN }); assertEquals("Properties was " + AbstractRunningStrategy.getProperties(), 1, AbstractRunningStrategy.getProperties().size()); assertEquals(AbstractRunningStrategy.getProperty("sendTwo"), "true"); // route orders to strategy and check output setPropertiesToNull(); theStrategy = createStrategy(getOtherStrategy().getName(), getLanguage(), getOtherStrategy().getFile(), null, true, outputURN); AbstractRunningStrategy.setProperty("sendTwo", "true"); doOtherTest(theStrategy, new Object[] { BigDecimal.ONE, BigDecimal.TEN }); assertEquals("Properties was " + AbstractRunningStrategy.getProperties(), 1, AbstractRunningStrategy.getProperties().size()); assertEquals(AbstractRunningStrategy.getProperty("sendTwo"), "true"); } /** * Tests a strategy's ability to retrieve <code>ExecutionReport</code> values related to its own orders. * * @throws Exception if an error occurs */ @Test public void executionReports() throws Exception { // create a strategy that sends its orders to a known module that can also emit execution reports generateOrders(getOrdersStrategy(), outputURN); doExecutionReportTest(0, false); // create an order and have the strategy submit it MockRecorderModule.shouldSendExecutionReports = false; doExecutionReportTest(0, true); MockRecorderModule.shouldSendExecutionReports = true; MockRecorderModule.shouldFullyFillOrders = false; doExecutionReportTest(1, true); // test an order that is split into several execution reports StrategyTestBase.executionReportMultiplicity = 4; doExecutionReportTest(4, true); } /** * Tests a strategy's ability to cancel all orders submitted. * * @throws Exception if an error occurs */ @Test public void cancelAllOrders() throws Exception { MockRecorderModule.shouldFullyFillOrders = false; // cancel 0 orders ModuleURN strategy = generateOrders(getOrdersStrategy(), outputURN); AbstractRunningStrategy runningStrategy = (AbstractRunningStrategy)getRunningStrategy(strategy).getRunningStrategy(); runningStrategy.initializeReportHistoryManager(); AbstractRunningStrategy.setProperty("cancelAll", "true"); // trigger cancel runningStrategy.onTrade(tradeEvent); assertEquals("0", AbstractRunningStrategy.getProperty("ordersCanceled")); AbstractRunningStrategy.setProperty("price", "1000"); AbstractRunningStrategy.setProperty("quantity", "500"); AbstractRunningStrategy.setProperty("side", Side.Sell.toString()); AbstractRunningStrategy.setProperty("symbol", "METC"); AbstractRunningStrategy.setProperty("orderType", OrderType.Market.name()); AbstractRunningStrategy.setProperty("quantity", "10000"); // create an order to cancel runningStrategy.onAsk(askEvent); // trigger cancel runningStrategy.onTrade(tradeEvent); // create two orders to cancel runningStrategy.onAsk(askEvent); runningStrategy.onAsk(askEvent); // trigger cancel runningStrategy.onTrade(tradeEvent); // without a functioning ER sender, the previous order will stay in the collection of orders to cancel // submit another order AbstractRunningStrategy.setProperty("ordersCanceled", "0"); runningStrategy.onAsk(askEvent); // make sure an order cancel all can be submitted during strategy stop AbstractRunningStrategy.setProperty("allOrdersCanceled", ""); stopStrategy(strategy); // payload of orders to stop includes the previous 3, the one sent via "onAsk" above, and one sent in "onStop" // cycle the module to get a fresh session startStrategy(strategy); // trigger a cancel (should trigger a cancel on all previous orders as the cycle won't affect the open orders) runningStrategy = (AbstractRunningStrategy)getRunningStrategy(strategy).getRunningStrategy(); runningStrategy.onTrade(tradeEvent); } /** * Provides a more in-depth test of strategy order cancel involving {@link ExecutionReport} objects. * * @throws Exception if an error occurs */ @Test public void cancelSingleOrder() throws Exception { MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(outputURN); assertNotNull("Must be able to find the recorder created", recorder); // set up data for the orders to be created // set price AbstractRunningStrategy.setProperty("price", "100.23"); // add quantity AbstractRunningStrategy.setProperty("quantity", "10000"); // add side AbstractRunningStrategy.setProperty("side", Side.Buy.name()); // add symbol AbstractRunningStrategy.setProperty("symbol", "METC"); // add type AbstractRunningStrategy.setProperty("orderType", OrderType.Market.name()); // add account AbstractRunningStrategy.setProperty("account", "account-" + System.nanoTime()); // try to cancel an order with a null orderID ModuleURN strategy = generateOrders(getOrdersStrategy(), outputURN); AbstractRunningStrategy runningStrategy = (AbstractRunningStrategy)getRunningStrategy(strategy).getRunningStrategy(); assertNull(AbstractRunningStrategy.getProperty("orderCanceled")); runningStrategy.onOther(this); assertEquals("false", AbstractRunningStrategy.getProperty("orderCanceled")); // now for an orderID that does not match a submitted order AbstractRunningStrategy.setProperty("orderCanceled", ""); runningStrategy.onOther(new OrderID("this-order-does-not-exist-" + System.nanoTime())); assertEquals("false", AbstractRunningStrategy.getProperty("orderCanceled")); // submit an order assertNull(AbstractRunningStrategy.getProperty("orderID")); runningStrategy.onAsk(askEvent); String orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); // start and stop the strategy stopStrategy(strategy); startStrategy(strategy); assertEquals(1, StrategyImpl.getRunningStrategies().size()); AbstractRunningStrategy.setProperty("orderCanceled", ""); runningStrategy = (AbstractRunningStrategy)getRunningStrategy(strategy).getRunningStrategy(); // make sure that order cannot be canceled now runningStrategy.onOther(new OrderID(orderIDString)); assertEquals("false", AbstractRunningStrategy.getProperty("orderCanceled")); // submit an order that will produce a single ER AbstractRunningStrategy.setProperty("executionReportsReceived", "0"); AbstractRunningStrategy.setProperty("orderCanceled", ""); MockRecorderModule.shouldSendExecutionReports = true; MockRecorderModule.shouldFullyFillOrders = false; StrategyTestBase.executionReportMultiplicity = 1; runningStrategy.onAsk(askEvent); assertEquals("1", AbstractRunningStrategy.getProperty("executionReportsReceived")); // cancel that order (using the received ER) orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); runningStrategy.onOther(new OrderID(orderIDString)); assertEquals("true", AbstractRunningStrategy.getProperty("orderCanceled")); // submit another order, create a cancel order, but don't submit it recorder.resetDataReceived(); AbstractRunningStrategy.setProperty("executionReportsReceived", "0"); AbstractRunningStrategy.setProperty("orderCanceled", null); runningStrategy.onAsk(askEvent); assertEquals("1", AbstractRunningStrategy.getProperty("executionReportsReceived")); assertEquals(recorder.getDataReceived().toString(), 1, recorder.getDataReceived().size()); assertTrue(recorder.getDataReceived().get(0).getData() instanceof OrderSingle); recorder.resetDataReceived(); // set up the strategy to not submit the cancel AbstractRunningStrategy.setProperty("skipSubmitOrders", "true"); // generate the cancel orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); runningStrategy.onOther(new OrderID(orderIDString)); // verify it was properly generated assertEquals("true", AbstractRunningStrategy.getProperty("orderCanceled")); // verify it was not submitted assertTrue(recorder.getDataReceived().isEmpty()); // submit, generate cancel, modify it, submit it after delay recorder.resetDataReceived(); AbstractRunningStrategy.setProperty("executionReportsReceived", "0"); AbstractRunningStrategy.setProperty("orderCanceled", null); runningStrategy.onAsk(askEvent); assertEquals("1", AbstractRunningStrategy.getProperty("executionReportsReceived")); assertEquals(recorder.getDataReceived().toString(), 1, recorder.getDataReceived().size()); assertTrue(recorder.getDataReceived().get(0).getData() instanceof OrderSingle); String modifiedAccountName = "modified account-" + System.nanoTime(); assertFalse(((OrderSingle)recorder.getDataReceived().get(0).getData()).getAccount().equals(modifiedAccountName)); recorder.resetDataReceived(); // set up the strategy to not submit the cancel AbstractRunningStrategy.setProperty("delaySubmitOrders", "true"); AbstractRunningStrategy.setProperty("newAccountName", modifiedAccountName); // generate the cancel orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); runningStrategy.onOther(new OrderID(orderIDString)); // verify it was properly generated assertEquals("true", AbstractRunningStrategy.getProperty("orderCanceled")); // verify it was submitted assertEquals(recorder.getDataReceived().toString(), 1, recorder.getDataReceived().size()); assertTrue(recorder.getDataReceived().get(0).getData() instanceof OrderCancel); OrderCancel orderCancel = (OrderCancel)recorder.getDataReceived().get(0).getData(); assertEquals(modifiedAccountName, orderCancel.getAccount()); assertNull(orderCancel.getBrokerOrderID()); // clean up before continuing AbstractRunningStrategy.setProperty("skipSubmitOrders", null); AbstractRunningStrategy.setProperty("delaySubmitOrders", null); // submit an order that will produce multiple ERs AbstractRunningStrategy.setProperty("executionReportsReceived", "0"); AbstractRunningStrategy.setProperty("orderCanceled", ""); StrategyTestBase.executionReportMultiplicity = 10; runningStrategy.onAsk(askEvent); assertEquals("10", AbstractRunningStrategy.getProperty("executionReportsReceived")); // cancel that order (using the received ER) orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); runningStrategy.onOther(new OrderID(orderIDString)); assertEquals("true", AbstractRunningStrategy.getProperty("orderCanceled")); // make sure an order cancel can be submitted during strategy stop AbstractRunningStrategy.setProperty("orderCancelNull", ""); stopStrategy(strategy); assertEquals("true", AbstractRunningStrategy.getProperty("orderCancelNull")); } /** * Tests a strategy's ability to cancel an existing order and replace it with a new one. * * @throws Exception if an error occurs */ @Test public void cancelReplace() throws Exception { MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(outputURN); assertNotNull("Must be able to find the recorder created", recorder); // for now, forbid the creation of execution reports MockRecorderModule.shouldSendExecutionReports = false; // set up data for the orders to be created // set price AbstractRunningStrategy.setProperty("price", "100.23"); // add quantity AbstractRunningStrategy.setProperty("quantity", "10000"); // add side AbstractRunningStrategy.setProperty("side", Side.Buy.name()); // add symbol AbstractRunningStrategy.setProperty("symbol", "METC"); // add time-in-force AbstractRunningStrategy.setProperty("timeInForce", TimeInForce.Day.toString()); // add type AbstractRunningStrategy.setProperty("orderType", OrderType.Market.name()); // create a strategy to use as our test vehicle ModuleURN strategy = generateOrders(getOrdersStrategy(), outputURN); AbstractRunningStrategy runningStrategy = (AbstractRunningStrategy)getRunningStrategy(strategy).getRunningStrategy(); // submit an order assertNull(AbstractRunningStrategy.getProperty("orderID")); runningStrategy.onAsk(askEvent); // save the orderID of the order we created, we'll need it later String orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertEquals(1, runningStrategy.getSubmittedOrders().size()); assertEquals(OrderType.Market, runningStrategy.getSubmittedOrders().iterator().next().getOrderType()); assertNotNull(orderIDString); // try to cancel/replace with a null OrderID AbstractRunningStrategy.setProperty("orderID", null); AbstractRunningStrategy.setProperty("newOrderID", ""); OrderSingle newOrder = Factory.getInstance().createOrderSingle(); assertNotNull(AbstractRunningStrategy.getProperty("newOrderID")); BigDecimal quantity = new BigDecimal("1000.50"); newOrder.setQuantity(quantity); newOrder.setPrice(new BigDecimal("1")); newOrder.setTimeInForce(TimeInForce.GoodTillCancel); newOrder.setInstrument(new Equity("METC")); // try to cancel/replace with a null OrderID runningStrategy.onOther(newOrder); assertNull(AbstractRunningStrategy.getProperty("newOrderID")); // try to cancel/replace with an unsubmitted OrderID OrderID unsubmittedOrderID = new OrderID("this-order-id-does-not-exist-" + System.nanoTime()); AbstractRunningStrategy.setProperty("orderID", unsubmittedOrderID.toString()); AbstractRunningStrategy.setProperty("newOrderID", ""); assertNotNull(AbstractRunningStrategy.getProperty("newOrderID")); runningStrategy.onOther(newOrder); assertNull(AbstractRunningStrategy.getProperty("newOrderID")); // try with a null replacement order // put back the orderID of the order to replace AbstractRunningStrategy.setProperty("orderID", orderIDString); AbstractRunningStrategy.setProperty("newOrderID", ""); runningStrategy.onOther(""); assertNull(StringUtils.trimToNull(AbstractRunningStrategy.getProperty("newOrderID"))); // now allow the cancel/replace to succeed // make sure the order is open before we begin MockRecorderModule.shouldSendExecutionReports = true; MockRecorderModule.shouldFullyFillOrders = false; StrategyTestBase.executionReportMultiplicity = 1; newOrder.setOrderID(new OrderID(orderIDString)); List<ExecutionReport> reports = generateExecutionReports(newOrder); for(ExecutionReport report : reports) { runningStrategy.onExecutionReportRedirected(report); } runningStrategy.onOther(newOrder); String replaceIDString = AbstractRunningStrategy.getProperty("newOrderID"); assertNotNull(replaceIDString); assertFalse(replaceIDString.equals(newOrder.getOrderID().toString())); // hooray, it worked // send a new order runningStrategy.onAsk(askEvent); orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); AbstractRunningStrategy.setProperty("orderID", orderIDString); // cause a cancel/replace again, but this time don't allow the cancel/replace to be submitted recorder.resetDataReceived(); AbstractRunningStrategy.setProperty("skipSubmitOrders", "true"); runningStrategy.onOther(newOrder); assertNotNull(replaceIDString); assertTrue(recorder.getDataReceived().isEmpty()); // can't cancel/replace this order any more, so create a new one runningStrategy.onAsk(askEvent); recorder.resetDataReceived(); orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); AbstractRunningStrategy.setProperty("orderID", orderIDString); // cancel/replace this order, don't automatically submit it, then modify it and submit it manually AbstractRunningStrategy.setProperty("delaySubmitOrders", "true"); newOrder.setOrderType(OrderType.Market); runningStrategy.onOther(newOrder); assertNotNull(replaceIDString); assertEquals(recorder.getDataReceived().toString(), 1, recorder.getDataReceived().size()); Object receivedData = recorder.getDataReceived().get(0).getData(); assertTrue("Object is " + receivedData, receivedData instanceof OrderReplace); OrderReplace receivedOrder = (OrderReplace)receivedData; assertNull(receivedOrder.getBrokerOrderID()); assertEquals(quantity.add(BigDecimal.ONE), receivedOrder.getQuantity()); AbstractRunningStrategy.setProperty("delaySubmitOrders", null); AbstractRunningStrategy.setProperty("skipSubmitOrders", null); // turn on execution reports MockRecorderModule.shouldSendExecutionReports = true; MockRecorderModule.shouldFullyFillOrders = false; StrategyTestBase.executionReportMultiplicity = 20; // re-submit the order runningStrategy.onAsk(askEvent); assertNotNull(AbstractRunningStrategy.getProperty("orderID")); assertFalse(orderIDString.equals(AbstractRunningStrategy.getProperty("orderID"))); AbstractRunningStrategy.setProperty("newOrderID", null); // cancel/replace again (this time using execution reports) runningStrategy.onOther(newOrder); assertNotNull(AbstractRunningStrategy.getProperty("newOrderID")); // submit an order again AbstractRunningStrategy.setProperty("orderID", null); runningStrategy.onAsk(askEvent); orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); // cycle the strategy stopStrategy(strategy); startStrategy(strategy); runningStrategy = (AbstractRunningStrategy)getRunningStrategy(strategy).getRunningStrategy(); AbstractRunningStrategy.setProperty("newOrderID", null); // try to cancel/replace again, won't work because the order to be replaced was in the last strategy session (before the stop) runningStrategy.onOther(newOrder); assertNull(AbstractRunningStrategy.getProperty("newOrderID")); // make sure an order replace can be submitted during strategy stop AbstractRunningStrategy.setProperty("orderReplaceNull", ""); AbstractRunningStrategy.setProperty("shouldReplace", "true"); stopStrategy(strategy); assertEquals("true", AbstractRunningStrategy.getProperty("orderReplaceNull")); // do a final test making sure that a price *is* specified for a non-market replace AbstractRunningStrategy.setProperty("orderType", OrderType.Limit.name()); recorder.resetDataReceived(); startStrategy(strategy); runningStrategy = (AbstractRunningStrategy)getRunningStrategy(strategy).getRunningStrategy(); AbstractRunningStrategy.setProperty("newOrderID", null); runningStrategy.onAsk(askEvent); orderIDString = AbstractRunningStrategy.getProperty("orderID"); assertNotNull(orderIDString); assertEquals(1, runningStrategy.getSubmittedOrders().size()); assertEquals(OrderType.Limit, runningStrategy.getSubmittedOrders().iterator().next().getOrderType()); recorder.resetDataReceived(); AbstractRunningStrategy.setProperty("orderID", orderIDString); AbstractRunningStrategy.setProperty("newOrderID", ""); newOrder.setPrice(new BigDecimal("12345")); runningStrategy.onOther(newOrder); receivedData = recorder.getDataReceived().get(0).getData(); assertTrue("Object is " + receivedData, receivedData instanceof OrderReplace); receivedOrder = (OrderReplace)receivedData; assertEquals(new BigDecimal("12345"), receivedOrder.getPrice()); } /** * Tests {@link AbstractRunningStrategy#getPositionAsOf(Date, String)}. * * @throws Exception if an unexpected error occurs */ @Test public void positionAsOf() throws Exception { Instrument validEquity = null; for(Instrument instrument : positions.keySet()) { if(instrument instanceof Equity) { validEquity = instrument; break; } } assertNotNull(validEquity); Position position = positions.get(validEquity); assertNotNull(position); String invalidSymbol = "there-is-no-position-for-this-symbol-" + System.nanoTime(); assertFalse(positions.containsKey(new Equity(invalidSymbol))); // null symbol doPositionAsOfTest(null, new Date(), null); // invalid symbol doPositionAsOfTest(invalidSymbol, new Date(), null); // null date doPositionAsOfTest(validEquity.getSymbol(), null, null); // call fails MockClient.getPositionFails = true; doPositionAsOfTest(validEquity.getSymbol(), new Date(), null); MockClient.getPositionFails = false; getClientFails = true; doPositionAsOfTest(validEquity.getSymbol(), new Date(), null); getClientFails = false; // date in the past (before position begins) Interval<BigDecimal> openingBalance = position.getPositionView().get(0); doPositionAsOfTest(validEquity.getSymbol(), new Date(openingBalance.getDate().getTime() - 1000), // 1s before the open of the position BigDecimal.ZERO); // date in the past (after position begins) List<Interval<BigDecimal>> view = position.getPositionView(); int median = view.size() / 2; assertTrue("Position " + position + " contains no data!", median > 0); Interval<BigDecimal> dataPoint = position.getPositionView().get(median); Date date = dataPoint.getDate(); BigDecimal expectedValue = position.getPositionAt(date); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); assertTrue(date.getTime() < System.currentTimeMillis()); // found a date somewhere in the middle of the position and earlier than today doPositionAsOfTest(validEquity.getSymbol(), date, expectedValue); // date exactly now date = new Date(); expectedValue = position.getPositionAt(date); dataPoint = view.get(view.size() - 1); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); doPositionAsOfTest(validEquity.getSymbol(), date, expectedValue); // pick a data point two weeks into the future date = new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 14)); expectedValue = position.getPositionAt(date); dataPoint = view.get(view.size() - 1); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); doPositionAsOfTest(validEquity.getSymbol(), date, expectedValue); } /** * Tests {@link AbstractRunningStrategy#getCurrencyPositionAsOf(Date, String)}. * * @throws Exception if an unexpected error occurs */ @Test public void currencyPositionAsOf() throws Exception { Instrument validCurrency = null; for(Instrument instrument : positions.keySet()) { if(instrument instanceof Currency) { validCurrency = instrument; break; } } assertNotNull(validCurrency); Position position = positions.get(validCurrency); assertNotNull(position); String invalidSymbol = "there-is-no-position-for-this-symbol-" + System.nanoTime(); assertFalse(positions.containsKey(new Currency(invalidSymbol))); // null symbol doCurrencyPositionAsOfTest(null, new Date(), null); // invalid symbol doCurrencyPositionAsOfTest(invalidSymbol, new Date(), null); // null date doCurrencyPositionAsOfTest(validCurrency.getSymbol(), null, null); // call fails MockClient.getPositionFails = true; doCurrencyPositionAsOfTest(validCurrency.getSymbol(), new Date(), null); MockClient.getPositionFails = false; getClientFails = true; doCurrencyPositionAsOfTest(validCurrency.getSymbol(), new Date(), null); getClientFails = false; // date in the past (before position begins) Interval<BigDecimal> openingBalance = position.getPositionView().get(0); doCurrencyPositionAsOfTest(validCurrency.getSymbol(), new Date(openingBalance.getDate().getTime() - 1000), // 1s before the open of the position BigDecimal.ZERO); // date in the past (after position begins) List<Interval<BigDecimal>> view = position.getPositionView(); int median = view.size() / 2; assertTrue("Position " + position + " contains no data!", median > 0); Interval<BigDecimal> dataPoint = position.getPositionView().get(median); Date date = dataPoint.getDate(); BigDecimal expectedValue = position.getPositionAt(date); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); assertTrue(date.getTime() < System.currentTimeMillis()); // found a date somewhere in the middle of the position and earlier than today doCurrencyPositionAsOfTest(validCurrency.getSymbol(), date, expectedValue); // date exactly now date = new Date(); expectedValue = position.getPositionAt(date); dataPoint = view.get(view.size() - 1); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); doCurrencyPositionAsOfTest(validCurrency.getSymbol(), date, expectedValue); // pick a data point two weeks into the future date = new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 14)); expectedValue = position.getPositionAt(date); dataPoint = view.get(view.size() - 1); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); doCurrencyPositionAsOfTest(validCurrency.getSymbol(), date, expectedValue); } /** * Tests {@link AbstractRunningStrategy#getAllPositionsAsOf(Date)}. * * @throws Exception if an unexpected error occurs */ @Test public void allPositionsAsOf() throws Exception { // null date doAllPositionsAsOfTest(null, null); // call fails MockClient.getPositionFails = true; doAllPositionsAsOfTest(new Date(), null); MockClient.getPositionFails = false; // the date of the earliest position of all instruments Date date = new Date(); for(Position position : positions.values()) { // examine only equities to make sure that the position we find is for an equity if(position.getInstrument() instanceof Equity) { date = new Date(Math.min(date.getTime(), position.getPositionView().get(0).getDate().getTime())); } } MockClient client = new MockClient(); date = new Date(date.getTime() - 1000); doAllPositionsAsOfTest(date, // 1s before the open of the position client.getAllEquityPositionsAsOf(date)); // date in the past (after position begins) date = new Date(date.getTime() + 2000); // 1s after the open of the position assertTrue(date.getTime() < System.currentTimeMillis()); // found a date somewhere in the middle of the position and earlier than today doAllPositionsAsOfTest(date, client.getAllEquityPositionsAsOf(date)); // date exactly now date = new Date(); doAllPositionsAsOfTest(date, client.getAllEquityPositionsAsOf(date)); // pick a data point two weeks into the future date = new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 14)); doAllPositionsAsOfTest(date, client.getAllEquityPositionsAsOf(date)); } /** * Tests {@link AbstractRunningStrategy#getAllCurrencyPositionsAsOf(Date)}. * * @throws Exception if an unexpected error occurs */ @Test public void allCurrencyPositionsAsOf() throws Exception { // null date doAllCurrencyPositionsAsOfTest(null, null); // call fails MockClient.getPositionFails = true; doAllCurrencyPositionsAsOfTest(new Date(), null); MockClient.getPositionFails = false; // the date of the earliest position of all instruments Date date = new Date(); for(Position position : positions.values()) { // examine only Currencies to make sure that the position we find is for an Currency if(position.getInstrument() instanceof Currency) { date = new Date(Math.min(date.getTime(), position.getPositionView().get(0).getDate().getTime())); } } MockClient client = new MockClient(); date = new Date(date.getTime() - 1000); doAllCurrencyPositionsAsOfTest(date, // 1s before the open of the position client.getAllCurrencyPositionsAsOf(date)); // date in the past (after position begins) date = new Date(date.getTime() + 2000); // 1s after the open of the position assertTrue(date.getTime() < System.currentTimeMillis()); // found a date somewhere in the middle of the position and earlier than today doAllCurrencyPositionsAsOfTest(date, client.getAllCurrencyPositionsAsOf(date)); // date exactly now date = new Date(); doAllCurrencyPositionsAsOfTest(date, client.getAllCurrencyPositionsAsOf(date)); // pick a data point two weeks into the future date = new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 14)); doAllCurrencyPositionsAsOfTest(date, client.getAllCurrencyPositionsAsOf(date)); } /** * Tests {@link AbstractRunningStrategy#getOptionPositionAsOf(Date, String, String, BigDecimal, OptionType)}. * * @throws Exception if an unexpected error occurs */ @Test public void optionPositionAsOf() throws Exception { Option validOption = null; for(Instrument instrument : positions.keySet()) { if(instrument instanceof Option) { validOption = (Option)instrument; break; } } assertNotNull(validOption); Position position = positions.get(validOption); assertNotNull(position); String invalidSymbol = "there-is-no-position-for-this-symbol-" + System.nanoTime(); Option invalidOption = new Option(invalidSymbol, DateUtils.dateToString(new Date(), DateUtils.DAYS), EventTestBase.generateDecimalValue(), OptionType.Call); assertFalse(positions.containsKey(invalidOption)); // null option root doOptionPositionAsOfTest(null, validOption.getExpiry(), validOption.getStrikePrice(), validOption.getType(), new Date(), null); // null expiry doOptionPositionAsOfTest(validOption.getSymbol(), null, validOption.getStrikePrice(), validOption.getType(), new Date(), null); // null strike price doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), null, validOption.getType(), new Date(), null); // null option type doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), validOption.getStrikePrice(), null, new Date(), null); // null date doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), validOption.getStrikePrice(), validOption.getType(), null, null); // option doesn't exist doOptionPositionAsOfTest(invalidOption.getSymbol(), invalidOption.getExpiry(), invalidOption.getStrikePrice(), invalidOption.getType(), new Date(), null); // call fails MockClient.getPositionFails = true; doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), validOption.getStrikePrice(), validOption.getType(), new Date(), null); MockClient.getPositionFails = false; // date in the past (before position begins) Interval<BigDecimal> openingBalance = position.getPositionView().get(0); doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), validOption.getStrikePrice(), validOption.getType(), new Date(openingBalance.getDate().getTime() - 1000), // 1s before the open of the position BigDecimal.ZERO); // date in the past (after position begins) List<Interval<BigDecimal>> view = position.getPositionView(); int median = view.size() / 2; assertTrue("Position " + position + " contains no data!", median > 0); Interval<BigDecimal> dataPoint = position.getPositionView().get(median); Date date = dataPoint.getDate(); BigDecimal expectedValue = position.getPositionAt(date); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); assertTrue(date.getTime() < System.currentTimeMillis()); // found a date somewhere in the middle of the position and earlier than today doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), validOption.getStrikePrice(), validOption.getType(), date, expectedValue); // date exactly now date = new Date(); expectedValue = position.getPositionAt(date); dataPoint = view.get(view.size() - 1); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), validOption.getStrikePrice(), validOption.getType(), date, expectedValue); // pick a data point two weeks into the future date = new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 14)); expectedValue = position.getPositionAt(date); dataPoint = view.get(view.size() - 1); assertEquals("value at " + date + ": " + position, dataPoint.getValue(), expectedValue); doOptionPositionAsOfTest(validOption.getSymbol(), validOption.getExpiry(), validOption.getStrikePrice(), validOption.getType(), date, expectedValue); } /** * Tests {@link AbstractRunningStrategy#getAllOptionPositionsAsOf(Date)}. * * @throws Exception if an unexpected error occurs */ @Test public void allOptionPositionsAsOf() throws Exception { // null date doAllOptionPositionsAsOfTest(null, null); // call fails MockClient.getPositionFails = true; doAllOptionPositionsAsOfTest(new Date(), null); MockClient.getPositionFails = false; // the date of the earliest position of all instruments Date date = new Date(); for(Position position : positions.values()) { if(position.getInstrument() instanceof Option) { date = new Date(Math.min(date.getTime(), position.getPositionView().get(0).getDate().getTime())); } } MockClient client = new MockClient(); date = new Date(date.getTime() - 1000); doAllOptionPositionsAsOfTest(date, // 1s before the open of the position client.getAllOptionPositionsAsOf(date)); // date in the past (after position begins) date = new Date(date.getTime() + 2000); // 1s after the open of the position assertTrue(date.getTime() < System.currentTimeMillis()); // found a date somewhere in the middle of the position and earlier than today doAllOptionPositionsAsOfTest(date, client.getAllOptionPositionsAsOf(date)); // date exactly now date = new Date(); doAllOptionPositionsAsOfTest(date, client.getAllOptionPositionsAsOf(date)); // pick a data point two weeks into the future date = new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 14)); doAllOptionPositionsAsOfTest(date, client.getAllOptionPositionsAsOf(date)); } /** * Tests {@link AbstractRunningStrategy#getOptionPositionsAsOf(Date, String...)}. * * @throws Exception if an unexpected error occurs */ @Test public void optionPositionsAsOf() throws Exception { MockClient client = new MockClient(); Option validOption1 = null; Option validOption2 = null; for(Instrument instrument : positions.keySet()) { if(instrument instanceof Option && validOption1 == null) { validOption1 = (Option)instrument; } else { if(instrument instanceof Option && validOption2 == null) { validOption2 = (Option)instrument; } } } assertNotNull(validOption1); assertNotNull(validOption2); Position position1 = positions.get(validOption1); Position position2 = positions.get(validOption2); assertNotNull(position1); assertNotNull(position2); String invalidSymbol = "there-is-no-position-for-this-symbol-" + System.nanoTime(); Option invalidOption = new Option(invalidSymbol, DateUtils.dateToString(new Date(), DateUtils.DAYS), EventTestBase.generateDecimalValue(), OptionType.Call); assertFalse(positions.containsKey(invalidOption)); // null option roots doOptionPositionsAsOfTest(null, new Date(), null, null); // empty option roots doOptionPositionsAsOfTest(new String[0], new Date(), null, null); String[] optionRoots = new String[] { validOption1.getSymbol(), invalidOption.getSymbol(), null }; Date date = new Date(); // a mix of valid and invalid doOptionPositionsAsOfTest(optionRoots, date, null, client.getOptionPositionsAsOf(date, optionRoots)); // null date doOptionPositionsAsOfTest(new String[] { validOption1.getSymbol() }, null, null, null); optionRoots = new String[] { invalidOption.getSymbol() }; date = new Date(); // option doesn't exist doOptionPositionsAsOfTest(optionRoots, date, null, client.getOptionPositionsAsOf(date, optionRoots)); // call fails MockClient.getPositionFails = true; doOptionPositionsAsOfTest(new String[] { validOption1.getSymbol() }, new Date(), null, null); MockClient.getPositionFails = false; // date in the past (before position begins) optionRoots = new String[] { validOption1.getSymbol(), validOption2.getSymbol() }; Interval<BigDecimal> openingBalance1 = position1.getPositionView().get(0); Interval<BigDecimal> openingBalance2 = position2.getPositionView().get(0); date = new Date(Math.min(openingBalance1.getDate().getTime(), openingBalance2.getDate().getTime()) - 1000); // 1s before the open of the position doOptionPositionsAsOfTest(optionRoots, date, null, client.getOptionPositionsAsOf(date, optionRoots)); // date in the past (after position begins) List<Interval<BigDecimal>> view = position1.getPositionView(); int median = view.size() / 2; assertTrue("Position " + position1 + " contains no data!", median > 0); Interval<BigDecimal> dataPoint = position1.getPositionView().get(median); date = dataPoint.getDate(); assertTrue(date.getTime() < System.currentTimeMillis()); // found a date somewhere in the middle of the position and earlier than today doOptionPositionsAsOfTest(optionRoots, date, null, client.getOptionPositionsAsOf(date, optionRoots)); // date exactly now date = new Date(); doOptionPositionsAsOfTest(optionRoots, date, null, client.getOptionPositionsAsOf(date, optionRoots)); // pick a data point two weeks into the future date = new Date(System.currentTimeMillis() + (1000 * 60 * 60 * 24 * 14)); doOptionPositionsAsOfTest(optionRoots, date, null, client.getOptionPositionsAsOf(date, optionRoots)); // do a pair of special tests that need special handling Properties parameters = new Properties(); parameters.setProperty("nullOptionRoot", "true"); doOptionPositionsAsOfTest(new String[] { validOption1.getSymbol() }, date, parameters, null); parameters.clear(); parameters.setProperty("emptyOptionRoot", "true"); doOptionPositionsAsOfTest(new String[] { validOption1.getSymbol() }, date, parameters, null); } /** * Tests {@link AbstractRunningStrategy#getUnderlying(String)}. * * @throws Exception if an unexpected error occurs */ @Test public void underlying() throws Exception { MockClient client = new MockClient(); Option validOption = null; for(Instrument instrument : positions.keySet()) { if(instrument instanceof Option) { validOption = (Option)instrument; break; } } assertNotNull(validOption); assertTrue(underlyings.containsKey(validOption.getSymbol())); String invalidSymbol = "there-is-no-underlying-for-this-symbol-" + System.nanoTime(); assertFalse(underlyings.containsKey(invalidSymbol)); // null option root doUnderlyingTest(null, null); // empty option root doUnderlyingTest("", null); // invalid option root doUnderlyingTest(invalidSymbol, null); // call fails MockClient.getPositionFails = true; doUnderlyingTest(validOption.getSymbol(), null); MockClient.getPositionFails = false; // valid option root doUnderlyingTest(validOption.getSymbol(), client.getUnderlying(validOption.getSymbol())); } /** * Tests {@link AbstractRunningStrategy#getOptionRoots(String)}. * * @throws Exception if an unexpected error occurs */ @Test public void optionRoots() throws Exception { MockClient client = new MockClient(); String underlyingSymbol = roots.keySet().iterator().next(); assertNotNull(underlyingSymbol); String invalidUnderlyingSymbol = "not-an-underlying-symbol"; assertFalse(roots.keySet().contains(invalidUnderlyingSymbol)); // null underlying symbol doOptionRootsTest(null, null); // empty underlying symbol doOptionRootsTest("", null); // invalid underlying symbol doOptionRootsTest(invalidUnderlyingSymbol, client.getOptionRoots(invalidUnderlyingSymbol)); // call fails MockClient.getPositionFails = true; doOptionRootsTest(underlyingSymbol, null); MockClient.getPositionFails = false; // valid underlying symbol doOptionRootsTest(underlyingSymbol, client.getOptionRoots(underlyingSymbol)); } /** * Tests that two strategies with the same class name can co-exist. * * @throws Exception */ @Test public void strategiesOfSameClass() throws Exception { StrategyCoordinates strategy1 = getPart1Strategy(); ModuleURN strategy1URN = createStrategy(strategy1.getName(), getLanguage(), strategy1.getFile(), null, null, null); ModuleURN strategy2URN = createStrategy(strategy1.getName(), getLanguage(), strategy1.getFile(), null, null, null); doSuccessfulStartTestNoVerification(strategy1URN); doSuccessfulStartTestNoVerification(strategy2URN); Set<StrategyImpl> runningStrategies = StrategyImpl.getRunningStrategies(); // should be two running strategies assertEquals(2, runningStrategies.size()); // execute the onCallback method in each running strategy for(StrategyImpl runningStrategy : runningStrategies) { runningStrategy.getRunningStrategy().onCallback(null); } // both strategies get their own onCallback called assertEquals("2", AbstractRunningStrategy.getProperty("onCallback")); // there should be two callbacks registered String strategyName1 = AbstractRunningStrategy.getProperty("callback1"); String strategyName2 = AbstractRunningStrategy.getProperty("callback2"); assertFalse(strategyName1.equals(strategyName2)); } /** * Verifies that a Strategy may be dynamically redefined. * * @throws Exception if an error occurs */ @Test public void redefinedStrategy() throws Exception { StrategyCoordinates strategy1 = getPart1Strategy(); StrategyCoordinates strategy2 = getPart1RedefinedStrategy(); ModuleURN strategy1URN = createStrategy(strategy1.getName(), getLanguage(), strategy1.getFile(), null, null, null); ModuleURN strategy2URN = createStrategy(strategy2.getName(), getLanguage(), strategy2.getFile(), null, null, null); doSuccessfulStartTestNoVerification(strategy1URN); doSuccessfulStartTestNoVerification(strategy2URN); setPropertiesToNull(); // strategies have started and are working Set<StrategyImpl> runningStrategies = StrategyImpl.getRunningStrategies(); // should be two running strategies assertEquals(2, runningStrategies.size()); // execute the onAsk method in each running strategy for(StrategyImpl runningStrategy : runningStrategies) { runningStrategy.getRunningStrategy().onAsk(askEvent); } // both strategies should get their onAsk called, but the definition should be the second one Properties properties = AbstractRunningStrategy.getProperties(); int askCounter = 0; for(Object key : properties.keySet()) { String keyString = (String)key; if(keyString.startsWith("ask")) { askCounter += 1; assertTrue(properties.getProperty(keyString).startsWith("part1")); } } assertEquals(2, askCounter); } /** * Tests the stategy's ability to execute CEP queries. * * @throws Exception if an error occurs */ @Test public void cep() throws Exception { String validEsperStatement1 = "select * from trade where instrumentAsString='METC'"; String validEsperStatement2 = "select * from ask where instrumentAsString='ORCL'"; String validSystemStatement1 = "select * from trade"; String validSystemStatement2 = "select * from ask"; String invalidStatement = "this statement is not syntactically valid"; Event[] events = new Event[] { EventTestBase.generateEquityTradeEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("1"), new BigDecimal("100")), EventTestBase.generateEquityTradeEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("2"), new BigDecimal("200")), EventTestBase.generateEquityAskEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("3"), new BigDecimal("300")), EventTestBase.generateEquityAskEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("4"), new BigDecimal("400")), EventTestBase.generateEquityBidEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("5"), new BigDecimal("500")), EventTestBase.generateEquityBidEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("6"), new BigDecimal("600")) }; String[] sources = new String[] { null, "esper", "system" }; String[][] statements = new String[][] { { null }, { }, { invalidStatement }, { validSystemStatement1, validSystemStatement2 }, { validSystemStatement1 }, { validEsperStatement1 }, { validEsperStatement1, validEsperStatement2 } }; for(int sourceCounter=0;sourceCounter<sources.length;sourceCounter++) { for(int statementCounter=0;statementCounter<statements.length;statementCounter++) { SLF4JLoggerProxy.debug(LanguageTestBase.class, "{}:{}", sourceCounter, statementCounter); List<OrderSingleSuggestion> suggestions = doCEPTest(sources[sourceCounter], statements[statementCounter], events, true); // verify results switch(sourceCounter) { case 0 : assertTrue(suggestions.isEmpty()); continue; case 1 : // esper conditions switch(statementCounter) { case 0 : // null statements assertTrue(suggestions.isEmpty()); continue; case 1 : // empty statements assertTrue(suggestions.isEmpty()); continue; case 2 : // invalid statements assertTrue(suggestions.isEmpty()); continue; case 3 : // 2 valid system statements (also valid esper statements) // note that the last statement is the only one that will return data assertEquals(2, suggestions.size()); verifyCEPSuggestion("METC", new BigDecimal("3"), new BigDecimal("300"), suggestions.get(0)); verifyCEPSuggestion("ORCL", new BigDecimal("4"), new BigDecimal("400"), suggestions.get(1)); continue; case 4 : // 1 valid system statement (also valid esper statement) assertEquals(2, suggestions.size()); verifyCEPSuggestion("METC", new BigDecimal("1"), new BigDecimal("100"), suggestions.get(0)); verifyCEPSuggestion("ORCL", new BigDecimal("2"), new BigDecimal("200"), suggestions.get(1)); continue; case 5 : // 1 valid esper statement assertEquals(1, suggestions.size()); verifyCEPSuggestion("METC", new BigDecimal("1"), new BigDecimal("100"), suggestions.get(0)); continue; case 6 : // 2 valid esper statements assertEquals(1, suggestions.size()); verifyCEPSuggestion("ORCL", new BigDecimal("4"), new BigDecimal("400"), suggestions.get(0)); continue; default : fail("Unexpected statement"); } continue; case 2 : // system conditions switch(statementCounter) { case 0 : // null statements assertTrue(suggestions.isEmpty()); continue; case 1 : // empty statements assertTrue(suggestions.isEmpty()); continue; case 2 : // invalid statements assertTrue(suggestions.isEmpty()); continue; case 3 : // 2 valid system statements // note that the first statement is the only one that will return data assertEquals(2, suggestions.size()); verifyCEPSuggestion("METC", new BigDecimal("1"), new BigDecimal("100"), suggestions.get(0)); verifyCEPSuggestion("ORCL", new BigDecimal("2"), new BigDecimal("200"), suggestions.get(1)); continue; case 4 : // 1 valid system statement assertEquals(2, suggestions.size()); verifyCEPSuggestion("METC", new BigDecimal("1"), new BigDecimal("100"), suggestions.get(0)); verifyCEPSuggestion("ORCL", new BigDecimal("2"), new BigDecimal("200"), suggestions.get(1)); continue; case 5 : // 1 valid esper statement (not valid for system) assertTrue(suggestions.isEmpty()); continue; case 6 : // 2 valid esper statements (not valid for system) assertTrue(suggestions.isEmpty()); continue; default : fail("Unexpected statement"); } default : fail("Unexpected source"); } } } } /** * Tests the ability to cancel a single CEP request. * * @throws Exception if an error occurs */ @Test public void cancelSingleCep() throws Exception { Event[] events = new Event[] { EventTestBase.generateEquityTradeEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("1"), new BigDecimal("100")), EventTestBase.generateEquityTradeEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("2"), new BigDecimal("200")), EventTestBase.generateEquityAskEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("3"), new BigDecimal("300")), EventTestBase.generateEquityAskEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("4"), new BigDecimal("400")), EventTestBase.generateEquityBidEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("5"), new BigDecimal("500")), EventTestBase.generateEquityBidEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("6"), new BigDecimal("600")) }; assertNull(AbstractRunningStrategy.getProperty("requestID")); // create a strategy that creates some suggestions List<OrderSingleSuggestion> suggestions = doCEPTest("esper", new String[] { "select * from trade" }, events, false); assertEquals(2, suggestions.size()); String requestIDString = AbstractRunningStrategy.getProperty("requestID"); assertNotNull(requestIDString); // issue a cancel request for a non-existent id int badID = 10500; assertFalse(Integer.parseInt(requestIDString) == badID); AbstractRunningStrategy.setProperty("shouldCancelCEPData", "true"); AbstractRunningStrategy.setProperty("requestID", Integer.toString(badID)); // the strategy is still running and it has an active CEP query // if we send an "onOther" to the strategy, it will trigger a cancel request StrategyImpl strategy = getRunningStrategy(theStrategy); strategy.getRunningStrategy().onOther(this); ModuleURN cepModuleURN = new ModuleURN("metc:cep:esper:" + strategy.getDefaultNamespace()); // verify that the cancel did not affect the existing query by triggering another set of suggestions via the CEP query assertEquals(0, getReceivedSuggestions(outputURN).size()); feedEventsToCEP(events, cepModuleURN); assertEquals(2, getReceivedSuggestions(outputURN).size()); // cancel the actual query and verify no events are received from CEP AbstractRunningStrategy.setProperty("requestID", requestIDString); assertEquals(0, getReceivedSuggestions(outputURN).size()); // triggers the cancel strategy.getRunningStrategy().onOther(this); // triggers the events to CEP feedEventsToCEP(events, cepModuleURN); // measure the result assertEquals(0, getReceivedSuggestions(outputURN).size()); } /** * Cancels all active cep requests. * * @throws Exception if an error occurs */ @Test public void cancelAllCep() throws Exception { Event[] events = new Event[] { EventTestBase.generateEquityTradeEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("1"), new BigDecimal("100")), EventTestBase.generateEquityTradeEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("2"), new BigDecimal("200")), EventTestBase.generateEquityAskEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("3"), new BigDecimal("300")), EventTestBase.generateEquityAskEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("4"), new BigDecimal("400")), EventTestBase.generateEquityBidEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("5"), new BigDecimal("500")), EventTestBase.generateEquityBidEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("ORCL"), "Q", new BigDecimal("6"), new BigDecimal("600")) }; assertEquals(2, doCEPTest("esper", new String[] { "select * from trade" }, events, false).size()); StrategyImpl strategy = getRunningStrategy(theStrategy); strategy.getRunningStrategy().onCallback(this); ModuleURN cepModuleURN = new ModuleURN("metc:cep:esper:" + strategy.getDefaultNamespace()); feedEventsToCEP(events, cepModuleURN); assertEquals(0, getReceivedSuggestions(outputURN).size()); // cancel again to make sure nothing breaks strategy.getRunningStrategy().onCallback(this); feedEventsToCEP(events, cepModuleURN); assertEquals(0, getReceivedSuggestions(outputURN).size()); } /** * Tests a strategy's ability to send events to a targeted CEP module * * @throws Exception if an error occurs */ @Test public void sendEventToCEP() throws Exception { // start the event strategy StrategyCoordinates strategyFile = getEventStrategy(); theStrategy = createStrategy(strategyFile.getName(), getLanguage(), strategyFile.getFile(), null, null, null); AbstractRunningStrategy.setProperty("source", "esper"); // get a handle to that strategy StrategyImpl strategy = getRunningStrategy(theStrategy); // begin testing assertNull(AbstractRunningStrategy.getProperty("ask")); assertNull(AbstractRunningStrategy.getProperty("askCount")); // send an event to a null source AbstractRunningStrategy.setProperty("nilSource", "true"); // start the reaction strategy.getRunningStrategy().onOther(askEvent); // make sure nothing got sent out assertNull(AbstractRunningStrategy.getProperty("ask")); assertNull(AbstractRunningStrategy.getProperty("askCount")); // next test - null event AbstractRunningStrategy.setProperty("nilSource", null); AbstractRunningStrategy.setProperty("nilEvent", "true"); assertNull(AbstractRunningStrategy.getProperty("ask")); assertNull(AbstractRunningStrategy.getProperty("askCount")); // start the reaction strategy.getRunningStrategy().onOther(askEvent); // make sure nothing got sent out assertNull(AbstractRunningStrategy.getProperty("ask")); assertNull(AbstractRunningStrategy.getProperty("askCount")); // next test - empty provider AbstractRunningStrategy.setProperty("nilEvent", null); AbstractRunningStrategy.setProperty("source", ""); // start the reaction strategy.getRunningStrategy().onOther(askEvent); // make sure nothing got sent out assertNull(AbstractRunningStrategy.getProperty("ask")); assertNull(AbstractRunningStrategy.getProperty("askCount")); // next - invalid provider AbstractRunningStrategy.setProperty("source", "this-cep-provider-does-not-exist"); // start the reaction strategy.getRunningStrategy().onOther(askEvent); // make sure nothing got sent out assertNull(AbstractRunningStrategy.getProperty("ask")); assertNull(AbstractRunningStrategy.getProperty("askCount")); // next - valid but unstarted provider (since no query is established, the event gets sent but is never received back by the strategy) AbstractRunningStrategy.setProperty("source", "esper"); // start the reaction strategy.getRunningStrategy().onOther(askEvent); // make sure nothing got sent out assertNull(AbstractRunningStrategy.getProperty("ask")); assertNull(AbstractRunningStrategy.getProperty("askCount")); // next, create a query that listens for ask events AbstractRunningStrategy.setProperty("shouldRequestCEPData", "true"); String[] statements = new String[] { "select * from ask" }; AbstractRunningStrategy.setProperty("statements", createConsolidatedCEPStatement(statements)); // start the query strategy.getRunningStrategy().onCallback(this); // start the reaction, this will cause the event to be echoed back to the strategy strategy.getRunningStrategy().onOther(askEvent); assertEquals("1", AbstractRunningStrategy.getProperty("askCount")); assertEquals(askEvent.toString(), AbstractRunningStrategy.getProperty("ask")); // setup onStop test DataSink dataSink = new DataSink(); moduleManager.addSinkListener(dataSink); stopStrategy(theStrategy); Map<DataFlowID,List<Object>> sinkData = dataSink.getAllData(); // should have created a single data flow assertEquals(1, sinkData.keySet().size()); DataFlowID dataFlowID = sinkData.keySet().iterator().next(); assertNotNull(dataFlowID); List<Object> data = sinkData.get(dataFlowID); // the data flow will have 1 event assertEquals(1, data.size()); assertTrue("Expected " + data.get(0) + " to be a TradeEvent", data.get(0) instanceof TradeEvent); } /** * Tests the strategy's ability to send an event to event subscribers. * * @throws Exception if an error occurs */ @Test public void sendEvent() throws Exception { // these will be the subscribers to events ModuleURN alternateURN = createModule(MockRecorderModule.Factory.PROVIDER_URN); MockRecorderModule eventSubscriber = MockRecorderModule.Factory.recorders.get(outputURN); MockRecorderModule allSubscriber = MockRecorderModule.Factory.recorders.get(alternateURN); // start the event strategy StrategyCoordinates strategyFile = getEventStrategy(); theStrategy = createStrategy(strategyFile.getName(), getLanguage(), strategyFile.getFile(), null, null, null); // get a handle to the running strategy StrategyImpl strategy = getRunningStrategy(theStrategy); // begin testing assertTrue(eventSubscriber.getDataReceived().isEmpty()); assertTrue(allSubscriber.getDataReceived().isEmpty()); AbstractRunningStrategy.setProperty("eventOnlyTest", "true"); // send a null event AbstractRunningStrategy.setProperty("nilEvent", "true"); // start reaction strategy.getRunningStrategy().onOther(askEvent); // make sure nothing got sent assertTrue(eventSubscriber.getDataReceived().isEmpty()); assertTrue(allSubscriber.getDataReceived().isEmpty()); // real event (no subscribers yet, though) AbstractRunningStrategy.setProperty("nilEvent", null); // start reaction strategy.getRunningStrategy().onOther(askEvent); // event got through, but didn't go anywhere assertTrue(eventSubscriber.getDataReceived().isEmpty()); assertTrue(allSubscriber.getDataReceived().isEmpty()); // set up a subscriber for the events channel and the all channel DataFlowID eventSubscription = moduleManager.createDataFlow(new DataRequest[] { new DataRequest(theStrategy, OutputType.EVENTS), new DataRequest(outputURN) }, false); DataFlowID allSubscription = moduleManager.createDataFlow(new DataRequest[] { new DataRequest(theStrategy, OutputType.ALL), new DataRequest(alternateURN) }, false); // start again strategy.getRunningStrategy().onOther(askEvent); // check results assertEquals(1, eventSubscriber.getDataReceived().size()); assertEquals(1, allSubscriber.getDataReceived().size()); assertEquals(askEvent, eventSubscriber.getDataReceived().get(0).getData()); assertEquals(askEvent, allSubscriber.getDataReceived().get(0).getData()); eventSubscriber.resetDataReceived(); // cleanup moduleManager.cancel(eventSubscription); moduleManager.cancel(allSubscription); // stop and make sure the event there gets sent DataSink dataSink = new DataSink(); moduleManager.addSinkListener(dataSink); stopStrategy(theStrategy); Map<DataFlowID,List<Object>> sinkData = dataSink.getAllData(); // should have created a single data flow assertEquals(1, sinkData.keySet().size()); DataFlowID dataFlowID = sinkData.keySet().iterator().next(); assertNotNull(dataFlowID); List<Object> data = sinkData.get(dataFlowID); // the data flow will have 1 event assertEquals(1, data.size()); assertTrue("Expected " + data.get(0) + " to be a TradeEvent", data.get(0) instanceof TradeEvent); } /** * Tests a strategy's ability to create processed market data requests. * * @throws Exception if an error occurs */ @Test public void processedMarketDataRequests() throws Exception { for(int apiCounter=0;apiCounter<=1;apiCounter++) { boolean useStringAPI = (apiCounter == 1); AbstractRunningStrategy.getProperties().clear(); if(useStringAPI) { AbstractRunningStrategy.setProperty("useStringAPI", "true"); } // these are the nominal test values String symbols = "METC,ORCL,GOOG,YHOO"; String marketDataSource = BogusFeedModuleFactory.IDENTIFIER; String compressedStatements = createConsolidatedCEPStatement(new String[] { "select * from ask where instrumentAsString='METC'" }); String cepSource = "esper"; // set the default values AbstractRunningStrategy.setProperty("symbols", symbols); AbstractRunningStrategy.setProperty("marketDataSource", marketDataSource); AbstractRunningStrategy.setProperty("statements", compressedStatements); AbstractRunningStrategy.setProperty("cepSource", cepSource); doProcessedMarketDataRequestVerification(false); // begin testing // test with null symbols AbstractRunningStrategy.setProperty("symbols", null); executeProcessedMarketDataRequest(false, false); // test with empty symbols string AbstractRunningStrategy.setProperty("symbols", ""); executeProcessedMarketDataRequest(false, false); // done with negative symbols, replace the value AbstractRunningStrategy.setProperty("symbols", symbols); // test null market data source AbstractRunningStrategy.setProperty("marketDataSource", null); executeProcessedMarketDataRequest(false, true); // test empty market data source (multiple matches, so fails) AbstractRunningStrategy.setProperty("marketDataSource", ""); executeProcessedMarketDataRequest(false, true); // done with negative market data source, replace the value AbstractRunningStrategy.setProperty("marketDataSource", marketDataSource); // test null statements AbstractRunningStrategy.setProperty("statements", null); executeProcessedMarketDataRequest(false, true); // test zero statements AbstractRunningStrategy.setProperty("statements", createConsolidatedCEPStatement(new String[0])); executeProcessedMarketDataRequest(false, true); // done with negative statements, replace the value AbstractRunningStrategy.setProperty("statements", compressedStatements); // test null cep source AbstractRunningStrategy.setProperty("cepSource", null); executeProcessedMarketDataRequest(false, true); // test empty cep source AbstractRunningStrategy.setProperty("cepSource", ""); executeProcessedMarketDataRequest(false, true); // done with negative cep source, replace the value AbstractRunningStrategy.setProperty("cepSource", cepSource); // turn off the md feed moduleManager.stop(bogusDataFeedURN); executeProcessedMarketDataRequest(false, true); // start the md feed again moduleManager.start(bogusDataFeedURN); // next test returns some values executeProcessedMarketDataRequest(true, true); // test cancellation of a combined request AbstractRunningStrategy.setProperty("cancelCep", "true"); // start the strategy for this mini-test theStrategy = createStrategy(getCombinedStrategy().getName(), getLanguage(), getCombinedStrategy().getFile(), null, null, null); AbstractRunningStrategy runningStrategy = (AbstractRunningStrategy)getRunningStrategy(theStrategy).getRunningStrategy(); runningStrategy.onCallback(this); } } /** * Tests that starting or stopping a strategy succeeds or fails depending on the strategy state. * * @throws Exception if an error occurs */ @Test public void stateChanges() throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty("shouldLoopOnStart", "true"); parameters.setProperty("shouldLoopOnStop", "true"); verifyPropertyNull("loopDone"); verifyPropertyNull("onStartBegins"); // strategy doesn't exist yet // need to manually start the strategy because it will be in "STARTING" status for a long long time (UNSTARTED->COMPILING->STARTING) final ModuleURN strategyURN = moduleManager.createModule(StrategyModuleFactory.PROVIDER_URN, null, strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null); final List<Throwable> thrownExceptions = new ArrayList<Throwable>(); // start the strategy in another thread Thread helperThread = new Thread(new Runnable() { @Override public void run() { try { moduleManager.start(strategyURN); } catch (ModuleException e) { thrownExceptions.add(e); } }}); helperThread.start(); // strategy is now somewhere in the journey from UNSTARTED->COMPILING->STARTING. this change is atomic with respect // to module operations // wait until the strategy enters "STARTING" MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { try { return getStatus(strategyURN).equals(STARTING) && AbstractRunningStrategy.getProperty("onStartBegins") != null; } catch (Exception e) { return false; } } }); // strategy is in STARTING state and will stay there until released by instrumentation that affects the running strategy // strategy is now looping // reset start counter AbstractRunningStrategy.setProperty("onStartBegins", null); // test to see what happens if the strategy is started again by the moduleManager (STARTING->UNSTARTED) new ExpectedFailure<ModuleStateException>(MODULE_NOT_STARTED_STATE_INCORRECT, strategyURN.toString(), ExpectedFailure.IGNORE, ExpectedFailure.IGNORE) { @Override protected void run() throws Exception { moduleManager.start(strategyURN); } }; verifyStrategyStatus(strategyURN, STARTING); // try to stop the module (STARTING->STOPPING) new ExpectedFailure<ModuleStateException>(MODULE_NOT_STOPPED_STATE_INCORRECT, strategyURN.toString(), ExpectedFailure.IGNORE, ExpectedFailure.IGNORE) { @Override protected void run() throws Exception { moduleManager.stop(strategyURN); } }; // release the running strategy (or it will keep running beyond the end of the test) AbstractRunningStrategy.setProperty("shouldStopLoop", "true"); helperThread.join(); // strategy is now moving from STARTING->RUNNING // wait for the strategy to become ready verifyStrategyReady(strategyURN); // strategy is in RUNNING state verifyStrategyStatus(strategyURN, RUNNING); // try to start again (RUNNING->UNSTARTED) new ExpectedFailure<ModuleStateException>(MODULE_NOT_STARTED_STATE_INCORRECT, strategyURN.toString(), ExpectedFailure.IGNORE, ExpectedFailure.IGNORE) { @Override protected void run() throws Exception { moduleManager.start(strategyURN); } }; // change status to STOPPING // make sure the strategy loops in onStop so we have time to play with it // reset all our flags and counters setPropertiesToNull(); helperThread = new Thread(new Runnable() { @Override public void run() { try { moduleManager.stop(strategyURN); } catch (ModuleException e) { thrownExceptions.add(e); } }}); helperThread.start(); // wait until the strategy enters "STOPPING" MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { return getStatus(strategyURN).equals(STOPPING) && AbstractRunningStrategy.getProperty("onStopBegins") != null; } }); // strategy is now looping // reset stop counter AbstractRunningStrategy.setProperty("onStopBegins", null); // module is listed as stopped assertFalse(moduleManager.getModuleInfo(strategyURN).getState().isStarted()); // test stopping (STOPPING->STOPPING) new ExpectedFailure<ModuleStateException>(MODULE_NOT_STOPPED_STATE_INCORRECT, strategyURN.toString(), ExpectedFailure.IGNORE, ExpectedFailure.IGNORE) { @Override protected void run() throws Exception { moduleManager.stop(strategyURN); } }; // test starting (STOPPING->UNSTARTED) new ExpectedFailure<ModuleStateException>(MODULE_NOT_STARTED_STATE_INCORRECT, strategyURN.toString(), ExpectedFailure.IGNORE, ExpectedFailure.IGNORE) { @Override protected void run() throws Exception { moduleManager.start(strategyURN); } }; // let the strategy stop AbstractRunningStrategy.setProperty("shouldStopLoop", "true"); helperThread.join(); // wait for the strategy to stop verifyStrategyStopped(strategyURN); verifyStrategyStatus(strategyURN, STOPPED); // module is listed as stopped assertFalse(moduleManager.getModuleInfo(strategyURN).getState().isStarted()); // cannot stop again (STOPPED->STOPPING) new ExpectedFailure<ModuleStateException>(MODULE_NOT_STOPPED_STATE_INCORRECT, strategyURN.toString(), ExpectedFailure.IGNORE, ExpectedFailure.IGNORE) { @Override protected void run() throws Exception { moduleManager.stop(strategyURN); } }; // can start again (STOPPED->UNSTARTED->...) moduleManager.start(strategyURN); // (...->RUNNING) verifyStrategyReady(strategyURN); verifyStrategyStatus(strategyURN, RUNNING); // strategy is RUNNING // move it to FAILED (RUNNING->STOPPING->FAILED) AbstractRunningStrategy.setProperty("shouldFailOnStop", "true"); stopStrategy(strategyURN); verifyStrategyStatus(strategyURN, FAILED); AbstractRunningStrategy.setProperty("shouldFailOnStop", null); // try to stop (FAILED->STOPPING) new ExpectedFailure<ModuleStateException>(MODULE_NOT_STOPPED_STATE_INCORRECT, strategyURN.toString(), ExpectedFailure.IGNORE, ExpectedFailure.IGNORE) { @Override protected void run() throws Exception { moduleManager.stop(strategyURN); } }; // make sure it can start again (FAILED->UNSTARTED) moduleManager.start(strategyURN); verifyStrategyReady(strategyURN); moduleManager.stop(strategyURN); } /** * Tests the ability for a strategy to request and receive {@link org.marketcetera.marketdata.Content#MARKET_STAT} data. * * @throws Exception if an error occurs */ @Test public void statistics() throws Exception { verifyPropertyNull("onStatistics"); Properties parameters = new Properties(); parameters.setProperty("content", "MARKET_STAT"); getMarketData(BogusFeedModuleFactory.IDENTIFIER, "GOOG,YHOO,MSFT,METC", false, parameters); verifyPropertyNonNull("onStatistics"); } /** * Tests the ability of a strategy to request and cancel data flows from other modules. * * @throws Exception if an error occurs */ @Test public void createDataFlows() throws Exception { // invalid URN final ModuleURN invalidURN = new ModuleURN("metc:something:something"); // valid URN, but not started final ModuleURN validUnstartedURN = moduleManager.createModule(MockRecorderModule.Factory.PROVIDER_URN); // valid URN, started, but not emitter final ModuleURN validURNNotEmitter = SinkModuleFactory.INSTANCE_URN; // valid URN, started, but not receiver final ModuleURN validURNNotReceiver = BogusFeedModuleFactory.INSTANCE_URN; assertFalse(moduleManager.getModuleInfo(SinkModuleFactory.INSTANCE_URN).isEmitter()); // valid, started receiver ModuleURN dataEmitterURN = createModule(StrategyDataEmissionModule.Factory.PROVIDER_URN); final Properties parameters = new Properties(); // null URN list doDataFlowTest(parameters, false); // single URN (invalid flow, need two at least) parameters.setProperty("urns", dataEmitterURN.getValue()); doDataFlowTest(parameters, false); // two URNs, but one is unstarted parameters.setProperty("urns", validUnstartedURN.getValue()); parameters.setProperty("useStrategyURN", "true"); doDataFlowTest(parameters, false); // two URNs, but one is invalid parameters.setProperty("urns", invalidURN.getValue()); doDataFlowTest(parameters, false); // valid, started, but not emitter parameters.setProperty("urns", validURNNotEmitter.getValue()); doDataFlowTest(parameters, false); // valid, started, but not receiver parameters.setProperty("urns", dataEmitterURN.getValue() + "," + validURNNotReceiver.getValue()); doDataFlowTest(parameters, false); // valid simple test with 2 URNs parameters.setProperty("urns", dataEmitterURN.getValue()); doDataFlowTest(parameters, true); // again, but this time setting up extra data flow tests parameters.setProperty("shouldCancelDataFlow", "true"); doDataFlowTest(parameters, true); parameters.remove("shouldCancelDataFlow"); // repeat the test, but sabotage the manual cancel parameters.setProperty("urns", dataEmitterURN.getValue()); parameters.setProperty("shouldSkipCancel", "true"); doDataFlowTest(parameters, true); parameters.remove("shouldSkipCancel"); // all tests so far have been without the sink, now add the sink parameters.setProperty("routeToSink", "true"); doDataFlowTest(parameters, true); // do a test that sets up a data flow that doesn't involve the strategy parameters.remove("useStrategyURN"); parameters.remove("routeToSink"); parameters.setProperty("urns", dataEmitterURN.getValue() + "," + MockRecorderModule.Factory.recorders.get(outputURN).getURN()); doDataFlowTest(parameters, true); // a new test that tries to set up a data flow when the strategy can't accept new data parameters.setProperty("urns", dataEmitterURN.getValue()); parameters.setProperty("useStrategyURN", "true"); parameters.setProperty("shouldMakeNewRequest", "true"); doDataFlowTest(parameters, true); } /** * Tests the ability to set and retrieve user data. * * @throws Exception if an unexpected error occurs */ @Test public void userdata() throws Exception { Client testClient = StrategyModule.clientFactory.getClient(); assertNull(testClient.getUserData()); StrategyCoordinates strategy = getStrategyCompiles(); ModuleURN strategyModule = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); verifyPropertyNonNull("onStart"); doSuccessfulStartTest(strategyModule); Properties userdata = testClient.getUserData(); assertNotNull(userdata); assertNotNull(userdata.getProperty("onStart")); } /** * Gets the language to use for this test. * * @return a <code>Language</code> value */ protected abstract Language getLanguage(); /** * Get a strategy that will not compile in the given language. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getStrategyWillNotCompile(); /** * Get a strategy that will compile in the given language. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getStrategyCompiles(); /** * Get a strategy whose main class does not subclass {@link RunningStrategy}. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getStrategyWrongClass(); /** * Get a strategy with multiple classes. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getStrategyMultipleClasses(); /** * Get a strategy which overrides only "onAsk". * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getEmptyStrategy(); /** * Get a strategy which expects parameters. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getParameterStrategy(); /** * Get a strategy which executes trade suggestions. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getSuggestionStrategy(); /** * Get a strategy which sends FIX messages. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getMessageStrategy(); /** * Get a strategy that sends orders. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getOrdersStrategy(); /** * Get a strategy that sends other data. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getOtherStrategy(); /** * Gets a strategy that defines and calls into a helper class. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getPart1Strategy(); /** * Get a strategy that redefines the class and helper defined in {@link #getPart1Strategy()}. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getPart1RedefinedStrategy(); /** * Get a strategy that complements the classes defined in {@link #getPart1Strategy()}. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getPart2Strategy(); /** * Gets a strategy that sends events. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getEventStrategy(); /** * Gets a strategy that executes a processed market data request. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getCombinedStrategy(); /** * Gets a strategy that requests and cancels data flows. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getDataFlowStrategy(); /** * Gets a strategy that exercises the strategy API's ability to retain and * release <code>OrderID</code> values. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getOrderRetentionStrategy(); /** * Gets a strategy that exercises the Strategy API calls related to * positions. * * @return a <code>StrategyCoordinates</code> value */ protected abstract StrategyCoordinates getPositionsStrategy(); /** * Indicates the number of expected compiler warnings for the given strategy. * * <p>Subclasses may override this method to assist calculations for tests that * compute the number of expected messages. The default implementation returns * zero. * * @param inStrategy a <code>StrategyCoordinates</code> value * @return an <code>int</code> value */ protected int getExpectedCompilationWarningsFor(StrategyCoordinates inStrategy) { return 0; } /** * Executes a single processed market data request test. * * @param inSucceeds a <code>boolean</code> value indicating whether the test is expected to succeed or not * @param inCanConstructRequest a <code>boolean</code> value indicating whether the request can be constructed or not * @throws Exception if an error occurs */ private void executeProcessedMarketDataRequest(boolean inSucceeds, boolean inCanConstructRequest) throws Exception { theStrategy = createStrategy(getCombinedStrategy().getName(), getLanguage(), getCombinedStrategy().getFile(), null, null, null); AbstractRunningStrategy strategy = (AbstractRunningStrategy)getRunningStrategy(theStrategy).getRunningStrategy(); AbstractRunningStrategy.setProperty("finished", null); // reset any stored results from the previous test Set<Object> keys = new HashSet<Object>(AbstractRunningStrategy.getProperties().keySet()); for(Object rawKey : keys) { String key = (String)rawKey; if(key.startsWith("ask") || key.startsWith("bid")) { AbstractRunningStrategy.getProperties().remove(rawKey); } } AbstractRunningStrategy.setProperty("bid", null); AbstractRunningStrategy.setProperty("ask", null); // start test strategy.onOther(this); // retrieve the id returned by the request String requestIDString = AbstractRunningStrategy.getProperty("requestID"); if(inCanConstructRequest) { assertNotNull("The request should have returned a value, either zero or non-zero, but null means the request didn't even happen", requestIDString); } else { assertNull(requestIDString); } // wait until the agreed-upon number of events have arrived (if the strategy is going to work) if(inSucceeds) { assertTrue(Integer.parseInt(requestIDString) > 0); MarketDataFeedTestBase.wait(new Callable<Boolean>(){ @Override public Boolean call() throws Exception { return AbstractRunningStrategy.getProperty("finished") != null; } }); } else { if(inCanConstructRequest) { assertEquals("0", requestIDString); } else { assertNull(requestIDString); } } // check results doProcessedMarketDataRequestVerification(inSucceeds); stopStrategy(theStrategy); } /** * Verify the result of a single processed market data request. * * @param inSucceeds a <code>boolean</code> value indicating whether the test is expected to succeed or not * @throws Exception if an error occurs */ private void doProcessedMarketDataRequestVerification(boolean inSucceeds) throws Exception { Properties storedProperties = AbstractRunningStrategy.getProperties(); for(Object rawKey : storedProperties.keySet()) { String key = (String)rawKey; if(key.contains("bid")) { fail("Should not have received any bids"); } if(key.contains("ask")) { String value = storedProperties.getProperty(key); assertEquals(inSucceeds ? "Received an ask for a symbol other than 'METC': " + key : "Wasn't expecting any asks", inSucceeds, key.contains("METC")); assertTrue("Expected more than 0 asks for 'METC'", Integer.parseInt(value) > 0); } } } /** * Verifies that a trade suggestion created as a result of a CEP query matches the expected values. * * @param inSymbol a <code>String</code> value containing the expected symbol * @param inPrice a <code>BigDecimal</code> value containing the expected price * @param inQuantity a <code>BigDecimal</code> value containing the expected quantity * @param inSuggestion an <code>OrderSingleSuggestion</code> containing the actual suggestion * @throws Exception if an error occurs */ private void verifyCEPSuggestion(String inSymbol, BigDecimal inPrice, BigDecimal inQuantity, OrderSingleSuggestion inSuggestion) throws Exception { assertEquals(inSymbol, inSuggestion.getOrder().getInstrument().getSymbol()); assertEquals(inPrice, inSuggestion.getOrder().getPrice()); assertEquals(inQuantity, inSuggestion.getOrder().getQuantity()); } /** * Retrieves the suggestions stored by the given recorder. * * @param inRecorder a <code>ModuleURN</code> value containing a {@link MockRecorderModule} URN. * @return a <code>List<OrderSingleSuggestion></code> value containing the recorded suggestions */ private List<OrderSingleSuggestion> getReceivedSuggestions(ModuleURN inRecorder) { MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(inRecorder); List<OrderSingleSuggestion> suggestions = new ArrayList<OrderSingleSuggestion>(); for(DataReceived datum : recorder.getDataReceived()) { suggestions.add((OrderSingleSuggestion)datum.getData()); } recorder.resetDataReceived(); return suggestions; } /** * Feeds the given events to the given <code>CEP</code> module. * * @param inEvents an <code>Event[]</code> value * @param inCEPModule a <code>ModuleURN</code> value containing a CEP module * @return a <code>DataFlowID</code> value representing the channel by which the events are fed * @throws Exception if an error occurs */ private DataFlowID feedEventsToCEP(Event[] inEvents, ModuleURN inCEPModule) throws Exception { SynchronousRequest request = new SynchronousRequest(inEvents); request.semaphore.acquire(); DataFlowID dataFlowID = moduleManager.createDataFlow(new DataRequest[] { new DataRequest(CopierModuleFactory.INSTANCE_URN, request), new DataRequest(inCEPModule) }, false); // wait until the copier is ready request.semaphore.acquire(); return dataFlowID; } /** * Creates a consolidated string used to communicate a set of CEP statements to a strategy. * * @param inStatements a <code>String[]</code> value * @return a <code>String</code> value */ private String createConsolidatedCEPStatement(String[] inStatements) { StringBuilder statements = new StringBuilder(); boolean separatorNeeded = false; for(String statement : inStatements) { if(separatorNeeded) { statements.append("#"); // arbitrary separator character } else { separatorNeeded = true; } statements.append(statement); } return statements.toString(); } /** * Executes a single CEP test. * * @param inProvider a <code>String</code> value containing the provider to whom to make the request * @param inStatements a <code>String[]</code> value containing the statements to pass to the CEP module * @param inEvents an <code>Event[]</code> value containing the events to cause to be passed to the CEP module * @param inCleanup a <code>boolean</code> value indicating whether the strategy started during the test should be stopped or not * @return a <code>List<OrderSingleSuggestion></code> value containing the suggestions received * @throws Exception if an error occurs */ private List<OrderSingleSuggestion> doCEPTest(String inProvider, String[] inStatements, Event[] inEvents, boolean inCleanup) throws Exception { setPropertiesToNull(); MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(outputURN); recorder.resetDataReceived(); Properties parameters = new Properties(); parameters.setProperty("shouldRequestCEPData", "true"); if(inProvider != null) { parameters.setProperty("source", inProvider); } if(inStatements != null) { parameters.setProperty("statements", createConsolidatedCEPStatement(inStatements)); } StrategyCoordinates strategyFile = getStrategyCompiles(); theStrategy = createStrategy(strategyFile.getName(), getLanguage(), strategyFile.getFile(), parameters, null, outputURN); StrategyImpl strategy = getRunningStrategy(theStrategy); ModuleURN cepModuleURN = new ModuleURN("metc:cep:" + inProvider + ":" + strategy.getDefaultNamespace()); long requestID = 0; if(AbstractRunningStrategy.getProperty("requestID") != null) { requestID = Long.parseLong(AbstractRunningStrategy.getProperty("requestID")); } // feed events into the cep module if(requestID != 0) { feedEventsToCEP(inEvents, cepModuleURN); } // collect the suggestions created List<OrderSingleSuggestion> suggestions = getReceivedSuggestions(outputURN); if(inCleanup) { stopStrategy(theStrategy); } return suggestions; } /** * Performs a single brokers test. * * @param inExpectedBrokers a <code>BrokerStatus[]</code> value containing the expected brokers * @throws Exception if an error occurs */ private void doBrokerTest(BrokerStatus[] inExpectedBrokers) throws Exception { StrategyCoordinates strategy = getStrategyCompiles(); AbstractRunningStrategy.getProperties().clear(); AbstractRunningStrategy.setProperty("askForBrokers", "true"); verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); int counter = 0; for(BrokerStatus broker : inExpectedBrokers) { assertEquals(broker.toString(), AbstractRunningStrategy.getProperty("" + counter++)); } // verify there are no extra properties assertNull("Property " + inExpectedBrokers.length + " was non-null", AbstractRunningStrategy.getProperty("" + inExpectedBrokers.length)); } /** * Starts a strategy module which generates <code>FIX</code> messages and measures them against the * give expected results. * * @param inParameters a <code>Properties</code> value * @param inExpectedOrders a <code>FIXOrder[]</code> value * @throws Exception if an error occurs */ private void doMessageTest(Properties inParameters, final FIXOrder[] inExpectedOrders) throws Exception { ModuleURN suggestionReceiver = generateOrders(getMessageStrategy(), inParameters); MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(suggestionReceiver); assertNotNull("Must be able to find the recorder created", recorder); validateMessages(recorder, inExpectedOrders); stopStrategy(theStrategy); validateMessages(recorder, inExpectedOrders); } /** * Validates sent messages. * * @param inRecorder a <code>MockRecorderModule</code> value * @param inExpectedOrders an <code>FIXOrder[]</code> value */ private void validateMessages(MockRecorderModule inRecorder, FIXOrder[] inExpectedOrders) { List<DataReceived> messages = inRecorder.getDataReceived(); assertEquals("The number of expected messages does not match the number of actual messages", inExpectedOrders.length, messages.size()); int index = 0; for(DataReceived datum : messages) { TypesTestBase.assertOrderFIXEquals(inExpectedOrders[index++], (FIXOrder)datum.getData(),true); } inRecorder.resetDataReceived(); } /** * Creates a strategy module from the given script with the given parameters and returns the * <code>ModuleURN</code> of the module that received any generated orders. * * @param inStrategy a <code>StrategyCoordinates</code> value * @param inParameters a <code>Properties</code> value * @return a <code>ModuleURN</code> value * @throws Exception if an error occurs */ private ModuleURN generateOrders(StrategyCoordinates inStrategy, Properties inParameters) throws Exception { // start the strategy pointing at the suggestion receiver for its suggestions createStrategy(null, inStrategy.getName(), getLanguage(), inStrategy.getFile(), inParameters, false, outputURN); return outputURN; } /** * Starts a strategy module which generates suggestions and measures them against the * given expected results. * * @param inParameters a <code>Properties</code> value * @param inExpectedSuggestions an <code>OrderSingleSuggestion[]</code> value * @throws Exception if an error occurs */ private void doSuggestionTest(Properties inParameters, final OrderSingleSuggestion[] inExpectedSuggestions) throws Exception { ModuleURN suggestionReceiver = generateSuggestions(getSuggestionStrategy(), inParameters, outputURN); // verify the data verifySuggestions(inExpectedSuggestions, suggestionReceiver); // do the same test while stopping stopStrategy(theStrategy); // verify again verifySuggestions(inExpectedSuggestions, suggestionReceiver); } /** * Verifies that the expected suggestions were sent. * * @param inExpectedSuggestions an <code>OrderSingleSuggestion[]</code> value * @param inSuggestionReceiver a <code>ModuleURN</code> value */ private void verifySuggestions(OrderSingleSuggestion[] inExpectedSuggestions, ModuleURN inSuggestionReceiver) { final MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(inSuggestionReceiver); assertNotNull("Must be able to find the recorder created", recorder); List<DataReceived> suggestions = recorder.getDataReceived(); assertEquals("The number of expected suggestions does not match the number of actual suggestions", inExpectedSuggestions.length, suggestions.size()); int index = 0; for(DataReceived datum : suggestions) { TypesTestBase.assertOrderSuggestionEquals(inExpectedSuggestions[index++], (OrderSingleSuggestion)datum.getData(), true); } recorder.resetDataReceived(); } /** * Performs a single iteration of an <code>ExecutionReport</code> test. * * @param inExecutionReportCount an <code>int</code> value containing the number of execution reports expected * @param inSendOrders a <code>boolean</code> value indicating if the orders should be submitted or not (simulate failure) * @throws Exception if an error occurs */ private void doExecutionReportTest(final int inExecutionReportCount, boolean inSendOrders) throws Exception { AbstractRunningStrategy.setProperty("executionReportCount", "0"); AbstractRunningStrategy.setProperty("price", "1000"); AbstractRunningStrategy.setProperty("quantity", "500"); AbstractRunningStrategy.setProperty("side", Side.Sell.toString()); AbstractRunningStrategy.setProperty("symbol", "METC"); AbstractRunningStrategy.setProperty("orderType", OrderType.Market.name()); AbstractRunningStrategy.setProperty("quantity", "10000"); // generate expected order List<ExecutionReport> expectedExecutionReports = new ArrayList<ExecutionReport>(); StrategyImpl runningStrategy = getRunningStrategy(theStrategy); OrderID orderID = null; if(inSendOrders) { // this will trigger the strategy to submit an order runningStrategy.dataReceived(askEvent); // generate expected result OrderSingle expectedOrder = Factory.getInstance().createOrderSingle(); expectedOrder.setPrice(new BigDecimal("1000")); expectedOrder.setQuantity(new BigDecimal("500")); expectedOrder.setSide(Side.Sell); expectedOrder.setInstrument(new Equity("METC")); expectedOrder.setOrderType(OrderType.Market); expectedOrder.setQuantity(new BigDecimal(10000)); String orderIDString = AbstractRunningStrategy.getProperty("orderID"); if(orderIDString != null) { orderID = new OrderID(orderIDString); expectedOrder.setOrderID(new OrderID(orderIDString)); } if(MockRecorderModule.shouldSendExecutionReports) { expectedExecutionReports.addAll(generateExecutionReports(expectedOrder)); } } runningStrategy.dataReceived(EventTestBase.generateEquityBidEvent(System.nanoTime(), System.currentTimeMillis(), new Equity("METC"), "Q", new BigDecimal("100.00"), new BigDecimal("10000"))); assertEquals(inExecutionReportCount, Integer.parseInt(AbstractRunningStrategy.getProperty("executionReportCount"))); Deque<ReportBase> actualExecutionReports = ((AbstractRunningStrategy)runningStrategy.getRunningStrategy()).getExecutionReports(orderID); assertEquals(expectedExecutionReports.size(), actualExecutionReports.size()); int index = 0; Collections.reverse(expectedExecutionReports); for(ReportBase actualExecutionReport : actualExecutionReports) { TypesTestBase.assertExecReportEquals(expectedExecutionReports.get(index++), (ExecutionReport)actualExecutionReport); } AbstractRunningStrategy.getProperties().clear(); MockRecorderModule.ordersReceived = 0; } /** * Starts a strategy module which generates orders and measures them against the * given expected results. * @param inStrategy a <code>ModuleURN</code> value * @param inExpectedOrders an <code>OrderSingle[]</code> value * @param inExpectedCumulativeOrders a <code>List<OrderSingle></code> value * @throws Exception if an error occurs */ private void doOrderTest(ModuleURN inStrategy, final OrderSingle[] inExpectedOrders, List<OrderSingle> inExpectedCumulativeOrders) throws Exception { final MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(outputURN); assertNotNull("Must be able to find the recorder created", recorder); // this will execute onAsk on the strategies, which will generate the desired order recorder.resetDataReceived(); MockRecorderModule.shouldSendExecutionReports = false; doSuccessfulStartTestNoVerification(inStrategy); List<DataReceived> orders = recorder.getDataReceived(); assertEquals("The number of expected orders does not match the number of actual orders", inExpectedOrders.length, orders.size()); int index = 0; for(DataReceived datum : orders) { TypesTestBase.assertOrderSingleEquals(inExpectedOrders[index++], (OrderSingle)datum.getData(), true); } StrategyImpl runningStrategy = getRunningStrategy(inStrategy); Set<OrderSingle> actualCumulativeOrders = ((AbstractRunningStrategy)runningStrategy.getRunningStrategy()).getSubmittedOrders(); assertEquals(inExpectedCumulativeOrders.size(), actualCumulativeOrders.size()); index = 0; for(OrderSingle actualOrder : actualCumulativeOrders) { TypesTestBase.assertOrderSingleEquals(inExpectedCumulativeOrders.get(index++), actualOrder, true); } } /** * Starts a strategy module which generates data and measures against the * given expected results. * * @param inStrategy a <code>ModuleURN</code> value * @param inExpectedObjects an <code>Object[]</code> value * @throws Exception if an error occurs */ private void doOtherTest(ModuleURN inStrategy, Object[] inExpectedObjects) throws Exception { MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(outputURN); assertNotNull("Must be able to find the recorder created", recorder); // this will execute onAsk on the strategies, which will generate the desired data recorder.resetDataReceived(); AbstractRunningStrategy runningStrategy = (AbstractRunningStrategy)getRunningStrategy(inStrategy).getRunningStrategy(); runningStrategy.onAsk(askEvent); List<DataReceived> objects = recorder.getDataReceived(); int index = 0; for(DataReceived datum : objects) { assertEquals(inExpectedObjects[index++], datum.getData()); } } /** * Executes a single data flow test. * * @param inParameters a <code>Properties</code> value * @param inDataExpected a <code>boolean</code> value indicating whether the test is expected to produce data (succeed) or not * @throws Exception if an error occurs */ private void doDataFlowTest(Properties inParameters, boolean inDataExpected) throws Exception { MockRecorderModule recorder = MockRecorderModule.Factory.recorders.get(outputURN); DataSink dataSink = new DataSink(); moduleManager.addSinkListener(dataSink); assertNotNull("Must be able to find the recorder created", recorder); recorder.resetDataReceived(); setPropertiesToNull(); StrategyCoordinates strategy = getDataFlowStrategy(); theStrategy = createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), inParameters, null, outputURN); List<Object> inExpectedData = new ArrayList<Object>(); if(inDataExpected) { inExpectedData.addAll(StrategyDataEmissionModule.getDataToSend()); assertNotNull(AbstractRunningStrategy.getProperty("dataFlowID")); } List<DataReceived> dataReceived = recorder.getDataReceived(); assertEquals("Expected " + inExpectedData + " but got " + dataReceived, inExpectedData.size(), dataReceived.size()); int index = 0; for(DataReceived datum : dataReceived) { assertEquals("Expected " + inExpectedData.get(index) + " but got " + datum, inExpectedData.get(index++), datum.getData()); } // check the sink if(inParameters.getProperty("routeToSink") == "true") { Map<DataFlowID,List<Object>> sinkData = dataSink.getAllData(); // all our tests create a single data flow at a time assertEquals(1, sinkData.keySet().size()); DataFlowID dataFlowID = sinkData.keySet().iterator().next(); assertTrue("Expected " + inExpectedData + " but got " + sinkData.get(dataFlowID), Arrays.equals(inExpectedData.toArray(), sinkData.get(dataFlowID).toArray())); } else { assertTrue(dataSink.getAllData().isEmpty()); } String rawDataFlowID = AbstractRunningStrategy.getProperty("dataFlowID"); assertEquals(inDataExpected, rawDataFlowID != null); // do an extra test, if necessary, canceling a few data flows if(inParameters.getProperty("shouldCancelDataFlow") == "true") { // cancel the main flow first (later setting us up to cancel a stopped flow) if(inDataExpected) { DataFlowID dataFlowID = new DataFlowID(rawDataFlowID); assertTrue(moduleManager.getDataFlows(true).contains(dataFlowID)); getRunningStrategy(theStrategy).getRunningStrategy().onCallback(dataFlowID); assertNotNull(AbstractRunningStrategy.getProperty("localDataFlowStopped")); assertFalse(moduleManager.getDataFlows(true).contains(dataFlowID)); AbstractRunningStrategy.setProperty("localDataFlowStopped", null); // create a bogus data flow dataFlowID = new DataFlowID("not-a-data-flow-id"); getRunningStrategy(theStrategy).getRunningStrategy().onCallback(dataFlowID); assertNotNull(AbstractRunningStrategy.getProperty("localDataFlowStopped")); assertFalse(moduleManager.getDataFlows(true).contains(dataFlowID)); AbstractRunningStrategy.setProperty("localDataFlowStopped", null); // create a data flow (not created by the strategy) MarketDataRequest inRequest = MarketDataRequestBuilder.newRequest().withProvider(BogusFeedModuleFactory.IDENTIFIER).withSymbols("METC").create(); dataFlowID = moduleManager.createDataFlow(new DataRequest[] { new DataRequest(new ModuleURN(String.format("metc:mdata:%s", inRequest.getProvider())), inRequest)}, true); assertNotNull(dataFlowID); assertTrue(moduleManager.getDataFlows(true).contains(dataFlowID)); getRunningStrategy(theStrategy).getRunningStrategy().onCallback(dataFlowID); assertNotNull(AbstractRunningStrategy.getProperty("localDataFlowStopped")); assertFalse(moduleManager.getDataFlows(true).contains(dataFlowID)); } } // cancel the data flow stopStrategy(theStrategy); // one way or the other, stopping the strategy will cause the data flow to stop, either directly // or indirectly when the strategy module stops if(inDataExpected) { DataFlowID dataFlowID = new DataFlowID(rawDataFlowID); // verifies that the data flow is not still running assertFalse(moduleManager.getDataFlows(true).contains(dataFlowID)); if(inParameters.getProperty("shouldSkipCancel") != null) { assertNull(AbstractRunningStrategy.getProperty("dataFlowStopped")); } else { assertNotNull(AbstractRunningStrategy.getProperty("dataFlowStopped")); } } // check to see if the strategy tried to create a new data flow while stopping if(inParameters.getProperty("shouldMakeNewRequest") == "true") { assertEquals("true", AbstractRunningStrategy.getProperty("newDataFlowAttempt")); assertEquals("null", AbstractRunningStrategy.getProperty("newDataFlowID")); } } /** * Creates a strategy module from the given script with the given parameters and returns the * <code>ModuleURN</code> of the module that received any generated order suggestions. * * @param inStrategy a <code>StrategyCoordinates</code> value * @param inParameters a <code>Properties</code> value * @param inOutputURN a <code>ModuleURN</code> value containing the destination to which to emit suggestions * @return a <code>ModuleURN</code> value * @throws Exception if an error occurs */ private ModuleURN generateSuggestions(StrategyCoordinates inStrategy, Properties inParameters, ModuleURN inOutputURN) throws Exception { // start the strategy pointing at the suggestion receiver for its suggestions createStrategy(inStrategy.getName(), getLanguage(), inStrategy.getFile(), inParameters, null, inOutputURN); return inOutputURN; } /** * Creates a strategy module from the given script with the given parameters and returns the * <code>ModuleURN</code> of the module that received any generated orders. * * @param inStrategy a <code>StrategyCoordinates</code> value * @param inOrdersURN a <code>ModuleURN</code> value containing the destination to which to emit suggestions * @return a <code>ModuleURN</code> value * @throws Exception if an error occurs */ private ModuleURN generateOrders(StrategyCoordinates inStrategy, ModuleURN inOrdersURN) throws Exception { // start the strategy pointing at the orders receiver for its orders theStrategy = createStrategy(inStrategy.getName(), getLanguage(), inStrategy.getFile(), null, null, inOrdersURN); setupMockORSConnection(theStrategy); return theStrategy; } /** * Creates a strategy that requests market data from the given provider for the given symbols. * * @param inProvider a <code>String</code> value containing the instance identifier of a market data provider * @param inSymbols a <code>String</code> value containing a comma-separated list of symbols for which to * request market data * @param inUseStringAPI a <code>boolean</code> value indicating whether to use the string version of the new market data API * @param inParameters a <code>Properties</code> value containing parameters to pass to the strategy * @return a <code>ModuleURN</code> value containing the instance URN of the strategy guaranteed to be running * @throws Exception if an error occurs */ private ModuleURN getMarketData(String inProvider, String inSymbols, boolean inUseStringAPI, Properties inParameters) throws Exception { final StrategyCoordinates strategy = getStrategyCompiles(); inParameters.setProperty("shouldRequestData", inProvider); inParameters.setProperty("symbols", inSymbols); if(inUseStringAPI) { inParameters.setProperty("useStringAPI", "true"); } return createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), inParameters, null, null); } /** * Tests that the given strategy is functional by verifying it receives data sent to it. * * @param inStrategy a <code>ModuleURN</code> value containing a reference to a started strategy * @throws Exception if an error occurs */ private void doSuccessfulStartTest(ModuleURN inStrategy) throws Exception { doSuccessfulStartTestNoVerification(inStrategy); // verify the data was received verifyNonNullProperties(); } /** * Tests that the given strategy has been started and can receive data. * * @param inStrategy a <code>ModuleURN</code> value * @throws Exception if an error occurs */ protected void doSuccessfulStartTestNoVerification(ModuleURN inStrategy) throws Exception { verifyStrategyReady(inStrategy); // create an emitter module that will emit the types of data that the strategy must be able to process ModuleURN dataEmitterURN = createModule(StrategyTestBase.StrategyDataEmissionModule.Factory.PROVIDER_URN); // plumb the emitter together with the strategy (the data is transmitted when the request is made) DataFlowID dataFlowID = moduleManager.createDataFlow(new DataRequest[] { new DataRequest(dataEmitterURN, null), new DataRequest(inStrategy) }, false); // shut down the flow moduleManager.cancel(dataFlowID); } /** * Tests that the given callback fails as expected. * * <p>Note that this test requires the cooperation of the strategy being tested. The strategy * is supposed to look for the presence of the given parameter and fail in the appropriate callback * however it likes. * * @param inParameterThatCausesACallbackToFail a <code>String</code> value * @param inCallbacksThatShouldHaveSucceeded a <code>String[]</code> value * @throws Exception if an error occurs */ private void doCallbackFailsTest(String inParameterThatCausesACallbackToFail, String[] inCallbacksThatShouldHaveSucceeded) throws Exception { setPropertiesToNull(); final StrategyCoordinates strategy = getStrategyCompiles(); final Properties parameters = new Properties(); parameters.setProperty(inParameterThatCausesACallbackToFail, "true"); doSuccessfulStartTestNoVerification(createStrategy(strategy.getName(), getLanguage(), strategy.getFile(), parameters, null, null)); Set<String> allCallbacks = new HashSet<String>(Arrays.asList(new String[] { "onAsk", "onBid", "onCancel", "onExecutionReport", "onTrade", "onOther", "onDividend" })); for(String callback : inCallbacksThatShouldHaveSucceeded) { verifyPropertyNonNull(callback); allCallbacks.remove(callback); } for(String callbackShouldBeNull : allCallbacks) { verifyPropertyNull(callbackShouldBeNull); } } /** * Executes one iteration of the getPositionAsOf test. * * @param inSymbol a <code>String</code> value * @param inDate a <code>Date</code> value * @param inExpectedPosition a <code>BigDecimal</code> value * @throws Exception if an unexpected error occurs */ private void doPositionAsOfTest(String inSymbol, Date inDate, BigDecimal inExpectedPosition) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("positionAsOfDuringStop", "not-empty"); if(inSymbol != null) { AbstractRunningStrategy.setProperty("symbol", inSymbol); } if(inDate != null) { AbstractRunningStrategy.setProperty("date", Long.toString(inDate.getTime())); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedPosition == null ? null : inExpectedPosition.toString()), AbstractRunningStrategy.getProperty("positionAsOf")); assertNull(AbstractRunningStrategy.getProperty("positionAsOfDuringStop")); } /** * Executes one iteration of the getCurrencyPositionAsOf test. * * @param inSymbol a <code>String</code> value * @param inDate a <code>Date</code> value * @param inExpectedPosition a <code>BigDecimal</code> value * @throws Exception if an unexpected error occurs */ private void doCurrencyPositionAsOfTest(String inSymbol, Date inDate, BigDecimal inExpectedPosition) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("currencyPositionAsOfDuringStop", "not-empty"); if(inSymbol != null) { AbstractRunningStrategy.setProperty("symbol", inSymbol); } if(inDate != null) { AbstractRunningStrategy.setProperty("date", Long.toString(inDate.getTime())); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedPosition == null ? null : inExpectedPosition.toString()), AbstractRunningStrategy.getProperty("currencyPositionAsOf")); assertNull(AbstractRunningStrategy.getProperty("currencyPositionAsOfDuringStop")); } /** * Executes one iteration of the <code>getAllCurrencyPositionsAsOf</code> test. * * @param inDate a <code>Date</code> value * @param inExpectedPositions a <code>Map<PositionKey<Currency>,BigDecimal></code> value * @throws Exception if an unexpected error occurs */ private void doAllCurrencyPositionsAsOfTest(Date inDate, Map<PositionKey<Currency>,BigDecimal> inExpectedPositions) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("allCurrencyPositionsAsOfDuringStop", "not-empty"); if(inDate != null) { AbstractRunningStrategy.setProperty("date", Long.toString(inDate.getTime())); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedPositions == null ? null : inExpectedPositions.toString()), AbstractRunningStrategy.getProperty("allCurrencyPositionsAsOf")); assertNull(AbstractRunningStrategy.getProperty("allCurrencyPositionsAsOfDuringStop")); } /** * Executes one iteration of the <code>getAllPositionsAsOf</code> test. * * @param inDate a <code>Date</code> value * @param inExpectedPositions a <code>Map<PositionKey<Equity>,BigDecimal></code> value * @throws Exception if an unexpected error occurs */ private void doAllPositionsAsOfTest(Date inDate, Map<PositionKey<Equity>,BigDecimal> inExpectedPositions) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("allPositionsAsOfDuringStop", "not-empty"); if(inDate != null) { AbstractRunningStrategy.setProperty("date", Long.toString(inDate.getTime())); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedPositions == null ? null : inExpectedPositions.toString()), AbstractRunningStrategy.getProperty("allPositionsAsOf")); assertNull(AbstractRunningStrategy.getProperty("allPositionsAsOfDuringStop")); } /** * Executes a single iteration of the <code>getOptionPositionAsOf</code> test. * * @param inOptionRoot a <code>String</code> value * @param inExpiry a <code>String</code> value * @param inStrikePrice a <code>BigDecimal</code> value * @param inOptionType an <code>OptionType</code> value * @param inDate a <code>Date</code> value * @param inExpectedPosition a <code>BigDecimal</code> value * @throws Exception if an unexpected error occurs */ private void doOptionPositionAsOfTest(String inOptionRoot, String inExpiry, BigDecimal inStrikePrice, OptionType inOptionType, Date inDate, BigDecimal inExpectedPosition) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("optionPositionAsOfDuringStop", "not-empty"); if(inOptionRoot != null) { AbstractRunningStrategy.setProperty("optionRoot", inOptionRoot); } if(inExpiry != null) { AbstractRunningStrategy.setProperty("expiry", inExpiry); } if(inStrikePrice != null) { AbstractRunningStrategy.setProperty("strikePrice", inStrikePrice.toPlainString()); } if(inOptionType != null) { AbstractRunningStrategy.setProperty("optionType", inOptionType.toString()); } if(inDate != null) { AbstractRunningStrategy.setProperty("date", Long.toString(inDate.getTime())); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedPosition == null ? null : inExpectedPosition.toString()), AbstractRunningStrategy.getProperty("optionPositionAsOf")); assertNull(AbstractRunningStrategy.getProperty("optionPositionAsOfDuringStop")); } /** * Executes one iteration of the <code>getAllOptionPositionsAsOf</code> test. * * @param inDate a <code>Date</code> value * @param inExpectedPositions a <code>Map<PositionKey<Option>,BigDecimal></code> value * @throws Exception if an unexpected error occurs */ private void doAllOptionPositionsAsOfTest(Date inDate, Map<PositionKey<Option>,BigDecimal> inExpectedPositions) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("allOptionPositionsAsOfDuringStop", "not-empty"); if(inDate != null) { AbstractRunningStrategy.setProperty("date", Long.toString(inDate.getTime())); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedPositions == null ? null : inExpectedPositions.toString()), AbstractRunningStrategy.getProperty("allOptionPositionsAsOf")); assertNull(AbstractRunningStrategy.getProperty("allOptionPositionsAsOfDuringStop")); } /** * Executes one iteration of the <code>getOptionPositionsAsOf</code> test. * * @param inOptionRoots a <code>String[]</code> value * @param inDate a <code>Date</code> value * @param inParameters a <code>Properties</code> value to use as parameters if non-null * @param inExpectedPositions a <code>Map<PositionKey<Option>,BigDecimal></code> value * @throws Exception if an unexpected error occurs */ private void doOptionPositionsAsOfTest(String[] inOptionRoots, Date inDate, Properties inParameters, Map<PositionKey<Option>,BigDecimal> inExpectedPositions) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("optionPositionsAsOfDuringStop", "not-empty"); if(inOptionRoots != null && inOptionRoots.length > 0) { StringBuilder builder = new StringBuilder(); for(String optionRoot : inOptionRoots) { builder.append(optionRoot).append(','); } AbstractRunningStrategy.setProperty("optionRoots", builder.toString()); } if(inDate != null) { AbstractRunningStrategy.setProperty("date", Long.toString(inDate.getTime())); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), inParameters, null, null); // verify expected results assertEquals((inExpectedPositions == null ? null : inExpectedPositions.toString()), AbstractRunningStrategy.getProperty("optionPositionsAsOf")); assertNull(AbstractRunningStrategy.getProperty("optionPositionsAsOfDuringStop")); } /** * Executes one iteration of the <code>getUnderlying</code> test. * * @param inOptionRoot a <code>String</code> value * @param inExpectedUnderlyingSymbol a <code>String</code> value * @throws Exception if an unexpected error occurs */ private void doUnderlyingTest(String inOptionRoot, String inExpectedUnderlyingSymbol) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("underlyingDuringStop", "not-empty"); if(inOptionRoot != null) { AbstractRunningStrategy.setProperty("optionRoot", inOptionRoot); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedUnderlyingSymbol == null ? null : inExpectedUnderlyingSymbol), AbstractRunningStrategy.getProperty("underlying")); assertNull(AbstractRunningStrategy.getProperty("underlyingDuringStop")); } /** * Executes one iteration of the <code>getOptionRoots</code> test. * * @param inUnderlyingSymbol a <code>String</code> value * @param inExpectedOptionRoots a <code>Collection<String></code> value * @throws Exception if an unexpected error occurs */ private void doOptionRootsTest(String inUnderlyingSymbol, Collection<String> inExpectedOptionRoots) throws Exception { StrategyCoordinates strategy = getPositionsStrategy(); setPropertiesToNull(); AbstractRunningStrategy.setProperty("optionRootsDuringStop", "not-empty"); if(inUnderlyingSymbol != null) { AbstractRunningStrategy.setProperty("underlyingSymbol", inUnderlyingSymbol); } verifyStrategyStartsAndStops(strategy.getName(), getLanguage(), strategy.getFile(), null, null, null); // verify expected results assertEquals((inExpectedOptionRoots == null ? null : inExpectedOptionRoots.toString()), AbstractRunningStrategy.getProperty("optionRoots")); assertNull(AbstractRunningStrategy.getProperty("optionRootsDuringStop")); } /** * Executes the given block asynchronously. * * @param inBlock a <code>Callable<T></code> value * @return a <code>Future<T></code> value * @throws InterruptedException if an error occurs * @throws ExecutionException if an error occurs */ private <T> Future<T> doAsynchronous(Callable<T> inBlock) throws InterruptedException, ExecutionException { return executor.submit(inBlock); } /** * used for asynchronous test blocks */ private final ExecutorService executor = Executors.newCachedThreadPool(new NamedThreadFactory("LanguageTestBase")); //$NON-NLS-1$ /** * Indicates that a <code>JUnit</code> test is designated as a performance test instead of a unit test. * * <p>As this annotation becomes more widely used, an appropriate home can be chosen for it. In the * long run, <code>LanguageTestBase</code> is not the right owner. * * @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a> * @version $Id: LanguageTestBase.java 16864 2014-03-20 19:39:48Z colin $ * @since 1.0.0 */ public @interface PerformanceTest { boolean value() default true; } }