package com.opengamma.sesame;
import static com.opengamma.id.VersionCorrection.LATEST;
import static com.opengamma.sesame.config.ConfigBuilder.argument;
import static com.opengamma.sesame.config.ConfigBuilder.arguments;
import static com.opengamma.sesame.config.ConfigBuilder.config;
import static com.opengamma.sesame.config.ConfigBuilder.function;
import static com.opengamma.sesame.config.ConfigBuilder.implementations;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.fudgemsg.FudgeContext;
import org.fudgemsg.FudgeMsg;
import org.fudgemsg.mapping.FudgeDeserializer;
import org.fudgemsg.wire.FudgeMsgReader;
import org.fudgemsg.wire.xml.FudgeXMLStreamReader;
import org.springframework.core.io.ClassPathResource;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.threeten.bp.Period;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
import com.google.common.base.Throwables;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.core.config.ConfigSource;
import com.opengamma.core.config.impl.ConfigItem;
import com.opengamma.core.convention.ConventionSource;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.core.holiday.HolidaySource;
import com.opengamma.core.holiday.impl.WeekendHolidaySource;
import com.opengamma.core.legalentity.LegalEntitySource;
import com.opengamma.core.region.RegionSource;
import com.opengamma.core.region.impl.SimpleRegion;
import com.opengamma.core.security.Security;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.financial.analytics.curve.AbstractCurveDefinition;
import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration;
import com.opengamma.financial.analytics.curve.CurveGroupConfiguration;
import com.opengamma.financial.analytics.curve.CurveNodeIdMapper;
import com.opengamma.financial.analytics.curve.CurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.DiscountingCurveTypeConfiguration;
import com.opengamma.financial.analytics.curve.InterpolatedCurveDefinition;
import com.opengamma.financial.analytics.curve.OvernightCurveTypeConfiguration;
import com.opengamma.financial.convention.ConventionBundleSource;
import com.opengamma.financial.convention.FinancialConvention;
import com.opengamma.financial.convention.OISLegConvention;
import com.opengamma.financial.convention.OvernightIndexConvention;
import com.opengamma.financial.convention.SwapFixedLegConvention;
import com.opengamma.financial.currency.CurrencyMatrix;
import com.opengamma.id.ExternalId;
import com.opengamma.id.VersionCorrection;
import com.opengamma.master.holiday.HolidayMaster;
import com.opengamma.service.ServiceContext;
import com.opengamma.service.ThreadLocalServiceContext;
import com.opengamma.service.VersionCorrectionProvider;
import com.opengamma.sesame.component.RetrievalPeriod;
import com.opengamma.sesame.component.StringSet;
import com.opengamma.sesame.config.FunctionModelConfig;
import com.opengamma.sesame.engine.ComponentMap;
import com.opengamma.sesame.graph.FunctionModel;
import com.opengamma.sesame.marketdata.DefaultMarketDataFn;
import com.opengamma.sesame.marketdata.HistoricalMarketDataFn;
import com.opengamma.sesame.marketdata.MarketDataBundle;
import com.opengamma.sesame.marketdata.MarketDataFn;
import com.opengamma.util.JodaBeanSerialization;
import com.opengamma.util.fudgemsg.OpenGammaFudgeContext;
import com.opengamma.util.money.Currency;
import com.opengamma.util.result.Result;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.Tenor;
import com.opengamma.util.tuple.DoublesPair;
import com.opengamma.util.tuple.Pair;
@Test(groups = TestGroup.UNIT)
public class DiscountingMulticurveBundleFnTest {
private static Map<Tenor, Pair<Double, Double>> s_usdExpected = Maps.newTreeMap();
static {
s_usdExpected.put(Tenor.ofDays(7), DoublesPair.of(0.0301369863013698, 0.9999747921866));
s_usdExpected.put(Tenor.ofMonths(1), DoublesPair.of(0.0904109589041095, 0.9999219499368));
s_usdExpected.put(Tenor.ofMonths(3), DoublesPair.of(0.252054794520547, 0.9997721332947));
s_usdExpected.put(Tenor.ofMonths(6), DoublesPair.of(0.501369863013698, 0.9994883129360));
s_usdExpected.put(Tenor.ofYears(1), DoublesPair.of(1.01095890410958, 0.9986846371672));
}
private final class TestVersionCorrectionProvider implements VersionCorrectionProvider {
@Override
public VersionCorrection getPortfolioVersionCorrection() {
return LATEST;
}
@Override
public VersionCorrection getConfigVersionCorrection() {
return LATEST;
}
}
private static final Class<?>[] MOCK_CLASSES = {
ConfigSource.class,
HistoricalTimeSeriesSource.class,
ConventionSource.class,
HistoricalMarketDataFn.class,
SecuritySource.class,
HolidayMaster.class,
RegionSource.class,
CurrencyMatrix.class
};
private static final RootFinderConfiguration ROOT_FINDER_CONFIG = new RootFinderConfiguration(1e-9, 1e-9, 1000);
private DiscountingMulticurveBundleResolverFn _multicurveBundleFn;
private Environment _environment;
private CurveConstructionConfiguration _usdDiscountingCCC;
@BeforeClass
public void init() throws IOException {
//builds graph, initializing mocks
ClassToInstanceMap<Object> mocks = MockUtils.mocks(MOCK_CLASSES);
initConfigSource(mocks.getInstance(ConfigSource.class));
initConventionSource(mocks.getInstance(ConventionSource.class));
initSecuritySource(mocks.getInstance(SecuritySource.class));
initRegionSource(mocks.getInstance(RegionSource.class));
mocks.putInstance(RootFinderConfiguration.class, ROOT_FINDER_CONFIG);
mocks.putInstance(HolidaySource.class, new WeekendHolidaySource());
mocks.putInstance(LegalEntitySource.class, mock(LegalEntitySource.class));
mocks.putInstance(ConventionBundleSource.class, mock(ConventionBundleSource.class));
ComponentMap components = ComponentMap.of(mocks);
FunctionModelConfig config = config(
arguments(
function(DefaultDiscountingMulticurveBundleFn.class,
argument("impliedCurveNames", StringSet.of("Implied Deposit Curve KRW"))),
function(DefaultCurveNodeConverterFn.class,
argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofDays(1))))),
implementations(CurveDefinitionFn.class, DefaultCurveDefinitionFn.class,
CurveSpecificationFn.class, DefaultCurveSpecificationFn.class,
CurveSpecificationMarketDataFn.class, DefaultCurveSpecificationMarketDataFn.class,
CurveNodeConverterFn.class, DefaultCurveNodeConverterFn.class,
FXMatrixFn.class, DefaultFXMatrixFn.class,
DiscountingMulticurveBundleFn.class, DefaultDiscountingMulticurveBundleFn.class,
DiscountingMulticurveBundleResolverFn.class, DefaultDiscountingMulticurveBundleResolverFn.class,
MarketDataFn.class, DefaultMarketDataFn.class));
_multicurveBundleFn = FunctionModel.build(DiscountingMulticurveBundleResolverFn.class, config, components);
ZonedDateTime valuationDate = ZonedDateTime.of(2014, 1, 10, 11, 0, 0, 0, ZoneId.of("America/Chicago"));
MarketDataBundle marketDataBundle =
MarketDataResourcesLoader.getPreloadedBundle(
"/regression/curve_testing/usdMarketQuotes.properties",
"Ticker");
_environment = new SimpleEnvironment(valuationDate, marketDataBundle);
VersionCorrectionProvider vcProvider = new TestVersionCorrectionProvider();
ServiceContext serviceContext = ServiceContext.of(mocks).with(VersionCorrectionProvider.class, vcProvider);
ThreadLocalServiceContext.init(serviceContext);
_usdDiscountingCCC = createUSDCurveConstructionConfig();
}
/**
* @param instance
*/
private void initRegionSource(RegionSource instance) {
SimpleRegion region = new SimpleRegion();
//region.setExternalIdBundle(ExternalIdBundle.of(ExternalId.of("KeyISO_COUNTRY_ALPHA2","US"), ExternalId.of("KeyISO_CURRENCY_ALPHA3","USD")));
region.setCurrency(Currency.USD);
when(instance.getHighestLevelRegion(ExternalId.of("FINANCIAL_REGION", "US"))).thenReturn(region);
//TODO calendar with this region
}
@Test
public void testUSD() {
Result<MulticurveBundle> bundle = _multicurveBundleFn.generateBundle(_environment, _usdDiscountingCCC);
assertTrue("Curve bundle result failed", bundle.isSuccess());
MulticurveBundle value = bundle.getValue();
MulticurveProviderDiscount multicurve = value.getMulticurveProvider();
for (Map.Entry<Tenor, Pair<Double, Double>> entry : s_usdExpected.entrySet()) {
Tenor tenor = entry.getKey();
Pair<Double, Double> pair = entry.getValue();
double time = pair.getKey();
double df = multicurve.getDiscountFactor(Currency.USD, pair.getKey());
assertEquals("USD DF for tenor " + tenor + " (" + time + ") mismatch", df, pair.getValue(), 10E-6);
}
}
private CurveConstructionConfiguration createUSDCurveConstructionConfig() {
List<CurveTypeConfiguration> ctc = Lists.newArrayList(new DiscountingCurveTypeConfiguration("USD"), new OvernightCurveTypeConfiguration(ExternalId.of("BLOOMBERG_TICKER", "FEDL01 Index")));
Map<String, List<? extends CurveTypeConfiguration>> ct = Maps.newHashMap();
ct.put("USD Discounting", ctc);
List<CurveGroupConfiguration> cgc = Lists.newArrayList(new CurveGroupConfiguration(0, ct ));
return new CurveConstructionConfiguration("USD", cgc, Collections.<String>emptyList());
}
private void initConfigSource(ConfigSource cs) {
InterpolatedCurveDefinition usdDiscountingCurve = loadConfig(InterpolatedCurveDefinition.class, "USD_Discounting.xml", false);
when(cs.get(Object.class, "USD Discounting", LATEST)).thenReturn(Collections.singletonList(ConfigItem.<Object> of(usdDiscountingCurve)));
when(cs.get(AbstractCurveDefinition.class, "USD Discounting", LATEST)).thenReturn(Collections.singletonList(ConfigItem.<AbstractCurveDefinition> of(usdDiscountingCurve)));
when(cs.getSingle(InterpolatedCurveDefinition.class, "USD Discounting", LATEST)).thenReturn(usdDiscountingCurve);
CurveNodeIdMapper nodeIdMapper = loadConfig(CurveNodeIdMapper.class, "USD_OIS_NodeMapper.xml", true);
when(cs.getSingle(CurveNodeIdMapper.class, "USD OIS Node Mapper", LATEST)).thenReturn(nodeIdMapper);
}
private void initConventionSource(ConventionSource cs) {
SwapFixedLegConvention fixedLegConvention =
loadConvention(SwapFixedLegConvention.class, "USD_OIS_Fixed_Leg.xml", false);
ExternalId usdOisConventionId = ExternalId.of("CONVENTION", "USD OIS Fixed Leg");
when(cs.getSingle(usdOisConventionId, FinancialConvention.class))
.thenReturn(fixedLegConvention);
when(cs.getSingle(usdOisConventionId.toBundle(), LATEST))
.thenReturn(fixedLegConvention);
FinancialConvention oisOvernight =
loadConvention(OISLegConvention.class, "USD_OIS_Overnight_Leg.xml", false);
ExternalId usdOisOnConventionId = ExternalId.of("CONVENTION", "USD OIS Overnight Leg");
when(cs.getSingle(usdOisOnConventionId, FinancialConvention.class))
.thenReturn(oisOvernight);
when(cs.getSingle(usdOisOnConventionId.toBundle(), LATEST))
.thenReturn(oisOvernight);
OvernightIndexConvention ff =
loadConvention(OvernightIndexConvention.class, "FedFundsEffectiveRateU.xml", false);
ExternalId fffConventionId = ExternalId.of("BLOOMBERG_CONVENTION_NAME", "Federal Funds Effective Rate U");
when(cs.getSingle(fffConventionId, FinancialConvention.class))
.thenReturn(ff);
when(cs.getSingle(fffConventionId, OvernightIndexConvention.class))
.thenReturn(ff);
when(cs.getSingle(fffConventionId.toBundle(), LATEST))
.thenReturn(ff);
}
private void initSecuritySource(SecuritySource ss) {
Security sec = loadSecurity(Security.class, "FEDL01 Index.xml", false);
when(ss.getSingle(ExternalId.of("BLOOMBERG_TICKER", "FEDL01 Index").toBundle())).thenReturn(sec);
when(ss.getSingle(ExternalId.of("BLOOMBERG_TICKER", "FEDL01 Index").toBundle(), LATEST)).thenReturn(sec);
}
private Security loadSecurity(Class<Security> clazz, String path, boolean isFudge) {
return loadBean(clazz, "security/" + path, isFudge);
}
private <T> T loadConfig(Class<T> clazz, String path, boolean isFudge) {
return loadBean(clazz, "config/" + path, isFudge);
}
private <T> T loadConvention(Class<T> clazz, String path, boolean isFudge) {
return loadBean(clazz, "convention/" + path, isFudge);
}
private <T> T loadBean(Class<T> clazz, String path, boolean isFudge) {
try {
File file = new ClassPathResource("regression/curve_testing/" + path).getFile();
if (!isFudge) {
return JodaBeanSerialization.deserializer().xmlReader().read(new FileInputStream(file), clazz);
} else {
FudgeContext context = OpenGammaFudgeContext.getInstance();
FudgeXMLStreamReader streamReader = new FudgeXMLStreamReader(context, new FileReader(file));
// Don't close fudgeMsgReader; the caller will close the stream later
@SuppressWarnings("resource")
FudgeMsgReader fudgeMsgReader = new FudgeMsgReader(streamReader);
FudgeMsg msg = fudgeMsgReader.nextMessage();
return new FudgeDeserializer(context).fudgeMsgToObject(clazz, msg);
}
} catch (IOException ex) {
throw Throwables.propagate(ex);
}
}
}