/**
* 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.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
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.Period;
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.legalentity.LegalEntity;
import com.opengamma.analytics.financial.legalentity.LegalEntityFilter;
import com.opengamma.analytics.financial.legalentity.LegalEntityShortName;
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.IssuerProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.core.id.ExternalSchemes;
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.convention.daycount.DayCount;
import com.opengamma.financial.convention.daycount.DayCountFactory;
import com.opengamma.financial.convention.frequency.Frequency;
import com.opengamma.financial.convention.frequency.PeriodFrequency;
import com.opengamma.financial.convention.yield.YieldConvention;
import com.opengamma.financial.convention.yield.YieldConventionFactory;
import com.opengamma.financial.security.bond.GovernmentBondSecurity;
import com.opengamma.financial.security.future.BondFutureDeliverable;
import com.opengamma.financial.security.future.BondFutureSecurity;
import com.opengamma.financial.security.option.BondFutureOptionSecurity;
import com.opengamma.financial.security.option.ExerciseType;
import com.opengamma.financial.security.option.OptionType;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.master.security.SecurityDocument;
import com.opengamma.master.security.SecurityMaster;
import com.opengamma.sesame.CurveSelector;
import com.opengamma.sesame.DefaultFixingsFn;
import com.opengamma.sesame.FixingsFn;
import com.opengamma.sesame.IssuerProviderBundle;
import com.opengamma.sesame.IssuerProviderFn;
import com.opengamma.sesame.LookupIssuerProviderFn;
import com.opengamma.sesame.MarketExposureSelector;
import com.opengamma.sesame.OutputNames;
import com.opengamma.sesame.bondfutureoption.BlackBondFuturesProviderFn;
import com.opengamma.sesame.bondfutureoption.BlackExpStrikeBondFuturesProviderFn;
import com.opengamma.sesame.bondfutureoption.BondFutureOptionBlackCalculatorFactory;
import com.opengamma.sesame.bondfutureoption.BondFutureOptionCalculatorFactory;
import com.opengamma.sesame.bondfutureoption.BondFutureOptionFn;
import com.opengamma.sesame.bondfutureoption.DefaultBondFutureOptionFn;
import com.opengamma.sesame.config.ViewConfig;
import com.opengamma.sesame.marketdata.DefaultHistoricalMarketDataFn;
import com.opengamma.sesame.marketdata.HistoricalMarketDataFn;
import com.opengamma.sesame.marketdata.IssuerMulticurveId;
import com.opengamma.sesame.marketdata.MarketDataEnvironmentBuilder;
import com.opengamma.sesame.marketdata.VolatilitySurfaceId;
import com.opengamma.sesame.trade.BondFutureOptionTrade;
import com.opengamma.sesame.trade.BondFutureTrade;
import com.opengamma.util.money.Currency;
import com.opengamma.util.time.Expiry;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
import au.com.bytecode.opencsv.CSVReader;
/**
* Utility class for Bond Future Options views
*/
public final class BondFutureOptionViewUtils {
private BondFutureOptionViewUtils() { /* private constructor */ }
private static final Logger s_logger = LoggerFactory.getLogger(BondFutureOptionViewUtils.class);
private static String CURVE_BUNDLE = "CurveBundle";
/**
* Utility for creating a Bond Future Options specific view column
* @param currencies
*/
public static ViewConfig createViewConfig(Collection<String> currencies) {
return
configureView(
"Bond Future Options View",
config(
arguments(
function(
MarketExposureSelector.class,
argument("exposureFunctions", ConfigLink.resolved(createExposureFunction(currencies))))),
implementations(
BlackBondFuturesProviderFn.class, BlackExpStrikeBondFuturesProviderFn.class,
BondFutureOptionFn.class, DefaultBondFutureOptionFn.class,
BondFutureOptionCalculatorFactory.class, BondFutureOptionBlackCalculatorFactory.class,
FixingsFn.class, DefaultFixingsFn.class,
IssuerProviderFn.class, LookupIssuerProviderFn.class,
CurveSelector.class, MarketExposureSelector.class,
HistoricalMarketDataFn.class, DefaultHistoricalMarketDataFn.class)),
column(OutputNames.PRESENT_VALUE, output(OutputNames.PRESENT_VALUE, BondFutureOptionTrade.class)),
column(OutputNames.SECURITY_MODEL_PRICE, output(OutputNames.SECURITY_MODEL_PRICE, BondFutureOptionTrade.class)),
column(OutputNames.DELTA, output(OutputNames.DELTA, BondFutureOptionTrade.class)),
column(OutputNames.GAMMA, output(OutputNames.GAMMA, BondFutureOptionTrade.class)),
column(OutputNames.VEGA, output(OutputNames.VEGA, BondFutureOptionTrade.class)),
column(OutputNames.THETA, output(OutputNames.THETA, BondFutureOptionTrade.class)),
column(OutputNames.PV01, output(OutputNames.PV01, BondFutureOptionTrade.class)),
column(OutputNames.BUCKETED_PV01, output(OutputNames.BUCKETED_PV01, BondFutureOptionTrade.class)));
}
/**
* Create discounting curves and add to the {@link MarketDataEnvironmentBuilder}
* @param builder the MarketDataEnvironmentBuilder
* @param discountingFile name of the discounting curves file
* @param issuerFile name of the issuer curves file
* @throws IOException
*/
public static void parseCurves(MarketDataEnvironmentBuilder builder, String discountingFile, String issuerFile) throws IOException {
MulticurveProviderDiscount multicurve = new MulticurveProviderDiscount();
Map<String, CurveUtils.CurveRawData> discountingCurves = CurveUtils.parseCurves(discountingFile);
for (Map.Entry<String, CurveUtils.CurveRawData> curve : discountingCurves.entrySet()) {
YieldAndDiscountCurve yieldCurve = CurveUtils.createYieldCurve(curve.getKey() + " Discounting", curve.getValue());
multicurve.setCurve(Currency.of(curve.getKey()), yieldCurve);
}
Map<Pair<Object, LegalEntityFilter<LegalEntity>>, YieldAndDiscountCurve> issuer = new LinkedHashMap<>();
Map<String, CurveUtils.CurveRawData> issuerCurves = CurveUtils.parseCurves(issuerFile);
for (Map.Entry<String, CurveUtils.CurveRawData> curve : issuerCurves.entrySet()) {
YieldAndDiscountCurve yieldCurve = CurveUtils.createIssuerCurve(curve.getKey(), curve.getValue());
Pair<Object, LegalEntityFilter<LegalEntity>> key = Pairs.<Object, LegalEntityFilter<LegalEntity>>of(curve.getKey(), new LegalEntityShortName());
issuer.put(key, yieldCurve);
}
IssuerProviderBundle issuerProviderBundle = new IssuerProviderBundle(new IssuerProviderDiscount(multicurve, issuer),
new CurveBuildingBlockBundle());
builder.add(IssuerMulticurveId.of(CURVE_BUNDLE), issuerProviderBundle);
}
/**
* Create volatility surfaces and add to the {@link MarketDataEnvironmentBuilder}
* @param builder the MarketDataEnvironmentBuilder
* @param file the name of the volatility surface file
* @throws IOException
*/
public 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()));
}
}
/**
* Parse the input portfolio
* @param file the name of the portfolio file
* @param securityMaster to persists the security
* @return map of trade to currency
* @throws IOException
*/
public static HashMap<Object, String> parseBondFutureOptions(String file, SecurityMaster securityMaster) throws IOException {
HashMap<Object, String> trades = new HashMap<>();
Reader reader = new BufferedReader(
new InputStreamReader(
new ClassPathResource(file).getInputStream()
)
);
try {
CSVReader csvReader = new CSVReader(reader);
String[] line;
csvReader.readNext(); // skip headers
while ((line = csvReader.readNext()) != null) {
//Security
ExternalId underlyingId = ExternalSchemes.isinSecurityId(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();
boolean margined = false;
BondFutureOptionSecurity security = new BondFutureOptionSecurity(exchange, exchange, expiry,
exerciseType, underlyingId, pointValue, margined,
currency, strike, optionType);
security.setName(underlyingId.getValue() + " " +
optionType.toString() + " Option " +
expiry.getExpiry().toLocalDate().toString() + " " + strike);
securityMaster.add(new SecurityDocument(security));
//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(Long.parseLong(line[6]));
LocalDate tradeDate = LocalDate.now();
OffsetTime tradeTime = OffsetTime.of(LocalTime.of(0, 0), ZoneOffset.UTC);
SimpleTrade trade = new SimpleTrade(security,
tradeQuantity,
counterparty,
tradeDate,
tradeTime);
trade.setPremium(0.0);
trade.setPremiumCurrency(currency);
trades.put(new BondFutureOptionTrade(trade), currency.getCode());
}
} catch (IOException e) {
s_logger.error("Failed to parse trade data ", e);
}
return trades;
}
/**
* Parse the underlying bond futures
* @param file the name of the underlying bond futures file
* @param securityMaster to persists the security
* @throws IOException
*/
public static HashMap<Object, String> parseBondFutures(String file, SecurityMaster securityMaster) throws IOException {
HashMap<Object, String> trades = new HashMap<>();
Reader reader = new BufferedReader(
new InputStreamReader(
new ClassPathResource(file).getInputStream()
)
);
try {
CSVReader csvReader = new CSVReader(reader);
String[] line;
csvReader.readNext(); // skip headers
while ((line = csvReader.readNext()) != null) {
Currency currency = Currency.of(line[3]);
Expiry expiry = new Expiry(ZonedDateTime.of(LocalDate.parse(line[4]), LocalTime.of(0, 0), ZoneId.of("UTC")));
String tradingExchange = currency.getCode();
String settlementExchange = currency.getCode();
double unitAmount = Double.parseDouble(line[7]);
Collection<BondFutureDeliverable> basket = new ArrayList<>();
ExternalId id = ExternalSchemes.isinSecurityId(line[1]);
ExternalIdBundle underlying = id.toBundle();
double conversion = Double.parseDouble(line[2]);
BondFutureDeliverable bondFutureDeliverable = new BondFutureDeliverable(underlying, conversion);
basket.add(bondFutureDeliverable);
ZonedDateTime firstDeliveryDate = ZonedDateTime.of(LocalDate.parse(line[5]), LocalTime.of(0, 0), ZoneId.of("UTC"));
ZonedDateTime lastDeliveryDate = ZonedDateTime.of(LocalDate.parse(line[6]), LocalTime.of(0, 0), ZoneId.of("UTC"));
String category = currency.getCode();
BondFutureSecurity security = new BondFutureSecurity(expiry, tradingExchange, settlementExchange, currency, unitAmount, basket,
firstDeliveryDate, lastDeliveryDate, category);
security.setExternalIdBundle(ExternalSchemes.isinSecurityId(line[0]).toBundle());
security.setName(line[0] + " Bond Future on " + id.getValue() + " " +
expiry.getExpiry().toLocalDate().toString() + " " + unitAmount);
securityMaster.add(new SecurityDocument(security));
//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.of(1900, 1, 1);
OffsetTime tradeTime = OffsetTime.of(LocalTime.of(0, 0), ZoneOffset.UTC);
SimpleTrade trade = new SimpleTrade(security,
tradeQuantity,
counterparty,
tradeDate,
tradeTime);
trade.setPremium(0.0);
trade.setPremiumCurrency(currency);
trades.put(new BondFutureTrade(trade), currency.getCode());
}
} catch (IOException e) {
s_logger.error("Failed to parse trade data ", e);
}
return trades;
}
/**
* Parse the underlying bonds
* @param file the name of the underlying bonds file
* @param securityMaster to persists the security
* @throws IOException
*/
public static void parseBonds(String file, SecurityMaster securityMaster) throws IOException {
Reader reader = new BufferedReader(
new InputStreamReader(
new ClassPathResource(file).getInputStream()
)
);
try {
CSVReader csvReader = new CSVReader(reader);
String[] line;
csvReader.readNext(); // skip headers
while ((line = csvReader.readNext()) != null) {
//Security - various elements of the bond object are not used in these examples so can be hard coded
String issuerName = line[1];
String issuerDomicile = line[2];
String issuerType = "";
Currency currency = Currency.of(line[3]);
YieldConvention yieldConvention = YieldConventionFactory.INSTANCE.getYieldConvention(line[4]);
DayCount dayCountConvention = DayCountFactory.of(line[5]);
Period couponPeriod = Period.parse("P" + line[6]);
String couponType = "";
double couponRate = Double.parseDouble(line[7]);
Frequency couponFrequency = PeriodFrequency.of(couponPeriod);
ZonedDateTime maturityDate = ZonedDateTime.of(LocalDate.parse(line[8]), LocalTime.of(0, 0), ZoneId.of("UTC"));
ZonedDateTime firstCouponDate = ZonedDateTime.of(LocalDate.parse(line[9]), LocalTime.of(0, 0), ZoneId.of("UTC"));
ZonedDateTime accrualDate = ZonedDateTime.of(LocalDate.parse(line[10]), LocalTime.of(0, 0), ZoneId.of("UTC"));
ZonedDateTime settlementDate = ZonedDateTime.of(LocalDate.parse(line[11]), LocalTime.of(0, 0), ZoneId.of("UTC"));
Expiry lastTradeDate = new Expiry(maturityDate);
double issuancePrice = 1.0;
double totalAmountIssued = 1.0;
double minimumAmount = 1.0;
double minimumIncrement = 1.0;
double parAmount = 1.0;
double redemptionValue = 1.0;
GovernmentBondSecurity security =
new GovernmentBondSecurity(issuerName, issuerType, issuerDomicile, issuerType, currency, yieldConvention,
lastTradeDate, couponType, couponRate, couponFrequency, dayCountConvention,
accrualDate, settlementDate, firstCouponDate, issuancePrice,
totalAmountIssued, minimumAmount, minimumIncrement, parAmount, redemptionValue);
security.setExternalIdBundle(ExternalSchemes.isinSecurityId(line[0]).toBundle());
securityMaster.add(new SecurityDocument(security));
}
} catch (IOException e) {
s_logger.error("Failed to parse trade data ", e);
}
}
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), CURVE_BUNDLE);
}
return new ExposureFunctions("Exposure", exposureFunctions, idsToNames);
}
}