/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.credit.measures;
import java.math.BigDecimal;
import java.util.Iterator;
import org.threeten.bp.LocalDate;
import org.threeten.bp.OffsetTime;
import com.google.common.collect.ImmutableSortedSet;
import com.opengamma.analytics.financial.credit.isdastandardmodel.CDSAnalytic;
import com.opengamma.core.position.Counterparty;
import com.opengamma.core.position.Trade;
import com.opengamma.core.position.impl.SimpleCounterparty;
import com.opengamma.core.position.impl.SimpleTrade;
import com.opengamma.core.security.Security;
import com.opengamma.financial.analytics.isda.credit.CreditCurveDataKey;
import com.opengamma.financial.security.cds.CDSIndexComponentBundle;
import com.opengamma.financial.security.cds.CreditDefaultSwapIndexComponent;
import com.opengamma.financial.security.credit.IndexCDSDefinitionSecurity;
import com.opengamma.financial.security.credit.IndexCDSSecurity;
import com.opengamma.financial.security.credit.LegacyCDSSecurity;
import com.opengamma.financial.security.credit.StandardCDSSecurity;
import com.opengamma.financial.security.swap.InterestRateNotional;
import com.opengamma.id.ExternalId;
import com.opengamma.sesame.Environment;
import com.opengamma.sesame.credit.CdsData;
import com.opengamma.sesame.credit.IsdaCompliantCreditCurveFn;
import com.opengamma.sesame.credit.IsdaCreditCurve;
import com.opengamma.sesame.credit.converter.IndexCdsConverterFn;
import com.opengamma.sesame.credit.converter.LegacyCdsConverterFn;
import com.opengamma.sesame.credit.converter.StandardCdsConverterFn;
import com.opengamma.sesame.credit.market.CreditMarketDataResolverFn;
import com.opengamma.sesame.credit.market.IndexCdsMarketDataResolverFn;
import com.opengamma.sesame.credit.market.LegacyCdsMarketDataResolverFn;
import com.opengamma.sesame.credit.market.StandardCdsMarketDataResolverFn;
import com.opengamma.sesame.trade.IndexCDSTrade;
import com.opengamma.sesame.trade.LegacyCDSTrade;
import com.opengamma.sesame.trade.StandardCDSTrade;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.result.Result;
import com.opengamma.util.time.Tenor;
/**
* Abstract implementation of a credit risk measure, e.g. pv, cs01, etc. This
* class enforces a template for the generation of credit risk measures. The
* standard steps are:
* <li> resolve market data for security
* <li> convert security to its analytics type
* <li> extract any required meta-data into {@link CdsData}
* <li> price
*
* All steps are implemented except the last.
*
* @param <T> the type of risk measure this function produces
*/
public abstract class AbstractCreditRiskMeasureFn<T> implements CreditRiskMeasureFn<T> {
private final LegacyCdsConverterFn _legacyCdsConverterFn;
private final StandardCdsConverterFn _standardCdsConverterFn;
private final IndexCdsConverterFn _indexCdsConverterFn;
private final StandardCdsMarketDataResolverFn _standardCdsMarketDataResolverFn;
private final IndexCdsMarketDataResolverFn _indexCdsMarketDataResolverFn;
private final LegacyCdsMarketDataResolverFn _legacyCdsMarketDataResolverFn;
private final IsdaCompliantCreditCurveFn _creditCurveFn;
/**
* Creates an instance.
*
* @param legacyCdsConverterFn a legacy cds converter
* @param standardCdsConverterFn a standard cds converter
* @param indexCdsConverterFn a index cds converter
* @param indexCdsMarketDataResolverFn a market data resolver for index cds
* @param standardCdsMarketDataResolverFn a market data resolver for standard cds
* @param legacyCdsMarketDataResolverFn a market data resolver for legacy cds
* @param creditCurveFn the credit curve function
*/
protected AbstractCreditRiskMeasureFn(LegacyCdsConverterFn legacyCdsConverterFn,
StandardCdsConverterFn standardCdsConverterFn,
IndexCdsConverterFn indexCdsConverterFn,
IndexCdsMarketDataResolverFn indexCdsMarketDataResolverFn,
StandardCdsMarketDataResolverFn standardCdsMarketDataResolverFn,
LegacyCdsMarketDataResolverFn legacyCdsMarketDataResolverFn,
IsdaCompliantCreditCurveFn creditCurveFn) {
_legacyCdsConverterFn = ArgumentChecker.notNull(legacyCdsConverterFn, "legacyCdsConverterFn");
_standardCdsConverterFn = ArgumentChecker.notNull(standardCdsConverterFn, "standardCdsConverterFn");
_indexCdsConverterFn = ArgumentChecker.notNull(indexCdsConverterFn, "indexCdsConverterFn");
_indexCdsMarketDataResolverFn = ArgumentChecker.notNull(indexCdsMarketDataResolverFn,
"indexCdsMarketDataResolverFn");
_standardCdsMarketDataResolverFn = ArgumentChecker.notNull(standardCdsMarketDataResolverFn,
"standardCdsMarketDataResolverFn");
_legacyCdsMarketDataResolverFn = ArgumentChecker.notNull(legacyCdsMarketDataResolverFn,
"legacyCdsMarketDataResolverFn");
_creditCurveFn = ArgumentChecker.notNull(creditCurveFn, "creditCurveFn");
}
/**
* Resolve market data for the security using the passed function.
*
* @param env pricing environment
* @param resolverFn resolver function
* @param security security
* @return a resolved credit curve
*/
private <S> Result<IsdaCreditCurve> resolveMarketData(Environment env,
CreditMarketDataResolverFn<S> resolverFn,
S security) {
Result<CreditCurveDataKey> mdKeyResult = resolverFn.resolve(env, security);
if (!mdKeyResult.isSuccess()) {
return Result.failure(mdKeyResult);
}
return _creditCurveFn.buildIsdaCompliantCreditCurve(env, mdKeyResult.getValue()); //source from env
}
@Override
public Result<T> priceStandardCds(Environment env, StandardCDSTrade trade) {
StandardCDSSecurity cds = (StandardCDSSecurity) trade.getTrade().getSecurity();
Result<IsdaCreditCurve> marketDataResult = resolveMarketData(env, _standardCdsMarketDataResolverFn, cds);
//not much we can do if we can't resolve/build market data
if (!marketDataResult.isSuccess()) {
return Result.failure(marketDataResult);
}
IsdaCreditCurve creditCurve = marketDataResult.getValue();
Result<CDSAnalytic> analyticResult = _standardCdsConverterFn.toCdsAnalytic(env, cds, creditCurve);
if (analyticResult.isSuccess()) {
return price(extractForStandardCds(cds, creditCurve),
analyticResult.getValue(),
creditCurve);
} else {
return Result.failure(analyticResult);
}
}
@Override
public Result<T> priceLegacyCds(Environment env, LegacyCDSTrade trade) {
LegacyCDSSecurity cds = (LegacyCDSSecurity) trade.getTrade().getSecurity();
Result<IsdaCreditCurve> marketDataResult = resolveMarketData(env, _legacyCdsMarketDataResolverFn, cds);
//not much we can do if we can't resolve/build market data
if (!marketDataResult.isSuccess()) {
return Result.failure(marketDataResult);
}
IsdaCreditCurve creditCurve = marketDataResult.getValue();
Result<CDSAnalytic> analyticResult = _legacyCdsConverterFn.toCdsAnalytic(env, cds, creditCurve);
if (analyticResult.isSuccess()) {
return price(extractForLegacyCds(cds, creditCurve),
analyticResult.getValue(),
creditCurve);
} else {
return Result.failure(analyticResult);
}
}
@Override
public Result<T> priceIndexCds(Environment env, IndexCDSTrade trade) {
IndexCDSSecurity cds = (IndexCDSSecurity) trade.getTrade().getSecurity();
Result<IsdaCreditCurve> marketDataResult = resolveMarketData(env, _indexCdsMarketDataResolverFn, cds);
//not much we can do if we can't resolve/build market data
if (!marketDataResult.isSuccess()) {
return Result.failure(marketDataResult);
}
IsdaCreditCurve creditCurve = marketDataResult.getValue();
Result<CDSAnalytic> analyticResult = _indexCdsConverterFn.toCdsAnalytic(env, cds, creditCurve);
if (analyticResult.isSuccess()) {
return price(extractForIndexCds(cds, creditCurve),
analyticResult.getValue(),
creditCurve);
} else {
return Result.failure(analyticResult);
}
}
@Override
public Result<T> priceStandardCds(Environment env, StandardCDSSecurity cds) {
StandardCDSTrade tradeWrapper = new StandardCDSTrade(buildTrade(cds));
return priceStandardCds(env, tradeWrapper);
}
@Override
public Result<T> priceLegacyCds(Environment env, LegacyCDSSecurity cds) {
LegacyCDSTrade tradeWrapper = new LegacyCDSTrade(buildTrade(cds));
return priceLegacyCds(env, tradeWrapper);
}
@Override
public Result<T> priceIndexCds(Environment env, IndexCDSSecurity cds) {
IndexCDSTrade tradeWrapper = new IndexCDSTrade(buildTrade(cds));
return priceIndexCds(env, tradeWrapper);
}
private Trade buildTrade(Security security) {
return new SimpleTrade(security,
BigDecimal.ONE,
new SimpleCounterparty(ExternalId.of(Counterparty.DEFAULT_SCHEME, "CPARTY")),
LocalDate.now(),
OffsetTime.now());
}
/**
* Produce the risk measure for this instance using the analytics
* types passed.
*
* @param cdsData cds data
* @param cdsAnalytic the cds analytic constructed
* @param curve the resolved credit curve
* @return a result of the appropriate type
*/
protected abstract Result<T> price(CdsData cdsData,
CDSAnalytic cdsAnalytic,
IsdaCreditCurve curve);
/**
* Extracts relevant fields from standard cds security to CdsData.
*
*
* @param cds the standard cds
* @param creditCurve
* @return a CdsData instance
*/
private CdsData extractForStandardCds(StandardCDSSecurity cds, IsdaCreditCurve creditCurve) {
ImmutableSortedSet<Tenor> tenors = creditCurve.getCurveData().getCdsQuotes().keySet();
return CdsData.builder()
.coupon(cds.getCoupon())
.tenors(tenors)
.interestRateNotional(cds.getNotional())
.buy(cds.isBuyProtection())
.build();
}
/**
* Extracts relevant fields from index cds security to CdsData.
* Scaling the notional by the index factor, based on the combined weight
* of the index basket {@link CDSIndexComponentBundle}
*
* @param cds the index cds
* @return a CdsData instance
*/
private CdsData extractForIndexCds(IndexCDSSecurity cds, IsdaCreditCurve creditCurve) {
double indexFactor = 0d;
IndexCDSDefinitionSecurity definition = cds.getUnderlyingIndex().resolve();
CDSIndexComponentBundle components = definition.getComponents();
if (components.isEmpty()) {
indexFactor = 1d;
} else {
Iterator<CreditDefaultSwapIndexComponent> it = components.iterator();
while (it.hasNext()) {
indexFactor += it.next().getWeight();
}
}
InterestRateNotional notional = cds.getNotional();
InterestRateNotional scaledNotional = new InterestRateNotional(notional.getCurrency(),
notional.getAmount() * indexFactor);
ImmutableSortedSet<Tenor> tenors = creditCurve.getCurveData().getCdsQuotes().keySet();
return CdsData.builder()
.coupon(definition.getCoupon())
.tenors(tenors)
.interestRateNotional(scaledNotional)
.buy(cds.isBuyProtection())
.build();
}
/**
* Extracts relevant fields from legacy cds security to CdsData.
*
* @param cds the legacy cds
* @return a CdsData instance
*/
private CdsData extractForLegacyCds(LegacyCDSSecurity cds, IsdaCreditCurve creditCurve) {
ImmutableSortedSet<Tenor> tenors = creditCurve.getCurveData().getCdsQuotes().keySet();
return CdsData.builder()
.coupon(cds.getCoupon())
.tenors(tenors)
.interestRateNotional(cds.getNotional())
.buy(cds.isBuyProtection())
.build();
}
}