/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.integration.copier.snapshot.reader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.math.NumberUtils;
import org.fudgemsg.FudgeContext;
import org.fudgemsg.MutableFudgeMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;
import org.threeten.bp.LocalDate;
import org.threeten.bp.format.DateTimeParseException;
import com.opengamma.core.marketdatasnapshot.CurveKey;
import com.opengamma.core.marketdatasnapshot.CurveSnapshot;
import com.opengamma.core.marketdatasnapshot.UnstructuredMarketDataSnapshot;
import com.opengamma.core.marketdatasnapshot.ValueSnapshot;
import com.opengamma.core.marketdatasnapshot.VolatilitySurfaceKey;
import com.opengamma.core.marketdatasnapshot.VolatilitySurfaceSnapshot;
import com.opengamma.core.marketdatasnapshot.YieldCurveKey;
import com.opengamma.core.marketdatasnapshot.YieldCurveSnapshot;
import com.opengamma.core.marketdatasnapshot.impl.ManageableCurveSnapshot;
import com.opengamma.core.marketdatasnapshot.impl.ManageableUnstructuredMarketDataSnapshot;
import com.opengamma.core.marketdatasnapshot.impl.ManageableVolatilitySurfaceSnapshot;
import com.opengamma.core.marketdatasnapshot.impl.ManageableYieldCurveSnapshot;
import com.opengamma.financial.analytics.volatility.surface.BloombergFXOptionVolatilitySurfaceInstrumentProvider;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.id.UniqueId;
import com.opengamma.integration.copier.sheet.reader.CsvSheetReader;
import com.opengamma.integration.copier.snapshot.SnapshotColumns;
import com.opengamma.integration.copier.snapshot.SnapshotType;
import com.opengamma.integration.tool.marketdata.MarketDataSnapshotToolUtils;
import com.opengamma.util.fudgemsg.OpenGammaFudgeContext;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.Tenor;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Reads a snapshot from an imported file
*/
public class CsvSnapshotReader implements SnapshotReader {
private static final Logger s_logger = LoggerFactory.getLogger(CsvSnapshotReader.class);
private CsvSheetReader _sheetReader;
private Map<CurveKey, CurveSnapshot> _curves;
private UnstructuredMarketDataSnapshot _global;
private Map<VolatilitySurfaceKey, VolatilitySurfaceSnapshot> _surface;
private Map<YieldCurveKey, YieldCurveSnapshot> _yieldCurve;
private String _name;
private String _basisName;
private static final String MARKET_ALL = "market_all";
private final FudgeContext _fudgeContext = OpenGammaFudgeContext.getInstance();
public CsvSnapshotReader(String filename) {
_sheetReader = new CsvSheetReader(filename);
iterateSheetRows();
}
private void iterateSheetRows() {
_curves = new HashMap<>();
_surface = new HashMap<>();
_yieldCurve = new HashMap<>();
//Temporary maps for data structures
HashMap<String, ManageableCurveSnapshot> curveBuilder = new HashMap<>();
HashMap<String, Pair<YieldCurveKey, ManageableYieldCurveSnapshot>> yieldCurveBuilder = new HashMap<>();
HashMap<String, Pair<VolatilitySurfaceKey, ManageableVolatilitySurfaceSnapshot>> surfaceBuilder = new HashMap<>();
ManageableUnstructuredMarketDataSnapshot globalBuilder = new ManageableUnstructuredMarketDataSnapshot();
while (true) {
Map<String, String> currentRow = _sheetReader.loadNextRow();
// When rows are complete create snapshot elements from temporary structures
if (currentRow == null) {
for (Map.Entry<String, ManageableCurveSnapshot> entry : curveBuilder.entrySet()) {
_curves.put(CurveKey.of(entry.getKey()), entry.getValue());
}
for (Map.Entry<String, Pair<YieldCurveKey, ManageableYieldCurveSnapshot>> entry : yieldCurveBuilder.entrySet()) {
_yieldCurve.put(entry.getValue().getFirst(), entry.getValue().getSecond());
}
for (Map.Entry<String, Pair<VolatilitySurfaceKey, ManageableVolatilitySurfaceSnapshot>> entry : surfaceBuilder.entrySet()) {
_surface.put(entry.getValue().getFirst(), entry.getValue().getSecond());
}
_global = globalBuilder;
return;
}
String type = currentRow.get(SnapshotColumns.TYPE.get());
SnapshotType snapshotType = SnapshotType.from(type);
if (snapshotType != null) {
switch (snapshotType) {
case NAME:
_name = currentRow.get(SnapshotColumns.NAME.get());
break;
case BASIS_NAME:
_basisName = currentRow.get(SnapshotColumns.NAME.get());
break;
case CURVE:
buildCurves(curveBuilder, currentRow);
break;
case YIELD_CURVE:
buildYieldCurves(yieldCurveBuilder, currentRow);
break;
case GLOBAL_VALUES:
buildMarketDataSnapshot(globalBuilder, currentRow);
break;
case VOL_SURFACE:
buildSurface(surfaceBuilder, currentRow);
break;
}
} else {
s_logger.error("Unknown snapshot element of type {}", type);
}
}
}
/**
* Utility method to collect Market_All data, stored as the MarketValue of the
* ManageableUnstructuredMarketDataSnapshot, either by creating a FudgeMsg or adding to current FudgeMsg
*/
private void buildMarketAll(ManageableUnstructuredMarketDataSnapshot snapshot, Map<String, String> currentRow) {
ValueSnapshot valueSnapshot = snapshot.getValue(createExternalIdBundle(currentRow),
currentRow.get(SnapshotColumns.VALUE_NAME.get()));
String valueObject = currentRow.get(SnapshotColumns.VALUE_OBJECT.get());
if (valueSnapshot == null) {
if (valueObject.equalsIgnoreCase("null")) {
snapshot.putValue(createExternalIdBundle(currentRow),
currentRow.get(SnapshotColumns.VALUE_NAME.get()),
null);
} else {
MutableFudgeMsg msg = _fudgeContext.newMessage();
msg.add(valueObject, marketAllTypeForFudgeMessage(currentRow));
snapshot.putValue(createExternalIdBundle(currentRow),
currentRow.get(SnapshotColumns.VALUE_NAME.get()),
ValueSnapshot.of(msg));
}
} else {
MutableFudgeMsg msg = (MutableFudgeMsg) valueSnapshot.getMarketValue();
msg.add(valueObject, marketAllTypeForFudgeMessage(currentRow));
}
}
private Object marketAllTypeForFudgeMessage(Map<String, String> currentRow) {
Object output = null;
String input = currentRow.get(SnapshotColumns.MARKET_VALUE.get());
if (input != null) {
if (NumberUtils.isNumber(input)) {
output = NumberUtils.createDouble(input);
} else if (isValidInstant(input)) {
output = Instant.parse(input);
} else if (isValidLocalDate(input)) {
output = LocalDate.parse(input);
} else {
output = input;
}
}
return output;
}
private Boolean isValidInstant(String input) {
try {
Instant.parse(input);
} catch (DateTimeParseException e) {
return false;
}
return true;
}
private Boolean isValidLocalDate(String input) {
try {
LocalDate.parse(input);
} catch (DateTimeParseException e) {
return false;
}
return true;
}
/**
* Utility method to collect ManageableUnstructuredMarketDataSnapshot data, used by
* GLOBAL_VALUES, YIELD_CURVE and CURVE
*/
private void buildMarketDataSnapshot(ManageableUnstructuredMarketDataSnapshot snapshot,
Map<String, String> currentRow) {
// Special case for Market_All
if (currentRow.get(SnapshotColumns.VALUE_NAME.get()).equalsIgnoreCase(MARKET_ALL)) {
buildMarketAll(snapshot, currentRow);
} else {
snapshot.putValue(createExternalIdBundle(currentRow),
currentRow.get(SnapshotColumns.VALUE_NAME.get()),
createValueSnapshot(currentRow));
}
}
private void buildSurface(HashMap<String, Pair<VolatilitySurfaceKey, ManageableVolatilitySurfaceSnapshot>> surfaceBuilder,
Map<String, String> currentRow) {
String target = currentRow.get(SnapshotColumns.SURFACE_TARGET.get());
if (!surfaceBuilder.containsKey(target)) {
ManageableVolatilitySurfaceSnapshot surface = new ManageableVolatilitySurfaceSnapshot();
VolatilitySurfaceKey key = VolatilitySurfaceKey.of(UniqueId.parse(currentRow.get(SnapshotColumns.SURFACE_TARGET.get())),
currentRow.get(SnapshotColumns.NAME.get()),
currentRow.get(SnapshotColumns.SURFACE_INSTRUMENT_TYPE.get()),
currentRow.get(SnapshotColumns.SURFACE_QUOTE_TYPE.get()),
currentRow.get(SnapshotColumns.SURFACE_QUOTE_UNITS.get()));
HashMap<Pair<Object, Object>, ValueSnapshot> values = new HashMap<>();
values.put(createOrdinatePair(currentRow), createValueSnapshot(currentRow));
surface.setValues(values);
surfaceBuilder.put(target, Pairs.of(key, surface));
} else {
surfaceBuilder.get(target).getSecond().getValues().put(createOrdinatePair(currentRow),
createValueSnapshot(currentRow));
}
}
private void buildYieldCurves(HashMap<String, Pair<YieldCurveKey, ManageableYieldCurveSnapshot>> yieldCurveBuilder,
Map<String, String> currentRow) {
String name = currentRow.get(SnapshotColumns.NAME.get());
if (!yieldCurveBuilder.containsKey(name)) {
ManageableUnstructuredMarketDataSnapshot snapshot = new ManageableUnstructuredMarketDataSnapshot();
YieldCurveKey key = YieldCurveKey.of(Currency.of(currentRow.get(SnapshotColumns.YIELD_CURVE_CURRENCY.get())),
currentRow.get(SnapshotColumns.NAME.get()));
buildMarketDataSnapshot(snapshot, currentRow);
ManageableYieldCurveSnapshot curve = ManageableYieldCurveSnapshot.of(Instant.parse(currentRow.get(SnapshotColumns.INSTANT.get())), snapshot);
yieldCurveBuilder.put(name, Pairs.of(key, curve));
} else {
ManageableUnstructuredMarketDataSnapshot existingSnapshot = yieldCurveBuilder.get(name).getSecond().getValues();
buildMarketDataSnapshot(existingSnapshot, currentRow);
}
}
private void buildCurves(HashMap<String, ManageableCurveSnapshot> curvesBuilder, Map<String, String> currentRow) {
String name = currentRow.get(SnapshotColumns.NAME.get());
if (!curvesBuilder.containsKey(name)) {
ManageableCurveSnapshot curve = new ManageableCurveSnapshot();
ManageableUnstructuredMarketDataSnapshot snapshot = new ManageableUnstructuredMarketDataSnapshot();
curve.setValuationTime(Instant.parse(currentRow.get(SnapshotColumns.INSTANT.get())));
buildMarketDataSnapshot(snapshot, currentRow);
curve.setValues(snapshot);
curvesBuilder.put(name, curve);
} else {
ManageableUnstructuredMarketDataSnapshot existingSnapshot = curvesBuilder.get(name).getValues();
buildMarketDataSnapshot(existingSnapshot, currentRow);
}
}
private Pair<Object, Object> createOrdinatePair(Map<String, String> currentRow) {
return MarketDataSnapshotToolUtils.createOrdinatePair(currentRow.get(SnapshotColumns.SURFACE_X.get()),
currentRow.get(SnapshotColumns.SURFACE_Y.get()));
}
private ValueSnapshot createValueSnapshot(Map<String, String> currentRow) {
String market = currentRow.get(SnapshotColumns.MARKET_VALUE.get());
String override = currentRow.get(SnapshotColumns.OVERRIDE_VALUE.get());
String valueObject = currentRow.get(SnapshotColumns.VALUE_OBJECT.get());
//preserve null valueSnapshots
if (valueObject != null && valueObject.equalsIgnoreCase("null")) {
return null;
}
return MarketDataSnapshotToolUtils.createValueSnapshot(market, override);
}
private ExternalIdBundle createExternalIdBundle(Map<String, String> currentRow) {
Iterable<String> iterable = Arrays.asList(currentRow.get(SnapshotColumns.ID_BUNDLE.get()).split("\\|"));
return ExternalIdBundle.parse(iterable);
}
@Override
public Map<CurveKey, CurveSnapshot> readCurves() {
return _curves;
}
@Override
public UnstructuredMarketDataSnapshot readGlobalValues() {
return _global;
}
@Override
public Map<VolatilitySurfaceKey, VolatilitySurfaceSnapshot> readVolatilitySurfaces() {
return _surface;
}
@Override
public Map<YieldCurveKey, YieldCurveSnapshot> readYieldCurves() {
return _yieldCurve;
}
@Override
public void close() {
_sheetReader.close();
}
@Override
public String getName() {
return _name;
}
@Override
public String getBasisViewName() {
return _basisName;
}
}