/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.integration.tool.marketdata;
import static org.threeten.bp.temporal.ChronoField.DAY_OF_MONTH;
import static org.threeten.bp.temporal.ChronoField.HOUR_OF_DAY;
import static org.threeten.bp.temporal.ChronoField.MINUTE_OF_HOUR;
import static org.threeten.bp.temporal.ChronoField.MONTH_OF_YEAR;
import static org.threeten.bp.temporal.ChronoField.SECOND_OF_MINUTE;
import static org.threeten.bp.temporal.ChronoField.YEAR;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.LocalDate;
import org.threeten.bp.OffsetDateTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.DateTimeFormatterBuilder;
import org.threeten.bp.format.SignStyle;
import com.opengamma.core.marketdatasnapshot.ValueSnapshot;
import com.opengamma.financial.analytics.volatility.surface.BloombergFXOptionVolatilitySurfaceInstrumentProvider;
import com.opengamma.integration.copier.snapshot.SnapshotColumns;
import com.opengamma.integration.tool.marketdata.SnapshotUtils.VersionInfo;
import com.opengamma.util.time.Tenor;
import com.opengamma.util.tuple.ObjectsPair;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Utility methods for the MarketDataSnapshot Import/Export tools
*/
public class MarketDataSnapshotToolUtils {
private static final String VERSION_FROM = "Version From";
private static final String VERSION_TO = "Version To";
private static final String CORRECTION_FROM = "Correction From";
private static final String CORRECTION_TO = "Correction To";
private static final String UNIQUE_ID = "UniqueId";
private static final String NOT_SPECIFIED = "Not Specified";
/** Snapshot listing option flag */
private static final String SNAPSHOT_LIST_OPTION = "s";
/** Snapshot query option flag */
private static final String SNAPSHOT_QUERY_OPTION = "q";
/** Snapshot version list option flag */
private static final String SNAPSHOT_VERSION_LIST_OPTION = "v";
private static final Logger s_logger = LoggerFactory.getLogger(MarketDataSnapshotToolUtils.class);
public static Option createSnapshotListOption() {
final Option option = new Option(SNAPSHOT_LIST_OPTION, "snapshot-list", false, "List the snapshots available");
return option;
}
public static Option createSnapshotQueryOption() {
final Option option = new Option(SNAPSHOT_QUERY_OPTION, "snapshot-query", true, "List the snapshots available according to a glob");
option.setArgName("snapshot name glob");
return option;
}
public static Option createSnapshotVersionListOption() {
final Option option = new Option(SNAPSHOT_VERSION_LIST_OPTION, "snapshot-versions", true, "List the versions available for a named snapshot");
option.setArgName("snapshot name");
return option;
}
public static boolean handleQueryOptions(SnapshotUtils snapshotUtils, CommandLine commandLine) {
if (commandLine.hasOption(SNAPSHOT_LIST_OPTION)) {
printSnapshotList(snapshotUtils);
return true;
} else if (commandLine.hasOption(SNAPSHOT_QUERY_OPTION)) {
printSnapshotQuery(snapshotUtils, commandLine.getOptionValue(SNAPSHOT_QUERY_OPTION));
return true;
} else if (commandLine.hasOption(SNAPSHOT_VERSION_LIST_OPTION)) {
printVersionListQuery(snapshotUtils, commandLine.getOptionValue(SNAPSHOT_VERSION_LIST_OPTION));
return true;
} else {
return false;
}
}
private static void printSnapshotQuery(SnapshotUtils snapshotUtils, String query) {
List<String> snapshotsByGlob = snapshotUtils.snapshotByGlob(query);
for (String info : snapshotsByGlob) {
System.out.println(info);
}
}
private static void printSnapshotList(SnapshotUtils snapshotUtils) {
List<String> allSnapshots = snapshotUtils.allSnapshots();
for (String info : allSnapshots) {
System.out.println(info);
}
}
private static void printVersionListQuery(SnapshotUtils snapshotUtils, String optionValue) {
DateTimeFormatter dateTimeFormatter = new DateTimeFormatterBuilder()
.appendValue(YEAR, 4, 10, SignStyle.EXCEEDS_PAD)
.appendLiteral('-')
.appendValue(MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(DAY_OF_MONTH, 2)
.appendValue(HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR, 2)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE, 2)
.appendOffsetId()
.toFormatter();
List<VersionInfo> snapshotVersions = snapshotUtils.snapshotVersionsByName(optionValue);
System.out.println(OffsetDateTime.now().toString(dateTimeFormatter));
int fieldWidth = OffsetDateTime.now().toString(dateTimeFormatter).length(); // Assumes all offset date times have same width
header(fieldWidth);
String id = TimeZone.getDefault().getID();
for (VersionInfo versionInfo : snapshotVersions) {
OffsetDateTime versionFrom = versionInfo.getVersionFrom() != null ? OffsetDateTime.ofInstant(versionInfo.getVersionFrom(), ZoneId.of(id)) : null;
OffsetDateTime versionTo = versionInfo.getVersionTo() != null ? OffsetDateTime.ofInstant(versionInfo.getVersionTo(), ZoneId.of(id)) : null;
OffsetDateTime correctionFrom = versionInfo.getCorrectionFrom() != null ? OffsetDateTime.ofInstant(versionInfo.getCorrectionFrom(), ZoneId.of(id)) : null;
OffsetDateTime correctionTo = versionInfo.getCorrectionTo() != null ? OffsetDateTime.ofInstant(versionInfo.getCorrectionTo(), ZoneId.of(id)) : null;
if (versionFrom != null) {
System.out.print(versionFrom.toString(dateTimeFormatter));
} else {
notSpecified(fieldWidth);
}
spaces();
if (versionTo != null) {
System.out.print(versionTo.toString(dateTimeFormatter));
} else {
notSpecified(fieldWidth);
}
spaces();
if (correctionFrom != null) {
System.out.print(correctionFrom.toString(dateTimeFormatter));
} else {
notSpecified(fieldWidth);
}
spaces();
if (correctionTo != null) {
System.out.print(correctionTo.toString(dateTimeFormatter));
} else {
notSpecified(fieldWidth);
}
spaces();
System.out.println(versionInfo.getUniqueId());
}
}
private static void header(int fieldWidth) {
System.out.print(VERSION_FROM);
pad(fieldWidth - VERSION_FROM.length());
spaces();
System.out.print(VERSION_TO);
pad(fieldWidth - VERSION_TO.length());
spaces();
System.out.print(CORRECTION_FROM);
pad(fieldWidth - CORRECTION_FROM.length());
spaces();
System.out.print(CORRECTION_TO);
pad(fieldWidth - CORRECTION_TO.length());
spaces();
System.out.println(UNIQUE_ID);
}
private static void spaces() {
System.out.print(" ");
}
private static void notSpecified(int fieldWidth) {
System.out.print(NOT_SPECIFIED);
pad(fieldWidth - NOT_SPECIFIED.length());
}
private static void pad(int n) {
String repeat = org.apache.commons.lang.StringUtils.repeat(" ", n);
System.out.print(repeat);
}
public static ValueSnapshot createValueSnapshot(String market, String override) {
Object marketValue = null;
Object overrideValue = null;
// marketValue can only be Double, LocalDate, empty or (FudgeMsg which is special cased for Market_All)
if (market != null && !market.isEmpty()) {
if (NumberUtils.isNumber(market)) {
marketValue = NumberUtils.createDouble(market);
} else {
try {
marketValue = LocalDate.parse(market);
} catch (IllegalArgumentException e) {
s_logger.error("Market value {} should be a Double, LocalDate or empty.", market);
}
}
}
//overrideValue can only be Double, LocalDate or empty
if (override != null && !override.isEmpty()) {
if (NumberUtils.isNumber(override)) {
overrideValue = NumberUtils.createDouble(override);
} else {
try {
overrideValue = LocalDate.parse(override);
} catch (IllegalArgumentException e) {
s_logger.error("Override value {} should be a Double, LocalDate or empty.", override);
}
}
}
return ValueSnapshot.of(marketValue, overrideValue);
}
private static Boolean isTenor(String tenor) {
try {
Tenor.parse(tenor);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
public static Pair<Object, Object> createOrdinatePair(String xValue, String yValue) {
String[] yValues = yValue.split("\\|");
Object surfaceX = null;
Object surfaceY = null;
if (xValue != null) {
if (NumberUtils.isNumber(xValue)) {
surfaceX = NumberUtils.createDouble(xValue);
} else if (isTenor(xValue)) {
surfaceX = Tenor.parse(xValue);
} else {
s_logger.error("Volatility surface X ordinate {} should be a Double, Tenor or empty.", xValue);
}
}
if (yValues != null) {
if (yValues.length > 1) {
try {
surfaceY = createYOrdinatePair(yValues);
} catch (IllegalArgumentException e) {
s_logger.error("Volatility surface Y ordinate {} should be a Double, Pair<Number, FXVolQuoteType> or empty.", xValue);
}
} else if (yValues.length == 1) {
if (NumberUtils.isNumber(yValues[0])) {
surfaceY = NumberUtils.createDouble(yValues[0]);
} else if (isTenor(yValues[0])) {
surfaceY = Tenor.parse(yValues[0]);
}
}
}
return Pairs.of(surfaceX, surfaceY);
}
// Bloomberg FX option volatility surface codes given a tenor, quote type (ATM, butterfly, risk reversal) and distance from ATM.
private static Pair<Number, BloombergFXOptionVolatilitySurfaceInstrumentProvider.FXVolQuoteType> createYOrdinatePair(String[] yPair) {
Number firstElement = null;
BloombergFXOptionVolatilitySurfaceInstrumentProvider.FXVolQuoteType secondElement = null;
if (NumberUtils.isNumber(yPair[0])) {
firstElement = NumberUtils.createDouble(yPair[0]);
}
switch (yPair[1]) {
case "ATM":
secondElement = BloombergFXOptionVolatilitySurfaceInstrumentProvider.FXVolQuoteType.ATM;
break;
case "RISK_REVERSAL":
secondElement = BloombergFXOptionVolatilitySurfaceInstrumentProvider.FXVolQuoteType.RISK_REVERSAL;
break;
case "BUTTERFLY":
secondElement = BloombergFXOptionVolatilitySurfaceInstrumentProvider.FXVolQuoteType.BUTTERFLY;
break;
}
return Pairs.of(firstElement, secondElement);
}
public static Pair<String, String> ordinalsAsString(Pair<Object, Object> rawOrdinates) {
String surfaceX;
if (rawOrdinates.getFirst() instanceof Tenor) {
surfaceX = ((Tenor) rawOrdinates.getFirst()).toFormattedString();
} else {
surfaceX = rawOrdinates.getFirst().toString();
}
String surfaceY;
if (rawOrdinates.getSecond() instanceof Pair) {
surfaceY = ((Pair) rawOrdinates.getSecond()).getFirst() + "|" + ((Pair) rawOrdinates.getSecond()).getSecond();
} else if (rawOrdinates.getSecond() instanceof Tenor) {
surfaceY = ((Tenor) rawOrdinates.getSecond()).toFormattedString();
} else {
surfaceY = rawOrdinates.getSecond().toString();
}
return ObjectsPair.of(surfaceX, surfaceY);
}
}