/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.integration.marketdata; import static org.threeten.bp.temporal.ChronoUnit.DAYS; import java.io.PrintWriter; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.concurrent.Executors; import org.apache.activemq.ActiveMQConnectionFactory; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Instant; import org.threeten.bp.LocalTime; import org.threeten.bp.OffsetDateTime; import org.threeten.bp.ZoneOffset; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.opengamma.bbg.BloombergConstants; import com.opengamma.component.ComponentInfo; import com.opengamma.component.ComponentServer; import com.opengamma.component.factory.ComponentInfoAttributes; import com.opengamma.component.rest.RemoteComponentServer; import com.opengamma.core.config.impl.ConfigItem; import com.opengamma.core.id.ExternalSchemes; import com.opengamma.core.security.SecuritySource; import com.opengamma.core.security.impl.RemoteSecuritySource; import com.opengamma.engine.ComputationTargetResolver; import com.opengamma.engine.DefaultComputationTargetResolver; import com.opengamma.engine.marketdata.ExternalIdBundleResolver; import com.opengamma.engine.value.ValueSpecification; import com.opengamma.engine.view.ViewDefinition; import com.opengamma.engine.view.ViewProcessor; import com.opengamma.engine.view.client.ViewClient; import com.opengamma.engine.view.compilation.CompiledViewDefinition; import com.opengamma.engine.view.execution.ArbitraryViewCycleExecutionSequence; import com.opengamma.engine.view.execution.ExecutionFlags; import com.opengamma.engine.view.execution.ExecutionOptions; import com.opengamma.engine.view.execution.ViewCycleExecutionOptions; import com.opengamma.engine.view.execution.ViewCycleExecutionSequence; import com.opengamma.engine.view.execution.ViewExecutionOptions; import com.opengamma.engine.view.listener.AbstractViewResultListener; import com.opengamma.financial.view.rest.RemoteViewProcessor; import com.opengamma.id.ExternalId; import com.opengamma.id.ExternalIdBundle; import com.opengamma.id.ExternalScheme; import com.opengamma.id.VersionCorrection; import com.opengamma.livedata.UserPrincipal; import com.opengamma.util.jms.JmsConnector; import com.opengamma.util.jms.JmsConnectorFactoryBean; /** * Recorder for watch lists for tick recording. */ public class WatchListRecorder { private static final Logger s_logger = LoggerFactory.getLogger(WatchListRecorder.class); private static final int VALIDITY_PERIOD_DAYS = 1; private final ViewProcessor _viewProcessor; private final ExternalIdBundleResolver _lookup; private final List<String> _schemes; // in order of preference private PrintWriter _writer = new PrintWriter(System.out); public WatchListRecorder(final ViewProcessor viewProcessor, final ComputationTargetResolver targetResolver) { _viewProcessor = viewProcessor; _schemes = new ArrayList<String>(); _lookup = new ExternalIdBundleResolver(targetResolver.atVersionCorrection(VersionCorrection.LATEST)); } public void addWatchScheme(final ExternalScheme scheme) { _schemes.add(scheme.getName()); } public void setPrintWriter(final PrintWriter writer) { _writer = writer; } private void emitSpecification(final ValueSpecification specification, final Set<ExternalId> emitted, final Set<ExternalId> emittedRecently) { final ExternalIdBundle identifiers = specification.getTargetSpecification().accept(_lookup); schemeLoop: for (final String scheme : _schemes) { //CSIGNORE for (final ExternalId sid : identifiers) { if (scheme.equals(sid.getScheme().getName())) { if (emittedRecently != null) { if (emittedRecently.add(sid)) { if (!emitted.add(sid)) { _writer.print("# "); } _writer.println(sid.toString()); } } else { if (emitted.add(sid)) { _writer.println(sid.toString()); } } break schemeLoop; } } } } private void addInterestRates(final Set<ExternalId> emitted) { _writer.println("# Adding generated interest rates"); final String scheme = ExternalSchemes.BLOOMBERG_TICKER.getName(); final List<String> monthCodes = ImmutableList.of("H", "M", "U", "Z"); final List<String> securityCodes = ImmutableList.of("ED", "ER", "L", "ES", "EF"); final List<String> addSpace = ImmutableList.of("L"); if (_schemes.contains(scheme)) { for (final String securityCode : securityCodes) { for (int year = 0; year < 10; year++) { for (final String month : monthCodes) { String idValue = securityCode; if (addSpace.contains(securityCode)) { idValue += " "; } idValue += month + year + " " + BloombergConstants.MARKET_SECTOR_COMDTY; final ExternalId identifier = ExternalId.of(scheme, idValue); if (emitted.add(identifier)) { _writer.println(identifier.toString()); } } } } } } public void run() { final Collection<ConfigItem<ViewDefinition>> viewDefinitions = _viewProcessor.getConfigSource().getAll(ViewDefinition.class, VersionCorrection.LATEST); final Set<ExternalId> emitted = Sets.newHashSet(); final Set<ExternalId> emittedRecently = Sets.newHashSet(); final Instant now = OffsetDateTime.ofInstant(Instant.now(), ZoneOffset.UTC).with(LocalTime.NOON).toInstant(); s_logger.info("{} view(s) defined in demo view processor", viewDefinitions.size()); _writer.println("# Automatically generated"); final ViewClient client = _viewProcessor.createViewClient(UserPrincipal.getLocalUser()); final List<CompiledViewDefinition> compilations = new LinkedList<CompiledViewDefinition>(); client.setResultListener(new AbstractViewResultListener() { @Override public UserPrincipal getUser() { return UserPrincipal.getLocalUser(); } @Override public void viewDefinitionCompiled(final CompiledViewDefinition compiledViewDefinition, final boolean hasMarketDataPermissions) { compilations.add(compiledViewDefinition); } @Override public void viewDefinitionCompilationFailed(final Instant valuationTime, final Exception exception) { s_logger.error("Error while compiling view definition " + viewDefinitions + " for instant " + valuationTime, exception); } }); for (final ConfigItem<ViewDefinition> viewDefinition : viewDefinitions) { if (viewDefinition.getName().startsWith("10K")) { // Don't do the huge ones! s_logger.warn("Skipping {}", viewDefinition); _writer.println(); _writer.print("# Skipping "); _writer.println(viewDefinition); continue; } s_logger.debug("Compiling view {}", viewDefinition); _writer.println(); _writer.println("# " + viewDefinition); client.attachToViewProcess(viewDefinition.getUniqueId(), generateExecutionOptions(now)); try { client.waitForCompletion(); } catch (final InterruptedException e) { s_logger.warn("Interrupted while waiting for '{}' to complete" + viewDefinition); } client.detachFromViewProcess(); if (compilations.size() == 0) { _writer.println("# ERROR - Failed to compile " + viewDefinition); } else { _writer.println("# " + compilations.size() + " different compilations of " + viewDefinition + " for the next " + VALIDITY_PERIOD_DAYS + " days"); } for (int i = 0; i < compilations.size(); i++) { final CompiledViewDefinition compilation = compilations.get(i); final Set<ValueSpecification> liveData = compilation.getMarketDataRequirements(); s_logger.info("{} live data requirements for view {} for compilation {}", new Object[] {liveData.size(), viewDefinition, compilation.toString() }); _writer.println("# " + (i + 1) + " of " + compilations.size() + " - " + compilation); for (final ValueSpecification specification : liveData) { s_logger.debug("Specification {}", specification); emitSpecification(specification, emitted, emittedRecently); } _writer.flush(); emittedRecently.clear(); } compilations.clear(); } client.shutdown(); addInterestRates(emitted); } private ViewExecutionOptions generateExecutionOptions(final Instant now) { final List<ViewCycleExecutionOptions> executionOptionsList = new ArrayList<ViewCycleExecutionOptions>(); final ViewCycleExecutionOptions.Builder builder = ViewCycleExecutionOptions.builder(); for (int i = 0; i < VALIDITY_PERIOD_DAYS; i++) { final Instant valuationTime = now.plus(i, DAYS); executionOptionsList.add(builder.setValuationTime(valuationTime).create()); } final ViewCycleExecutionSequence executionSequence = new ArbitraryViewCycleExecutionSequence(executionOptionsList); return ExecutionOptions.of(executionSequence, ExecutionFlags.none().compileOnly().get()); } //------------------------------------------------------------------------- /** * Main entry point. * * @param args the arguments * @throws Exception if an error occurs */ public static void main(final String[] args) throws Exception { // CSIGNORE final CommandLineParser parser = new PosixParser(); final Options options = new Options(); final Option outputFileOpt = new Option("o", "output", true, "output file"); outputFileOpt.setRequired(true); options.addOption(outputFileOpt); final Option urlOpt = new Option("u", "url", true, "server url"); options.addOption(urlOpt); String outputFile = "watchList.txt"; String url = "http://localhost:8080/jax"; try { final CommandLine cmd = parser.parse(options, args); outputFile = cmd.getOptionValue("output"); url = cmd.getOptionValue("url"); } catch (final ParseException exp) { s_logger.error("Option parsing failed: {}", exp.getMessage()); System.exit(0); } final WatchListRecorder recorder = create(URI.create(url), "main", "combined"); recorder.addWatchScheme(ExternalSchemes.BLOOMBERG_TICKER); recorder.addWatchScheme(ExternalSchemes.BLOOMBERG_BUID); final PrintWriter pw = new PrintWriter(outputFile); recorder.setPrintWriter(pw); recorder.run(); pw.close(); System.exit(0); } private static WatchListRecorder create(final URI serverUri, final String viewProcessorClassifier, final String securitySourceClassifier) { final RemoteComponentServer remote = new RemoteComponentServer(serverUri); final ComponentServer server = remote.getComponentServer(); final ComponentInfo viewProcessorInfo = server.getComponentInfo(ViewProcessor.class, viewProcessorClassifier); final ComponentInfo securitySourceInfo = server.getComponentInfo(SecuritySource.class, securitySourceClassifier); final URI uri = URI.create(viewProcessorInfo.getAttribute(ComponentInfoAttributes.JMS_BROKER_URI)); final ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(uri); final JmsConnectorFactoryBean factory = new JmsConnectorFactoryBean(); factory.setName("WatchListRecorder"); factory.setConnectionFactory(cf); factory.setClientBrokerUri(uri); final JmsConnector jmsConnector = factory.getObjectCreating(); final ViewProcessor viewProcessor = new RemoteViewProcessor(viewProcessorInfo.getUri(), jmsConnector, Executors.newSingleThreadScheduledExecutor()); // TODO: Not ideal; the published resolver should be used rather than an ad-hoc one created based just on the security source final ComputationTargetResolver targetResolver = new DefaultComputationTargetResolver(new RemoteSecuritySource(securitySourceInfo.getUri())); return new WatchListRecorder(viewProcessor, targetResolver); } }