Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2021 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.loader.csv;

import java.util.Optional;
import java.util.Set;

import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.collect.io.CsvRow;
import com.opengamma.strata.product.Position;
import com.opengamma.strata.product.PositionInfo;
import com.opengamma.strata.product.SecurityPosition;
import com.opengamma.strata.product.etd.EtdFuturePosition;

/**
* Handles the CSV file format for ETD future trades.
*/
final class EtdFuturePositionCsvPlugin implements PositionCsvParserPlugin {

/**
* The singleton instance of the plugin.
*/
public static final EtdFuturePositionCsvPlugin INSTANCE = new EtdFuturePositionCsvPlugin();

//-------------------------------------------------------------------------
@Override
public Set<String> positionTypeNames() {
return ImmutableSet.of("FUT", "FUTURE");
}

@Override
public Optional<Position> parsePosition(
Class<?> requiredJavaType,
CsvRow row,
PositionInfo info,
PositionCsvInfoResolver resolver) {

if (requiredJavaType.isAssignableFrom(EtdFuturePosition.class)) {
return Optional.of(resolver.parseEtdFuturePosition(row, info));
}
if (requiredJavaType.isAssignableFrom(SecurityPosition.class)) {
return Optional.of(resolver.parseEtdFutureSecurityPosition(row, info));
}
return Optional.empty();
}

@Override
public String getName() {
return "EtdFuture";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2021 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.loader.csv;

import java.util.Optional;
import java.util.Set;

import com.google.common.collect.ImmutableSet;
import com.opengamma.strata.collect.io.CsvRow;
import com.opengamma.strata.product.Position;
import com.opengamma.strata.product.PositionInfo;
import com.opengamma.strata.product.SecurityPosition;
import com.opengamma.strata.product.etd.EtdOptionPosition;

/**
* Handles the CSV file format for ETD option trades.
*/
final class EtdOptionPositionCsvPlugin implements PositionCsvParserPlugin {

/**
* The singleton instance of the plugin.
*/
public static final EtdOptionPositionCsvPlugin INSTANCE = new EtdOptionPositionCsvPlugin();

//-------------------------------------------------------------------------
@Override
public Set<String> positionTypeNames() {
return ImmutableSet.of("OPT", "OPTION");
}

@Override
public Optional<Position> parsePosition(
Class<?> requiredJavaType,
CsvRow row,
PositionInfo info,
PositionCsvInfoResolver resolver) {

if (requiredJavaType.isAssignableFrom(EtdOptionPosition.class)) {
return Optional.of(resolver.parseEtdOptionPosition(row, info));
}
if (requiredJavaType.isAssignableFrom(SecurityPosition.class)) {
return Optional.of(resolver.parseEtdOptionSecurityPosition(row, info));
}
return Optional.empty();
}

@Override
public String getName() {
return "EtdOption";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,34 @@
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.CharSource;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.StandardId;
import com.opengamma.strata.basics.StandardSchemes;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.Guavate;
import com.opengamma.strata.collect.MapStream;
import com.opengamma.strata.collect.io.CsvIterator;
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.named.ExtendedEnum;
import com.opengamma.strata.collect.result.FailureItem;
import com.opengamma.strata.collect.result.FailureReason;
import com.opengamma.strata.collect.result.ValueWithFailures;
import com.opengamma.strata.product.GenericSecurityPosition;
import com.opengamma.strata.product.Position;
import com.opengamma.strata.product.PositionInfo;
import com.opengamma.strata.product.PositionInfoBuilder;
import com.opengamma.strata.product.ResolvableSecurityPosition;
import com.opengamma.strata.product.SecurityPosition;
import com.opengamma.strata.product.etd.EtdContractSpec;
import com.opengamma.strata.product.etd.EtdContractSpecId;
import com.opengamma.strata.product.etd.EtdFuturePosition;
import com.opengamma.strata.product.etd.EtdIdUtils;
import com.opengamma.strata.product.etd.EtdOptionPosition;
import com.opengamma.strata.product.etd.EtdOptionType;
import com.opengamma.strata.product.etd.EtdPosition;
import com.opengamma.strata.product.etd.EtdSettlementType;

/**
Expand Down Expand Up @@ -149,6 +148,21 @@ public final class PositionCsvLoader {
static final String NAME_FIELD = "Name";
static final String CCP_FIELD = "CCP";

/**
* The lookup of position parsers.
*/
static final ExtendedEnum<PositionCsvParserPlugin> ENUM_LOOKUP = ExtendedEnum.of(PositionCsvParserPlugin.class);
/**
* The lookup of position parsers.
*/
private static final ImmutableMap<String, PositionCsvParserPlugin> PLUGINS =
MapStream.of(PositionCsvParserPlugin.extendedEnum().lookupAllNormalized().values())
.flatMapKeys(plugin -> plugin.positionTypeNames().stream())
.toMap((a, b) -> {
System.err.println("Two plugins declare the same product type: " + a.positionTypeNames());
return a;
});

/**
* The resolver, providing additional information.
*/
Expand Down Expand Up @@ -323,75 +337,38 @@ private <T extends Position> ValueWithFailures<List<T>> parseFile(CharSource cha
}

// loads a single CSV file
@SuppressWarnings("unchecked")
private <T extends Position> ValueWithFailures<List<T>> parseFile(CsvIterator csv, Class<T> posType) {
List<T> positions = new ArrayList<>();
List<FailureItem> failures = new ArrayList<>();
int line = 2;
for (CsvRow row : csv.asIterable()) {
String typeRaw = row.findValue(TYPE_FIELD).orElse("SMART");
String typeUpper = typeRaw.toUpperCase(Locale.ENGLISH);
try {
PositionInfo info = parsePositionInfo(row);
Optional<String> typeRawOpt = row.findValue(TYPE_FIELD);
if (typeRawOpt.isPresent()) {
// type specified
String type = typeRawOpt.get().toUpperCase(Locale.ENGLISH);
switch (type.toUpperCase(Locale.ENGLISH)) {
case "SEC":
case "SECURITY":
if (posType == SecurityPosition.class || posType == ResolvableSecurityPosition.class) {
positions.add(posType.cast(resolver.parseNonEtdSecurityPosition(row, info)));
} else if (posType == GenericSecurityPosition.class || posType == Position.class) {
Position parsed = resolver.parseNonEtdPosition(row, info);
if (posType.isInstance(parsed)) {
positions.add(posType.cast(parsed));
}
}
break;
case "FUT":
case "FUTURE":
if (posType == EtdPosition.class || posType == EtdFuturePosition.class ||
posType == ResolvableSecurityPosition.class || posType == Position.class) {
positions.add(posType.cast((Position) resolver.parseEtdFuturePosition(row, info)));
} else if (posType == SecurityPosition.class) {
positions.add(posType.cast(resolver.parseEtdFutureSecurityPosition(row, info)));
}
break;
case "OPT":
case "OPTION":
if (posType == EtdPosition.class || posType == EtdOptionPosition.class ||
posType == ResolvableSecurityPosition.class || posType == Position.class) {
positions.add(posType.cast(resolver.parseEtdOptionPosition(row, info)));
} else if (posType == SecurityPosition.class) {
positions.add(posType.cast(resolver.parseEtdOptionSecurityPosition(row, info)));
}
break;
default:
failures.add(FailureItem.of(
FailureReason.PARSING,
"CSV file position type '{positionType}' is not known at line {lineNumber}",
typeRawOpt.get(),
line));
break;
}
// type specified
PositionCsvParserPlugin plugin = PLUGINS.get(typeUpper);
if (plugin != null) {
plugin.parsePosition(posType, row, info, resolver)
.filter(parsed -> posType.isInstance(parsed))
.ifPresent(parsed -> positions.add((T) parsed));
} else {
// infer type
if (posType == SecurityPosition.class) {
positions.add(posType.cast(SecurityCsvPlugin.parsePositionLightweight(row, info, resolver)));
} else {
Position position = SecurityCsvPlugin.parsePosition(row, info, resolver);
if (posType.isInstance(position)) {
positions.add(posType.cast(position));
}
}
// failed to find the type
failures.add(FailureItem.of(
FailureReason.PARSING,
"CSV position file type '{tradeType}' is not known at line {lineNumber}",
typeRaw,
row.lineNumber()));
}
} catch (RuntimeException ex) {
failures.add(FailureItem.of(
FailureReason.PARSING,
ex,
"CSV file position could not be parsed at line {lineNumber}: {exceptionMessage}",
line,
"CSV position file type '{tradeType}' could not be parsed at line {lineNumber}: {exceptionMessage}",
typeRaw,
row.lineNumber(),
ex.getMessage()));
}
line++;
}
return ValueWithFailures.of(positions, failures);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2021 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.loader.csv;

import java.util.Optional;
import java.util.Set;

import org.joda.convert.FromString;
import org.joda.convert.ToString;

import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.io.CsvRow;
import com.opengamma.strata.collect.named.ExtendedEnum;
import com.opengamma.strata.collect.named.Named;
import com.opengamma.strata.product.Position;
import com.opengamma.strata.product.PositionInfo;
import com.opengamma.strata.product.Product;

/**
* Pluggable CSV position parser.
* <p>
* Implementations of this interface parse a CSV file.
* <p>
* See {@link PositionCsvLoader} for the main entry point to parsing.
*/
public interface PositionCsvParserPlugin
extends Named {

/**
* Obtains an instance from the specified unique name.
*
* @param uniqueName the unique name
* @return the parser
* @throws IllegalArgumentException if the name is not known
*/
@FromString
public static PositionCsvParserPlugin of(String uniqueName) {
ArgChecker.notNull(uniqueName, "uniqueName");
return extendedEnum().lookup(uniqueName);
}

/**
* Gets the extended enum helper.
* <p>
* This helper allows instances of the parser to be looked up.
* It also provides the complete set of available instances.
*
* @return the extended enum helper
*/
public static ExtendedEnum<PositionCsvParserPlugin> extendedEnum() {
return PositionCsvLoader.ENUM_LOOKUP;
}

//-------------------------------------------------------------------------
/**
* Returns the upper-case product types that this plugin supports.
* <p>
* These are matched against the CSV file type column.
*
* @return the types that this plugin supports
*/
public abstract Set<String> positionTypeNames();

/**
* Parses a single CSV format position from the input.
* <p>
* This parses a single position from the CSV rows provided.
* The position may exist on multiple rows
*
* @param requiredJavaType the Java type to return
* @param row the row to parse
* @param info the position info
* @param resolver the resolver
* @return the position object, empty if choosing not to parse because the Java type does not match
* @throws RuntimeException if unable to parse
*/
public abstract Optional<Position> parsePosition(
Class<?> requiredJavaType,
CsvRow row,
PositionInfo info,
PositionCsvInfoResolver resolver);

//-------------------------------------------------------------------------
/**
* Gets the name that uniquely identifies this parser.
* <p>
* The name should typically be the name of the {@link Product} that can be parsed.
* <p>
* This name is used in serialization and can be parsed using {@link #of(String)}.
*
* @return the unique name
*/
@ToString
@Override
public abstract String getName();

}
Loading