com.opengamma.strata.loader.csv.RatesCurveGroupDefinitionCsvLoader Maven / Gradle / Ivy
Show all versions of strata-loader Show documentation
/*
* Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.loader.csv;
import static com.opengamma.strata.collect.Guavate.toImmutableList;
import static java.util.stream.Collectors.groupingBy;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.CharSource;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.index.Index;
import com.opengamma.strata.collect.MapStream;
import com.opengamma.strata.collect.io.CharSources;
import com.opengamma.strata.collect.io.CsvFile;
import com.opengamma.strata.collect.io.CsvOutput;
import com.opengamma.strata.collect.io.CsvRow;
import com.opengamma.strata.collect.io.ResourceLocator;
import com.opengamma.strata.collect.io.UnicodeBom;
import com.opengamma.strata.collect.result.ParseFailureException;
import com.opengamma.strata.loader.LoaderUtils;
import com.opengamma.strata.market.curve.Curve;
import com.opengamma.strata.market.curve.CurveGroupName;
import com.opengamma.strata.market.curve.CurveName;
import com.opengamma.strata.market.curve.NodalCurveDefinition;
import com.opengamma.strata.market.curve.RatesCurveGroup;
import com.opengamma.strata.market.curve.RatesCurveGroupDefinition;
import com.opengamma.strata.market.curve.RatesCurveGroupEntry;
/**
* Loads a set of curve group definitions into memory by reading from CSV resources.
*
* The CSV file has the following header row:
* {@code Group Name, Curve Type, Reference, Curve Name}.
*
*
* - The 'Group Name' column is the name of the group of curves.
*
- The 'Curve Type' column is the type of the curve, "forward" or "discount".
*
- The 'Reference' column is the reference the curve is used for, such as "USD" or "USD-LIBOR-3M".
*
- The 'Curve Name' column is the name of the curve.
*
*
* CSV files sometimes contain a Unicode Byte Order Mark.
* Callers are responsible for handling this, such as by using {@link UnicodeBom}.
*
* @see RatesCurveGroupDefinition
*/
public final class RatesCurveGroupDefinitionCsvLoader {
// Column headers
private static final String GROUPS_NAME = "Group Name";
private static final String GROUPS_CURVE_TYPE = "Curve Type";
private static final String GROUPS_REFERENCE = "Reference";
private static final String GROUPS_CURVE_NAME = "Curve Name";
private static final ImmutableList HEADERS = ImmutableList.of(
GROUPS_NAME, GROUPS_CURVE_TYPE, GROUPS_REFERENCE, GROUPS_CURVE_NAME);
/** Name used in the reference column of the CSV file for discount curves. */
private static final String DISCOUNT = "discount";
/** Name used in the reference column of the CSV file for forward curves. */
private static final String FORWARD = "forward";
//-------------------------------------------------------------------------
/**
* Loads the curve groups definition CSV file.
*
* The list of {@link NodalCurveDefinition} will be empty in the resulting definition.
*
* @param groupsResource the curve groups CSV resource
* @return the list of definitions
*/
public static List loadCurveGroupDefinitions(ResourceLocator groupsResource) {
return parseCurveGroupDefinitions(groupsResource.getCharSource());
}
//-------------------------------------------------------------------------
/**
* Parses the curve groups definition CSV file.
*
* The list of {@link NodalCurveDefinition} will be empty in the resulting definition.
*
* @param charSource the curve groups CSV character source
* @return the list of definitions
*/
public static List parseCurveGroupDefinitions(CharSource charSource) {
try {
Map> curveGroups = new LinkedHashMap<>();
CsvFile csv = CsvFile.of(charSource, true);
for (CsvRow row : csv.rows()) {
String curveGroupStr = row.getField(GROUPS_NAME);
String curveTypeStr = row.getField(GROUPS_CURVE_TYPE);
String referenceStr = row.getField(GROUPS_REFERENCE);
String curveNameStr = row.getField(GROUPS_CURVE_NAME);
GroupAndReference gar = createKey(CurveGroupName.of(curveGroupStr), curveTypeStr, referenceStr);
CurveName curveName = CurveName.of(curveNameStr);
curveGroups.computeIfAbsent(curveName, k -> new LinkedHashSet<>()).add(gar);
}
return buildCurveGroups(curveGroups);
} catch (RuntimeException ex) {
throw new ParseFailureException(
ex,
"Error parsing groups CSV file '{fileName}': {exceptionMessage}",
CharSources.extractFileName(charSource),
ex.getMessage());
}
}
//-------------------------------------------------------------------------
// parses the identifier
private static GroupAndReference createKey(
CurveGroupName curveGroup,
String curveTypeStr,
String referenceStr) {
// discount and forward curves are supported
if (FORWARD.equalsIgnoreCase(curveTypeStr.toLowerCase(Locale.ENGLISH))) {
Index index = LoaderUtils.findIndex(referenceStr);
return new GroupAndReference(curveGroup, index);
} else if (DISCOUNT.equalsIgnoreCase(curveTypeStr.toLowerCase(Locale.ENGLISH))) {
Currency ccy = Currency.of(referenceStr);
return new GroupAndReference(curveGroup, ccy);
} else {
throw new ParseFailureException("Unsupported curve type '{type}'", curveTypeStr);
}
}
/**
* Builds a list of curve group definitions from the map of curves and their keys.
*
* The keys specify which curve groups each curve belongs to and how it is used in the group, for example
* as a discount curve for a particular currency or as a forward curve for an index.
*
* @param garMap the map of name to keys
* @return a map of curve group name to curve group definition built from the curves
*/
private static ImmutableList buildCurveGroups(
Map> garMap) {
Multimap groups = LinkedHashMultimap.create();
for (Map.Entry> entry : garMap.entrySet()) {
CurveName curveName = entry.getKey();
Set curveIds = entry.getValue();
Map> idsByGroup =
curveIds.stream().collect(groupingBy(p -> p.groupName));
for (Map.Entry> groupEntry : idsByGroup.entrySet()) {
CurveGroupName groupName = groupEntry.getKey();
List gars = groupEntry.getValue();
groups.put(groupName, curveGroupEntry(curveName, gars));
}
}
return MapStream.of(groups.asMap())
.map((name, entry) -> RatesCurveGroupDefinition.of(name, entry, ImmutableList.of()))
.collect(toImmutableList());
}
/**
* Creates a curve group entry for a curve from a list of keys from the same curve group.
*
* @param curveName the name of the curve
* @param gars the group-reference pairs
* @return a curve group entry built from the data in the IDs
*/
private static RatesCurveGroupEntry curveGroupEntry(CurveName curveName, List gars) {
Set currencies = new LinkedHashSet<>();
Set indices = new LinkedHashSet<>();
for (GroupAndReference gar : gars) {
if (gar.currency != null) {
currencies.add(gar.currency);
} else {
indices.add(gar.index);
}
}
return RatesCurveGroupEntry.builder()
.curveName(curveName)
.discountCurrencies(currencies)
.indices(indices)
.build();
}
//-------------------------------------------------------------------------
/**
* Writes the curve groups definition in a CSV format to a file.
*
* @param file the destination for the CSV, such as a file
* @param groups the curve groups
*/
public static void writeCurveGroupDefinition(File file, RatesCurveGroupDefinition... groups) {
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
writeCurveGroupDefinition(writer, groups);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
/**
* Writes the curve groups definition in a CSV format to an appendable.
*
* @param underlying the underlying appendable destination
* @param groups the curve groups
*/
public static void writeCurveGroupDefinition(Appendable underlying, RatesCurveGroupDefinition... groups) {
CsvOutput csv = CsvOutput.standard(underlying);
csv.writeLine(HEADERS);
for (RatesCurveGroupDefinition group : groups) {
writeCurveGroupDefinition(csv, group);
}
}
// write a single group definition to CSV
private static void writeCurveGroupDefinition(CsvOutput csv, RatesCurveGroupDefinition group) {
String groupName = group.getName().getName();
for (RatesCurveGroupEntry entry : group.getEntries()) {
for (Currency currency : entry.getDiscountCurrencies()) {
csv.writeLine(
ImmutableList.of(groupName, DISCOUNT, currency.toString(), entry.getCurveName().getName()));
}
for (Index index : entry.getIndices()) {
csv.writeLine(
ImmutableList.of(groupName, FORWARD, index.toString(), entry.getCurveName().getName()));
}
}
}
//-------------------------------------------------------------------------
/**
* Writes the curve group in a CSV format to a file.
*
* @param file the file
* @param groups the curve groups
*/
public static void writeCurveGroup(File file, RatesCurveGroup... groups) {
try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8)) {
writeCurveGroup(writer, groups);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
/**
* Writes the curve group in a CSV format to an appendable.
*
* @param underlying the underlying appendable destination
* @param groups the curve groups
*/
public static void writeCurveGroup(Appendable underlying, RatesCurveGroup... groups) {
CsvOutput csv = CsvOutput.standard(underlying);
csv.writeLine(HEADERS);
for (RatesCurveGroup group : groups) {
writeCurveGroup(csv, group);
}
}
// write a single group to CSV
private static void writeCurveGroup(CsvOutput csv, RatesCurveGroup group) {
String groupName = group.getName().getName();
Map discountingCurves = group.getDiscountCurves();
for (Entry entry : discountingCurves.entrySet()) {
List line = new ArrayList<>(4);
line.add(groupName);
line.add(DISCOUNT);
line.add(entry.getKey().toString());
line.add(entry.getValue().getName().getName());
csv.writeLine(line);
}
Map forwardCurves = group.getForwardCurves();
for (Entry entry : forwardCurves.entrySet()) {
List line = new ArrayList<>(4);
line.add(groupName);
line.add(FORWARD);
line.add(entry.getKey().toString());
line.add(entry.getValue().getName().getName());
csv.writeLine(line);
}
}
//-------------------------------------------------------------------------
// This class only has static methods
private RatesCurveGroupDefinitionCsvLoader() {
}
//-------------------------------------------------------------------------
// data holder
private static final class GroupAndReference {
private final CurveGroupName groupName;
private final Currency currency;
private final Index index;
private GroupAndReference(CurveGroupName groupName, Currency currency) {
this.groupName = groupName;
this.currency = currency;
this.index = null;
}
private GroupAndReference(CurveGroupName groupName, Index index) {
this.groupName = groupName;
this.currency = null;
this.index = index;
}
}
}