/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.solutions.util;
import static com.opengamma.sesame.config.ConfigBuilder.argument;
import static com.opengamma.sesame.config.ConfigBuilder.arguments;
import static com.opengamma.sesame.config.ConfigBuilder.column;
import static com.opengamma.sesame.config.ConfigBuilder.config;
import static com.opengamma.sesame.config.ConfigBuilder.configureView;
import static com.opengamma.sesame.config.ConfigBuilder.function;
import static com.opengamma.sesame.config.ConfigBuilder.implementations;
import static com.opengamma.sesame.config.ConfigBuilder.output;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalTime;
import org.threeten.bp.OffsetTime;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.ZonedDateTime;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.provider.curve.CurveBuildingBlockBundle;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.core.link.ConfigLink;
import com.opengamma.core.position.Counterparty;
import com.opengamma.core.position.impl.SimpleCounterparty;
import com.opengamma.core.position.impl.SimpleTrade;
import com.opengamma.financial.analytics.curve.exposure.CurrencyExposureFunction;
import com.opengamma.financial.analytics.curve.exposure.ExposureFunctions;
import com.opengamma.financial.security.option.EquityIndexOptionSecurity;
import com.opengamma.financial.security.option.ExerciseType;
import com.opengamma.financial.security.option.OptionType;
import com.opengamma.id.ExternalId;
import com.opengamma.sesame.CurveSelector;
import com.opengamma.sesame.CurveSelectorMulticurveBundleFn;
import com.opengamma.sesame.DefaultForwardCurveFn;
import com.opengamma.sesame.DefaultGridInterpolator2DFn;
import com.opengamma.sesame.DiscountingMulticurveCombinerFn;
import com.opengamma.sesame.ForwardCurveFn;
import com.opengamma.sesame.GridInterpolator2DFn;
import com.opengamma.sesame.MarketExposureSelector;
import com.opengamma.sesame.MulticurveBundle;
import com.opengamma.sesame.OutputNames;
import com.opengamma.sesame.config.ConfigBuilder;
import com.opengamma.sesame.config.ViewConfig;
import com.opengamma.sesame.equity.StaticReplicationDataBundleFn;
import com.opengamma.sesame.equity.StrikeDataBundleFn;
import com.opengamma.sesame.equity.StrikeDataFromPriceBundleFn;
import com.opengamma.sesame.equityindexoptions.DefaultEquityIndexOptionFn;
import com.opengamma.sesame.equityindexoptions.EquityIndexOptionFn;
import com.opengamma.sesame.marketdata.ForwardCurveId;
import com.opengamma.sesame.marketdata.MarketDataEnvironmentBuilder;
import com.opengamma.sesame.marketdata.MulticurveId;
import com.opengamma.sesame.marketdata.SurfaceId;
import com.opengamma.sesame.marketdata.VolatilitySurfaceId;
import com.opengamma.sesame.trade.EquityIndexOptionTrade;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.Expiry;
import au.com.bytecode.opencsv.CSVReader;
/**
* Utility class for Equity Index Options views
*/
public final class EquityIndexOptionViewUtils {
private EquityIndexOptionViewUtils() { /* private constructor */ }
private static final Logger s_logger = LoggerFactory.getLogger(EquityIndexOptionViewUtils.class);
/**
* Utility for creating a Equity Index Options specific view column
* @param currencies to be used in the creation of the exposure function
* @param priceSurface whether the surface is price based (true) or vol based (false)
*/
public static ViewConfig createViewConfig(Collection<String> currencies, boolean priceSurface) {
ConfigBuilder.Implementations implementations;
if (priceSurface) {
implementations = implementations(
GridInterpolator2DFn.class, DefaultGridInterpolator2DFn.class,
EquityIndexOptionFn.class, DefaultEquityIndexOptionFn.class,
StaticReplicationDataBundleFn.class, StrikeDataFromPriceBundleFn.class,
CurveSelector.class, MarketExposureSelector.class,
ForwardCurveFn.class, DefaultForwardCurveFn.class,
DiscountingMulticurveCombinerFn.class, CurveSelectorMulticurveBundleFn.class);
} else {
implementations = implementations(
EquityIndexOptionFn.class, DefaultEquityIndexOptionFn.class,
StaticReplicationDataBundleFn.class, StrikeDataBundleFn.class,
CurveSelector.class, MarketExposureSelector.class,
ForwardCurveFn.class, DefaultForwardCurveFn.class,
DiscountingMulticurveCombinerFn.class, CurveSelectorMulticurveBundleFn.class);
}
ViewConfig viewConfig = configureView(
"Equity Index Options View",
config(
arguments(
function(
MarketExposureSelector.class,
argument("exposureFunctions", ConfigLink.resolved(createExposureFunction(currencies)))),
function(
DefaultGridInterpolator2DFn.class,
argument("xInterpolatorName", "Linear"),
argument("xLeftExtrapolatorName", "FlatExtrapolator"),
argument("xRightExtrapolatorName", "FlatExtrapolator"),
argument("yInterpolatorName", "Linear"),
argument("yLeftExtrapolatorName", "FlatExtrapolator"),
argument("yRightExtrapolatorName", "FlatExtrapolator"))),
implementations),
column(OutputNames.PRESENT_VALUE, output(OutputNames.PRESENT_VALUE, EquityIndexOptionTrade.class)),
column(OutputNames.DELTA, output(OutputNames.DELTA, EquityIndexOptionTrade.class)),
column(OutputNames.GAMMA, output(OutputNames.GAMMA, EquityIndexOptionTrade.class)),
column(OutputNames.VEGA, output(OutputNames.VEGA, EquityIndexOptionTrade.class)),
column(OutputNames.PV01, output(OutputNames.PV01, EquityIndexOptionTrade.class)),
column(OutputNames.BUCKETED_PV01, output(OutputNames.BUCKETED_PV01, EquityIndexOptionTrade.class))
);
return viewConfig;
}
/**
* Create discounting curves and add to the {@link MarketDataEnvironmentBuilder}
* @param builder the MarketDataEnvironmentBuilder
* @param file name of the discounting curves file
* @throws IOException
*/
public static void parseDiscountingCurves(MarketDataEnvironmentBuilder builder, String file) throws IOException {
String bundleName = "MultiCurve";
MulticurveProviderDiscount multicurve = new MulticurveProviderDiscount();
Map<String, CurveUtils.CurveRawData> curves = CurveUtils.parseCurves(file);
for (Map.Entry<String, CurveUtils.CurveRawData> curve : curves.entrySet()) {
YieldAndDiscountCurve yieldCurve = CurveUtils.createYieldCurve(curve.getKey() + " Discounting", curve.getValue());
multicurve.setCurve(Currency.of(curve.getKey()), yieldCurve);
}
MulticurveBundle bundle = new MulticurveBundle(multicurve, new CurveBuildingBlockBundle());
builder.add(MulticurveId.of(bundleName), bundle);
}
/**
* Create volatility surfaces and add to the {@link MarketDataEnvironmentBuilder}
* @param builder the MarketDataEnvironmentBuilder
* @param file the name of the surface file
* @param priceSurface whether the surface is price based (true) or vol based (false)
* @throws IOException
*/
public static void parseSurfaces(MarketDataEnvironmentBuilder builder, String file, boolean priceSurface) throws IOException {
if (priceSurface) {
parsePriceSurfaces(builder, file);
} else {
parseVolatilitySurfaces(builder, file);
}
}
/**
* Create surfaces and add to the {@link MarketDataEnvironmentBuilder}
* @param builder the MarketDataEnvironmentBuilder
* @param file the name of the price surface file
* @throws IOException
*/
private static void parsePriceSurfaces(MarketDataEnvironmentBuilder builder, String file) throws IOException {
Map<String, VolUtils.SurfaceRawData> vols = VolUtils.parseSurface(file);
for (Map.Entry<String, VolUtils.SurfaceRawData> surface : vols.entrySet()) {
builder.add(SurfaceId.of(surface.getKey()), VolUtils.createPriceSurface(surface.getValue()));
}
}
/**
* Create surfaces and add to the {@link MarketDataEnvironmentBuilder}
* @param builder the MarketDataEnvironmentBuilder
* @param file the name of the vol surface file
* @throws IOException
*/
private static void parseVolatilitySurfaces(MarketDataEnvironmentBuilder builder, String file) throws IOException {
Map<String, VolUtils.SurfaceRawData> vols = VolUtils.parseSurface(file);
for (Map.Entry<String, VolUtils.SurfaceRawData> surface : vols.entrySet()) {
builder.add(VolatilitySurfaceId.of(surface.getKey()), VolUtils.createVolatilitySurface(surface.getValue()));
}
}
/**
* Create forward curves and add to the {@link MarketDataEnvironmentBuilder}
* @param builder the MarketDataEnvironmentBuilder
* @param file the name of the forward curves file
* @throws IOException
*/
public static void parseForwardCurves(MarketDataEnvironmentBuilder builder, String file) throws IOException {
Map<String, CurveUtils.CurveRawData> curves = CurveUtils.parseCurves(file);
for (Map.Entry<String, CurveUtils.CurveRawData> curve : curves.entrySet()) {
builder.add(ForwardCurveId.of(curve.getKey()), CurveUtils.createForwardCurve(curve.getValue()));
}
}
/**
* Parse the input portfolio
* @param file the name of the portfolio file
* @return map of trade to currency
* @throws IOException
*/
public static HashMap<Object, String> parsePortfolio(String file) throws IOException {
HashMap<Object, String> trades = new HashMap<>();
Reader curveReader = new BufferedReader(
new InputStreamReader(
new ClassPathResource(file).getInputStream()
)
);
try {
CSVReader csvReader = new CSVReader(curveReader);
String[] line;
csvReader.readNext(); // skip headers
while ((line = csvReader.readNext()) != null) {
//Security
ExternalId underlyingId = ExternalId.of("TICKER", line[0]);
OptionType optionType = OptionType.parse(line[1]);
ExerciseType exerciseType = ExerciseType.of(line[2]);
Currency currency = Currency.parse(line[3]);
double strike = Double.parseDouble(line[4]);
Expiry expiry = new Expiry(ZonedDateTime.of(LocalDate.parse(line[5]),
LocalTime.of(0, 0),
ZoneId.of("UTC")));
double pointValue = 1;
String exchange = currency.getCode();
EquityIndexOptionSecurity security = new EquityIndexOptionSecurity(optionType,
strike,
currency,
underlyingId,
exerciseType,
expiry,
pointValue,
exchange);
security.setName(underlyingId.getValue() + " " +
optionType.toString() + " Option " +
expiry.getExpiry().toLocalDate().toString() + " " + strike);
//Trade - various elements of the trade object are not used in these examples so can be hard coded
Counterparty counterparty = new SimpleCounterparty(ExternalId.of(Counterparty.DEFAULT_SCHEME, "COUNTERPARTY"));
BigDecimal tradeQuantity = BigDecimal.valueOf(1);
LocalDate tradeDate = LocalDate.now();
OffsetTime tradeTime = OffsetTime.of(LocalTime.of(0, 0), ZoneOffset.UTC);
SimpleTrade trade = new SimpleTrade(security,
tradeQuantity,
counterparty,
tradeDate,
tradeTime);
trades.put(new EquityIndexOptionTrade(trade), currency.getCode());
}
} catch (IOException e) {
s_logger.error("Failed to parse trade data ", e);
}
return trades;
}
private static ExposureFunctions createExposureFunction(Collection<String> currencies) {
List<String> exposureFunctions = ImmutableList.of(CurrencyExposureFunction.NAME);
ImmutableList<String> currencyList = ImmutableSet.copyOf(currencies).asList();
Map<ExternalId, String> idsToNames = new HashMap<>();
for (String currency : currencyList) {
idsToNames.put(ExternalId.of("CurrencyISO", currency), "MultiCurve");
}
return new ExposureFunctions("Exposure", exposureFunctions, idsToNames);
}
}