/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.sesame.integration_tests;
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.nonPortfolioOutput;
import static com.opengamma.sesame.config.ConfigBuilder.output;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Period;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.core.link.ConfigLink;
import com.opengamma.engine.marketdata.spec.LiveMarketDataSpecification;
import com.opengamma.engine.marketdata.spec.MarketDataSpecification;
import com.opengamma.financial.analytics.curve.CurveConstructionConfiguration;
import com.opengamma.financial.analytics.curve.exposure.ExposureFunctions;
import com.opengamma.financial.convention.businessday.BusinessDayConventions;
import com.opengamma.financial.convention.daycount.DayCounts;
import com.opengamma.financial.convention.frequency.PeriodFrequency;
import com.opengamma.financial.currency.CurrencyMatrix;
import com.opengamma.financial.security.irs.FixedInterestRateSwapLeg;
import com.opengamma.financial.security.irs.FloatingInterestRateSwapLeg;
import com.opengamma.financial.security.irs.InterestRateSwapLeg;
import com.opengamma.financial.security.irs.InterestRateSwapNotional;
import com.opengamma.financial.security.irs.InterestRateSwapSecurity;
import com.opengamma.financial.security.irs.PayReceiveType;
import com.opengamma.financial.security.irs.Rate;
import com.opengamma.financial.security.swap.FloatingRateType;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.sesame.ConfigDbMarketExposureSelectorFn;
import com.opengamma.sesame.DefaultCurveNodeConverterFn;
import com.opengamma.sesame.DefaultDiscountingMulticurveBundleFn;
import com.opengamma.sesame.DefaultDiscountingMulticurveBundleResolverFn;
import com.opengamma.sesame.OutputNames;
import com.opengamma.sesame.RootFinderConfiguration;
import com.opengamma.sesame.component.RetrievalPeriod;
import com.opengamma.sesame.component.StringSet;
import com.opengamma.sesame.config.ViewColumn;
import com.opengamma.sesame.config.ViewConfig;
import com.opengamma.sesame.engine.Results;
import com.opengamma.sesame.irs.DiscountingInterestRateSwapCalculatorFactory;
import com.opengamma.sesame.irs.DiscountingInterestRateSwapFn;
import com.opengamma.sesame.irs.InterestRateSwapCalculatorFactory;
import com.opengamma.sesame.irs.InterestRateSwapFn;
import com.opengamma.sesame.server.FunctionServer;
import com.opengamma.sesame.server.FunctionServerRequest;
import com.opengamma.sesame.server.IndividualCycleOptions;
import com.opengamma.sesame.server.RemoteFunctionServer;
import com.opengamma.util.GUIDGenerator;
import com.opengamma.util.money.Currency;
import com.opengamma.util.result.Result;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;
/**
* Tests that a view can be run against a remote server.
* The tests cover the validation of a successful PV result
* and a the curve bundle used to price the swap.
*/
@Test(groups = TestGroup.INTEGRATION, enabled = false)
public class RemoteInterestRateSwapTest {
private static final String URL = "http://localhost:8080/jax";
private static final String CURVE_RESULT = "Curve Bundle";
private FunctionServer _functionServer;
private IndividualCycleOptions _cycleOptions;
private ConfigLink<ExposureFunctions> _exposureConfig;
private ConfigLink<CurrencyMatrix> _currencyMatrixLink;
private ConfigLink<CurveConstructionConfiguration> _curveConstructionConfiguration;
private List<Object> _inputs = new ArrayList<>();
@BeforeClass
public void setUp() {
/* Create a RemoteFunctionServer to executes view requests RESTfully.*/
_functionServer = new RemoteFunctionServer(URI.create(URL));
/* Single cycle options containing the market data specification and valuation time.
The captureInputs flag (false by default) will return the data used to calculate
the result. Note this can be a very large object. */
MarketDataSpecification bloomberg = LiveMarketDataSpecification.of("Bloomberg");
_cycleOptions = IndividualCycleOptions.builder()
.valuationTime(DateUtils.getUTCDate(2014, 1, 22))
.marketDataSpecs(ImmutableList.of(bloomberg))
.captureInputs(false)
.build();
/* Configuration links matching the curve exposure function, currency matrix and curve bundle
as named on the remote server. These are needed as specific arguments in the creation
of the ViewConfig. */
_exposureConfig = ConfigLink.resolvable("USD CSA Exposure Functions", ExposureFunctions.class);
_currencyMatrixLink = ConfigLink.resolvable("BloombergLiveData", CurrencyMatrix.class);
_curveConstructionConfiguration = ConfigLink.resolvable("USD TO GBP CSA USD Curve Construction Configuration",
CurveConstructionConfiguration.class);
/* Add Fixed vs Libor 3m Swaps to the ManageableSecurity list, with different fixed leg rates*/
_inputs.add(createFixedVsLibor3mSwap(0.015));
_inputs.add(createFixedVsLibor3mSwap(0.016));
_inputs.add(createFixedVsLibor3mSwap(0.017));
_inputs.add(createFixedVsLibor3mSwap(0.018));
}
@Test(enabled = false)
public void testSwapPVExecution() {
/* Building the output specific request, based on a the view config, the single cycle options
and the List<ManageableSecurity> containing the swaps */
FunctionServerRequest<IndividualCycleOptions> request =
FunctionServerRequest.<IndividualCycleOptions>builder()
.viewConfig(createSingleColumnViewConfig(OutputNames.PRESENT_VALUE))
.inputs(_inputs)
.cycleOptions(_cycleOptions)
.build();
/* Execute the engine cycle and extract the first result result */
Results results = _functionServer.executeSingleCycle(request);
Result result = results.get(0,0).getResult();
assertThat(result.isSuccess(), is(true));
}
@Test(enabled = false)
public void testSwapPVAndBucketedPV01Execution() {
FunctionServerRequest<IndividualCycleOptions> request =
FunctionServerRequest.<IndividualCycleOptions>builder()
.viewConfig(createDoubleColumnViewConfig(OutputNames.PRESENT_VALUE, OutputNames.BUCKETED_PV01))
.inputs(_inputs)
.cycleOptions(_cycleOptions)
.build();
Results results = _functionServer.executeSingleCycle(request);
Result result = results.get(0,0).getResult();
assertThat(result.isSuccess(), is(true));
}
@Test(enabled = false)
public void testSwapReceiveLegCashFlowsExecution() {
FunctionServerRequest<IndividualCycleOptions> request =
FunctionServerRequest.<IndividualCycleOptions>builder()
.viewConfig(createSingleColumnViewConfig(OutputNames.RECEIVE_LEG_CASH_FLOWS))
.inputs(_inputs)
.cycleOptions(_cycleOptions)
.build();
Results results = _functionServer.executeSingleCycle(request);
Result result = results.get(0,0).getResult();
assertThat(result.isSuccess(), is(true));
}
@Test(enabled = false)
public void testSwapPayLegCashFlowsExecution() {
FunctionServerRequest<IndividualCycleOptions> request =
FunctionServerRequest.<IndividualCycleOptions>builder()
.viewConfig(createSingleColumnViewConfig(OutputNames.PAY_LEG_CASH_FLOWS))
.inputs(_inputs)
.cycleOptions(_cycleOptions)
.build();
Results results = _functionServer.executeSingleCycle(request);
Result result = results.get(0,0).getResult();
assertThat(result.isSuccess(), is(true));
}
@Test(enabled = false)
public void testSwapBucketedPV01Execution() {
FunctionServerRequest<IndividualCycleOptions> request =
FunctionServerRequest.<IndividualCycleOptions>builder()
.viewConfig(createSingleColumnViewConfig(OutputNames.BUCKETED_PV01))
.inputs(_inputs)
.cycleOptions(_cycleOptions)
.build();
Results results = _functionServer.executeSingleCycle(request);
Result result = results.get(0,0).getResult();
assertThat(result.isSuccess(), is(true));
}
@Test(enabled = false)
public void testSwapPV01Execution() {
FunctionServerRequest<IndividualCycleOptions> request =
FunctionServerRequest.<IndividualCycleOptions>builder()
.viewConfig(createSingleColumnViewConfig(OutputNames.PV01))
.inputs(_inputs)
.cycleOptions(_cycleOptions)
.build();
Results results = _functionServer.executeSingleCycle(request);
Result result = results.get(0,0).getResult();
assertThat(result.isSuccess(), is(true));
}
@Test(enabled = false)
public void testCurveBundleExecution() {
FunctionServerRequest<IndividualCycleOptions> request =
FunctionServerRequest.<IndividualCycleOptions>builder()
.viewConfig(createCurveBundleConfig())
.cycleOptions(_cycleOptions)
.build();
Results results = _functionServer.executeSingleCycle(request);
Result result = results.getNonPortfolioResults().get(CURVE_RESULT).getResult();
assertThat(result.isSuccess(), is(true));
}
/* Output specific single column view configuration for interest rate swaps */
private ViewConfig createSingleColumnViewConfig(String output) {
return
configureView(
"IRS Remote view",
createViewColumn(output)
);
}
/* Output specific double column view configuration for interest rate swaps */
private ViewConfig createDoubleColumnViewConfig(String first, String second) {
return
configureView(
"IRS Remote view",
createViewColumn(first),
createViewColumn(second)
);
}
/* Shared column configuration */
private ViewColumn createViewColumn(String output) {
return
column(
output,
config(
arguments(
function(
ConfigDbMarketExposureSelectorFn.class, argument("exposureConfig", _exposureConfig)),
function(
RootFinderConfiguration.class,
argument("rootFinderAbsoluteTolerance", 1e-9),
argument("rootFinderRelativeTolerance", 1e-9),
argument("rootFinderMaxIterations", 1000)),
function(
DefaultCurveNodeConverterFn.class,
argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1)))),
function(
DefaultDiscountingMulticurveBundleFn.class,
argument("impliedCurveNames", StringSet.of()))),
implementations(
InterestRateSwapFn.class, DiscountingInterestRateSwapFn.class,
InterestRateSwapCalculatorFactory.class, DiscountingInterestRateSwapCalculatorFactory.class)),
output(output, InterestRateSwapSecurity.class));
}
/* A non portfolio output view configuration to capture the build curves */
private ViewConfig createCurveBundleConfig() {
return
configureView(
"Curve Bundle only",
nonPortfolioOutput(
CURVE_RESULT,
output(
OutputNames.DISCOUNTING_MULTICURVE_BUNDLE,
config(
arguments(
function(
RootFinderConfiguration.class,
argument("rootFinderAbsoluteTolerance", 1e-9),
argument("rootFinderRelativeTolerance", 1e-9),
argument("rootFinderMaxIterations", 1000)),
function(
DefaultCurveNodeConverterFn.class,
argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1)))),
function(
DefaultDiscountingMulticurveBundleResolverFn.class,
argument("curveConfig", _curveConstructionConfiguration)),
function(
DefaultDiscountingMulticurveBundleFn.class,
argument("impliedCurveNames", StringSet.of())))))));
}
private InterestRateSwapSecurity createFixedVsLibor3mSwap(double rate) {
InterestRateSwapNotional notional = new InterestRateSwapNotional(Currency.USD, 1_000_000);
PeriodFrequency freq6m = PeriodFrequency.of(Period.ofMonths(6));
PeriodFrequency freq3m = PeriodFrequency.of(Period.ofMonths(3));
Set<ExternalId> calendarUSNY = Sets.newHashSet(ExternalId.of(ExternalSchemes.ISDA_HOLIDAY, "USNY"));
List<InterestRateSwapLeg> legs = new ArrayList<>();
FixedInterestRateSwapLeg payLeg = new FixedInterestRateSwapLeg();
payLeg.setNotional(notional);
payLeg.setDayCountConvention(DayCounts.THIRTY_U_360);
payLeg.setPaymentDateFrequency(freq6m);
payLeg.setPaymentDateBusinessDayConvention(BusinessDayConventions.MODIFIED_FOLLOWING);
payLeg.setPaymentDateCalendars(calendarUSNY);
payLeg.setAccrualPeriodFrequency(freq6m);
payLeg.setAccrualPeriodBusinessDayConvention(BusinessDayConventions.MODIFIED_FOLLOWING);
payLeg.setMaturityDateBusinessDayConvention(BusinessDayConventions.MODIFIED_FOLLOWING);
payLeg.setAccrualPeriodCalendars(calendarUSNY);
payLeg.setRate(new Rate(rate));
payLeg.setPayReceiveType(PayReceiveType.PAY);
legs.add(payLeg);
FloatingInterestRateSwapLeg receiveLeg = new FloatingInterestRateSwapLeg();
receiveLeg.setNotional(notional);
receiveLeg.setDayCountConvention(DayCounts.ACT_360);
receiveLeg.setPaymentDateFrequency(freq3m);
receiveLeg.setPaymentDateBusinessDayConvention(BusinessDayConventions.MODIFIED_FOLLOWING);
receiveLeg.setPaymentDateCalendars(calendarUSNY);
receiveLeg.setAccrualPeriodFrequency(freq3m);
receiveLeg.setAccrualPeriodBusinessDayConvention(BusinessDayConventions.MODIFIED_FOLLOWING);
receiveLeg.setAccrualPeriodCalendars(calendarUSNY);
receiveLeg.setResetPeriodFrequency(freq3m);
receiveLeg.setResetPeriodBusinessDayConvention(BusinessDayConventions.MODIFIED_FOLLOWING);
receiveLeg.setResetPeriodCalendars(calendarUSNY);
receiveLeg.setFixingDateBusinessDayConvention(BusinessDayConventions.PRECEDING);
receiveLeg.setMaturityDateBusinessDayConvention(BusinessDayConventions.MODIFIED_FOLLOWING);
receiveLeg.setFixingDateCalendars(calendarUSNY);
receiveLeg.setFixingDateOffset(-2);
receiveLeg.setFloatingRateType(FloatingRateType.IBOR);
receiveLeg.setFloatingReferenceRateId(ExternalId.of("BLOOMBERG_TICKER", "US0003M Index"));
receiveLeg.setPayReceiveType(PayReceiveType.RECEIVE);
legs.add(receiveLeg);
return new InterestRateSwapSecurity(
ExternalIdBundle.of(ExternalId.of("UUID", GUIDGenerator.generate().toString())),
"Fixed " + rate + " vs Libor 3m",
LocalDate.of(2014, 9, 12), // effective date
LocalDate.of(2021, 9, 12), // maturity date,
legs);
}
}