/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.swap.provider;
import static org.testng.AssertJUnit.assertEquals;
import java.util.HashMap;
import java.util.Map;
import org.testng.annotations.Test;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.analytics.env.AnalyticsEnvironment;
import com.opengamma.analytics.financial.datasets.CalendarGBP;
import com.opengamma.analytics.financial.instrument.annuity.AnnuityDefinition;
import com.opengamma.analytics.financial.instrument.index.GeneratorAttributeIR;
import com.opengamma.analytics.financial.instrument.index.GeneratorSwapFixedIbor;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexIborMaster;
import com.opengamma.analytics.financial.instrument.payment.CouponFloatingDefinition;
import com.opengamma.analytics.financial.instrument.payment.PaymentDefinition;
import com.opengamma.analytics.financial.instrument.swap.SwapFixedIborDefinition;
import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitor;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Coupon;
import com.opengamma.analytics.financial.interestrate.payments.derivative.Payment;
import com.opengamma.analytics.financial.interestrate.swap.derivative.Swap;
import com.opengamma.analytics.financial.interestrate.swap.derivative.SwapFixedCoupon;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueCurveSensitivityDiscountingCalculator;
import com.opengamma.analytics.financial.provider.calculator.discounting.PresentValueDiscountingCalculator;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount;
import com.opengamma.analytics.financial.provider.description.interestrate.ParameterProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyParameterSensitivity;
import com.opengamma.analytics.financial.provider.sensitivity.parameter.ParameterSensitivityParameterCalculator;
import com.opengamma.analytics.financial.schedule.ScheduleCalculator;
import com.opengamma.analytics.math.curve.ConstantDoublesCurve;
import com.opengamma.analytics.math.curve.InterpolatedDoublesCurve;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.interpolation.CombinedInterpolatorExtrapolatorFactory;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.Interpolator1DFactory;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.MatrixAlgebra;
import com.opengamma.analytics.math.matrix.OGMatrixAlgebra;
import com.opengamma.analytics.util.AssertMatrix;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.daycount.DayCounts;
import com.opengamma.timeseries.precise.zdt.ImmutableZonedDateTimeDoubleTimeSeries;
import com.opengamma.timeseries.precise.zdt.ZonedDateTimeDoubleTimeSeries;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.test.TestGroup;
import com.opengamma.util.time.DateUtils;
/**
* GBP swap pricing example
*/
@Test(groups = TestGroup.UNIT)
public class GBPSwapPVTest {
private static final InstrumentDerivativeVisitor<ParameterProviderInterface, MultipleCurrencyMulticurveSensitivity> PVCSDC = PresentValueCurveSensitivityDiscountingCalculator.getInstance();
/** The parameter sensitivity calculator */
private static final ParameterSensitivityParameterCalculator<ParameterProviderInterface> PSC = new ParameterSensitivityParameterCalculator<>(PVCSDC);
private static final MatrixAlgebra MA = new OGMatrixAlgebra();
private static final double NOTIONAL = 2e9;
private static final Calendar baseCalendar = new CalendarGBP("GBP");
private static final PresentValueDiscountingCalculator PVDC = PresentValueDiscountingCalculator.getInstance();
private static final ZonedDateTime TRADE_DATE = DateUtils.getUTCDate(2014, 10, 6);
// this is the single curve for IM
private static final double[] GBP_LIBOR_KNOT_TIMES = new double[] {0.002739726027397, 0.019178082191781, 0.082191780821918, 0.164383561643836, 0.249315068493151, 0.498630136986301,
0.747945205479452, 1, 1.4986301369863, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, 20, 25, 30, 35, 40, 45, 50 };
private static final double[] GBP_LIBOR_ZERO_RATES = new double[] {0.00475626901070822, 0.00483107619161134, 0.00504645027587814, 0.00531456932134962, 0.00551204367300484, 0.0061026272153353,
0.00684153896499341, 0.00765126878343251, 0.00940584623535082, 0.0111463649353094, 0.0151993630408899, 0.017520513620551, 0.0192799279116312, 0.0207051221084842, 0.0218964288340252,
0.0229171448309875, 0.0238054222996467, 0.0245820797759827, 0.025876126744085, 0.0272638169223121, 0.0285519785481517, 0.0289179058336173, 0.0290094237232156, 0.028796927786485,
0.0286085652864115, 0.0285639181095462, 0.0285319734875664 };
// these multi curves are used for VM
private static final double[] GBP_SONIA_KNOT_TIMES = new double[] {0.002739726027397, 0.019178082191781, 0.038356164383562, 0.084931506849315, 0.172602739726027, 0.252054794520548,
0.336986301369863, 0.413698630136986, 0.501369863013699, 0.580821917808219, 0.671232876712329, 0.747945205479452, 0.832876712328767, 0.920547945205479, 1, 1.25205479452055, 1.5013698630137,
1.75068493150685, 2.0027397260274, 3.0027397260274, 4.00821917808219, 5.00547945205479, 6.00547945205479, 7.00547945205479, 8.00547945205479, 9.00547945205479, 10.0109589041096, 12.0082191780822,
15.0164383561644, 20.013698630137, 25.0164383561644, 30.0219178082192, 35.0246575342466, 40.027397260274, 45.0301369863014, 50.0356164383562 };
private static final double[] GBP_SONIA_ZERO_RATES = new double[] {0.00430997455348493, 0.00431882113819674, 0.00431314320653989, 0.00431970749752497, 0.00444129725993973, 0.00447764229051919,
0.00454934099818509, 0.00480522065276289, 0.00503962777637656, 0.00520911179002989, 0.00543690213062051, 0.00563610380093184, 0.00583579456204562, 0.00612718766319607, 0.00636519907010272,
0.00717310918750252, 0.00795749811802235, 0.00870119236161661, 0.00946155387022128, 0.0123334511255753, 0.0143921749914485, 0.0159592596727554, 0.0172361877785297, 0.0183436791467994,
0.0192793358953591, 0.0201222559973813, 0.0208986383710833, 0.0222510994961065, 0.023877100242259, 0.0256026136259111, 0.026288001664418, 0.0266311744778153, 0.0264014166694374,
0.0263527169318637, 0.0262906111905873, 0.0263674066536486 };
private static final double[] GBP_LIBOR1M_KNOT_TIMES = new double[] {0.084931506849315, 0.172602739726027, 0.252054794520548, 0.501369863013699, 0.747945205479452, 1, 2.0027397260274,
3.0027397260274, 4.00821917808219, 5.00547945205479, 6.00547945205479, 7.00547945205479, 8.00547945205479, 9.00547945205479, 10.0109589041096, 12.0082191780822, 15.0164383561644, 20.013698630137,
25.0164383561644, 30.0219178082192, 35.0246575342466, 40.027397260274, 45.0301369863014, 50.0356164383562 };
private static final double[] GBP_LIBOR1M_ZERO_RATES = new double[] {0.00505581436649715, 0.00503291190352002, 0.00514256786002282, 0.00569033898394734, 0.00639149506676498, 0.00723232237139851,
0.0105298436453575, 0.0135410574559515, 0.0158030551363141, 0.0174456995488895, 0.0187732338667046, 0.0199055537021988, 0.0208531180033394, 0.0216810024002466, 0.0224286195281712,
0.0237374945104143, 0.0252160567356682, 0.0267142361493482, 0.0272605000077873, 0.0275097501922553, 0.0272973928154239, 0.02732399981293, 0.0272679024586238, 0.0273500955580994 };
private static final double[] GBP_LIBOR3M_KNOT_TIMES = new double[] {0.252054794520548, 0.446575342465753, 0.695890410958904, 0.945205479452055, 1.19452054794521, 1.44383561643836,
1.69315068493151, 1.96164383561644, 2.21095890410959, 3.0027397260274, 4.00821917808219, 5.00547945205479, 6.00547945205479, 7.00547945205479, 8.00547945205479, 9.00547945205479,
10.0109589041096, 12.0082191780822, 15.0164383561644, 20.013698630137, 25.0164383561644, 30.0219178082192, 35.0246575342466, 40.027397260274, 45.0301369863014, 50.0356164383562 };
private static final double[] GBP_LIBOR3M_ZERO_RATES = new double[] {0.00562351263918076, 0.00605140841711946, 0.00674163439039939, 0.00751172986806733, 0.00835257242596894, 0.00924368840059903,
0.0101182341187527, 0.0110392349927795, 0.0118815761688227, 0.0141891783018791, 0.0164362685797301, 0.0180908568757903, 0.0194306164834304, 0.0205622948941999, 0.021509365473766,
0.0223369044043144, 0.0230980379156519, 0.0243918201709714, 0.0258555923419827, 0.0273230838882434, 0.0278368027650289, 0.0280342598539863, 0.0278259808180962, 0.0277923406323035,
0.0277421859831982, 0.0278284728253182 };
private static final double[] GBP_LIBOR6M_KNOT_TIMES = new double[] {0.501369863013699, 1, 1.5013698630137, 2.0027397260274, 3.0027397260274, 4.00821917808219, 5.00547945205479, 6.00547945205479,
7.00547945205479, 8.00547945205479, 9.00547945205479, 10.0109589041096, 12.0082191780822, 15.0164383561644, 20.013698630137, 25.0164383561644, 30.0219178082192, 35.0246575342466, 40.027397260274,
45.0301369863014, 50.0356164383562 };
private static final double[] GBP_LIBOR6M_ZERO_RATES = new double[] {0.00710174175249047, 0.00860451137005419, 0.0103551375418353, 0.0121086290753976, 0.015178756626544, 0.0175003704137641,
0.0192427630940745, 0.0206581597595687, 0.0218403443388774, 0.0228520936339576, 0.0237315739821965, 0.0245039864998691, 0.025779797672448, 0.0271525952264722, 0.0284196247149596,
0.0287909199539885, 0.0288932996886611, 0.0286980928245931, 0.0285278998759854, 0.0284929581122082, 0.0284672034337625 };
private static final YieldAndDiscountCurve GBP_LIBOR_CURVE;
private static final YieldAndDiscountCurve GBP_SONIA_CURVE;
private static final YieldAndDiscountCurve GBP_LIBOR1M_CURVE;
private static final YieldAndDiscountCurve GBP_LIBOR3M_CURVE;
private static final YieldAndDiscountCurve GBP_LIBOR6M_CURVE;
private static final MulticurveProviderDiscount SINGLE_CURVE;
private static final MulticurveProviderDiscount MULTI_CURVE;
private static final IndexIborMaster MASTER_IBOR = IndexIborMaster.getInstance();
private static final IborIndex GBPLIBOR1M = MASTER_IBOR.getIndex("GBPLIBOR1M");
private static final IborIndex GBPLIBOR3M = MASTER_IBOR.getIndex("GBPLIBOR3M");
private static final IborIndex GBPLIBOR6M = MASTER_IBOR.getIndex("GBPLIBOR6M");
private static final Currency CCY = GBPLIBOR1M.getCurrency();
private static final ZonedDateTime[] FIXING_DATES = new ZonedDateTime[] {DateUtils.getUTCDate(2014, 8, 18), DateUtils.getUTCDate(2014, 10, 6) };
private static final ZonedDateTimeDoubleTimeSeries TS_GBPLIBOR3M = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(FIXING_DATES, new double[] {0.005605, 0.0056275 });
private static final ZonedDateTimeDoubleTimeSeries TS_GBPLIBOR6M = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(FIXING_DATES, new double[] {0.0069775, 0.0071144 });
private static final Map<IborIndex, ZonedDateTimeDoubleTimeSeries> FIXINGS;
private static final Interpolator1D IM_INTERPOLATOR;
private static final Interpolator1D VM_INTERPOLATOR;
static {
FIXINGS = new HashMap<>(4);
FIXINGS.put(GBPLIBOR3M, TS_GBPLIBOR3M);
FIXINGS.put(GBPLIBOR6M, TS_GBPLIBOR6M);
IM_INTERPOLATOR = CombinedInterpolatorExtrapolatorFactory.getInterpolator(Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR);
VM_INTERPOLATOR = CombinedInterpolatorExtrapolatorFactory.getInterpolator(
Interpolator1DFactory.PRODUCT_NATURAL_CUBIC, Interpolator1DFactory.FLAT_EXTRAPOLATOR,
Interpolator1DFactory.RECIPROCAL_EXTRAPOLATOR);
GBP_LIBOR_CURVE = new YieldCurve("GBP Libor", new InterpolatedDoublesCurve(GBP_LIBOR_KNOT_TIMES, GBP_LIBOR_ZERO_RATES, IM_INTERPOLATOR, true));
GBP_SONIA_CURVE = new YieldCurve("GBP Sonia", new InterpolatedDoublesCurve(GBP_SONIA_KNOT_TIMES, GBP_SONIA_ZERO_RATES, VM_INTERPOLATOR, true));
GBP_LIBOR1M_CURVE = new YieldCurve("GBP Libor 1M", new InterpolatedDoublesCurve(GBP_LIBOR1M_KNOT_TIMES, GBP_LIBOR1M_ZERO_RATES, VM_INTERPOLATOR, true));
GBP_LIBOR3M_CURVE = new YieldCurve("GBP Libor 3M", new InterpolatedDoublesCurve(GBP_LIBOR3M_KNOT_TIMES, GBP_LIBOR3M_ZERO_RATES, VM_INTERPOLATOR, true));
GBP_LIBOR6M_CURVE = new YieldCurve("GBP Libor 6M", new InterpolatedDoublesCurve(GBP_LIBOR6M_KNOT_TIMES, GBP_LIBOR6M_ZERO_RATES, VM_INTERPOLATOR, true));
@SuppressWarnings("unused")
YieldCurve zero = new YieldCurve("zero", ConstantDoublesCurve.from(0.0));
SINGLE_CURVE = new MulticurveProviderDiscount();
SINGLE_CURVE.setOrReplaceCurve(CCY, GBP_LIBOR_CURVE);
SINGLE_CURVE.setOrReplaceCurve(GBPLIBOR1M, GBP_LIBOR_CURVE);
SINGLE_CURVE.setOrReplaceCurve(GBPLIBOR3M, GBP_LIBOR_CURVE);
SINGLE_CURVE.setOrReplaceCurve(GBPLIBOR6M, GBP_LIBOR_CURVE);
MULTI_CURVE = new MulticurveProviderDiscount();
MULTI_CURVE.setOrReplaceCurve(CCY, GBP_SONIA_CURVE);
MULTI_CURVE.setOrReplaceCurve(GBPLIBOR1M, GBP_LIBOR1M_CURVE);
MULTI_CURVE.setOrReplaceCurve(GBPLIBOR3M, GBP_LIBOR3M_CURVE);
MULTI_CURVE.setOrReplaceCurve(GBPLIBOR6M, GBP_LIBOR6M_CURVE);
}
/**
* Test the IM NPV, delta & gamma for a seasoned swap.
* This is a 3M fixed Vs float with a coupon of 2% - the effective date is 18-Feb-2014 and the termination date is the
* 18-Feb-2019 (i.e. this was originally a 5Y swap)
*/
@Test
public void testSeasonedSwap() {
AnalyticsEnvironment.setInstance(AnalyticsEnvironment.getInstance().toBuilder().modelDayCount(DayCounts.ACT_365)
.build());
double coupon = 0.02;
ZonedDateTime effDate = DateUtils.getUTCDate(2014, 2, 18);
Period swapTenor = Period.ofYears(5); // termination date 18/02/2019
SwapFixedIborDefinition swapDef = makeSwapDef(GBPLIBOR3M, effDate, swapTenor, coupon, NOTIONAL);
double expImNpv = -2.012506863816616E7;
double expVmNpv = -2.92490786938425E7;
DoubleMatrix1D expDelta = new DoubleMatrix1D(0, 0, -13295.06565595203, -10166.814913375081, 192.18569490757258, 500.95144492207777, 737.1719141579288, 1610.7473112728212, 2960.684803071864,
5797.798336051921, 12428.744989705048, 517803.6258600666, 304194.28278619424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
DoubleMatrix1D expGamma = new DoubleMatrix1D(0, 0, 0.1566268008783391, 0.11977343596578863, -0.007108238030828089, -0.02635626715757221, -0.056885092021793426, -0.1787119119364074,
-0.45267430946650566, -1.3767795332248913, -3.8464351748222136, -225.74022089673812, -132.8577895249877, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
testImPriceAndDelta(swapDef, TRADE_DATE, expImNpv, expDelta, expGamma);
testVmNpv(swapDef, TRADE_DATE, expVmNpv);
AnalyticsEnvironment.setInstance(AnalyticsEnvironment.DEFAULT);
}
/**
* Test the IM NPV, delta & gamma for a spot starting 5Y swap.
* This is a 3M fixed Vs float with a coupon of 1.8% - the effective date is 6-Oct-2014 (i.e. today) and the termination
* date is the 16-Oct-2019
*/
@Test
public void testSpotStarting5YSwap() {
AnalyticsEnvironment.setInstance(AnalyticsEnvironment.getInstance().toBuilder().modelDayCount(DayCounts.ACT_365)
.build());
double coupon = 0.018;
ZonedDateTime effDate = DateUtils.getUTCDate(2014, 10, 6);
Period swapTenor = Period.ofYears(5); // termination date 6/10/2019
SwapFixedIborDefinition swapDef = makeSwapDef(GBPLIBOR3M, effDate, swapTenor, coupon, NOTIONAL);
// these number come from the SMART API
double expImNpv = 1.1050631904386938E7;
double expVmNpv = -75412.71316513419;
DoubleMatrix1D expDelta = new DoubleMatrix1D(0, 0, 0, 0, -49632.4255084524, 976.208958972902, -2026.74477030921, 3065.41427124944, 2656.9664567835, 5701.96379992345, 9906.05728427153,
15976.3010680254, 909245.758217927, 7433.36153796299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
DoubleMatrix1D expGamma = new DoubleMatrix1D(0, 0, 0, 0, 1.25100908130893, -0.0894835162024819, 0.125063124838612, -0.239876495266289, -0.403875990484971, -1.25711576707553, -3.11758912386388,
-6.5416697665622, -454.865666666857, -3.6581303462374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
testImPriceAndDelta(swapDef, TRADE_DATE, expImNpv, expDelta, expGamma);
testVmNpv(swapDef, TRADE_DATE, expVmNpv);
AnalyticsEnvironment.setInstance(AnalyticsEnvironment.DEFAULT);
}
/**
* Test the IM NPV, delta & gamma for a spot starting 10Y swap.
* This is a 6M fixed Vs float with a coupon of 1.8% - the effective date is 6-Oct-2014 (i.e. today) and the termination
* date is the 16-Oct-2024
*/
@Test
public void testSpotStarting10YSwap() {
AnalyticsEnvironment.setInstance(AnalyticsEnvironment.getInstance().toBuilder().modelDayCount(DayCounts.ACT_365)
.build());
double coupon = 0.03;
ZonedDateTime effDate = DateUtils.getUTCDate(2014, 10, 6);
Period swapTenor = Period.ofYears(10); // termination date 6/10/2024
SwapFixedIborDefinition swapDef = makeSwapDef(GBPLIBOR6M, effDate, swapTenor, coupon, NOTIONAL);
// these number come from the SMART API
double expImNpv = -1.0222040526150137E8;
double expVmNpv = -1.0496644868809742E8;
DoubleMatrix1D expDelta = new DoubleMatrix1D(0, 0, 0, 0, 0, -97196.9994870792, -1079.96666096754, 1335.14030038791, 5521.29236720072, 9510.26367240674, 17185.06655544, 24577.9320516185,
22254.5350746961, 34549.256798932, 36014.5418502935, 39942.877027383, 47537.8635419423, 1585829.99987959, 10828.3857355132, 0, 0, 0, 0, 0, 0, 0, 0);
DoubleMatrix1D expGamma = new DoubleMatrix1D(0, 0, 0, 0, 0, 4.84622451300801, 0.0538469390334223, -0.161052818155604, -0.719393713339903, -2.0834698170384, -5.22254635716672, -10.1242640156405,
-11.3974801071293, -20.2488639790105, -25.2621973392004, -32.0024263476015, -43.2417411211072, -1587.05920064115, -10.7314585575958, 0, 0, 0, 0, 0, 0, 0, 0);
testImPriceAndDelta(swapDef, TRADE_DATE, expImNpv, expDelta, expGamma);
testVmNpv(swapDef, TRADE_DATE, expVmNpv);
AnalyticsEnvironment.setInstance(AnalyticsEnvironment.DEFAULT);
}
/**
* Print multicurve, for debugging
*/
@Test(enabled = false)
public void printMulticurve() {
System.out.println(SINGLE_CURVE);
System.out.println(CCY);
System.out.println(GBPLIBOR1M.getDayCount() + "\t" + GBPLIBOR1M.getTenor() + "\t" + GBPLIBOR1M.getSpotLag());
System.out.println(GBPLIBOR3M.getDayCount() + "\t" + GBPLIBOR3M.getTenor() + "\t" + GBPLIBOR3M.getSpotLag());
System.out.println(GBPLIBOR3M);
}
private void testImPriceAndDelta(SwapFixedIborDefinition swapDef, ZonedDateTime tradeDate, double expImNpv, DoubleMatrix1D expDelta, DoubleMatrix1D expGamma) {
double oneBps = 1e-4;
double oneBpsSqr = 1e-8;
IborIndex index = swapDef.getIborLeg().getIborIndex();
ZonedDateTimeDoubleTimeSeries fixings = FIXINGS.get(index);
SwapFixedCoupon<Coupon> swap = swapDef.toDerivative(tradeDate, new ZonedDateTimeDoubleTimeSeries[] {fixings });
MultipleCurrencyAmount price = swap.accept(PVDC, SINGLE_CURVE);
assertEquals(expImNpv, price.getAmount(CCY), 1e-15 * NOTIONAL);
Function1D<DoubleMatrix1D, DoubleMatrix1D> func = getDeltaFunction(swap, index, GBP_LIBOR_KNOT_TIMES, IM_INTERPOLATOR);
DoubleMatrix1D delta = func.evaluate(new DoubleMatrix1D(GBP_LIBOR_ZERO_RATES));
// scale to be in bps
delta = (DoubleMatrix1D) MA.scale(delta, oneBps);
if (expDelta != null) {
AssertMatrix.assertEqualsVectors(expDelta, delta, 1e-13 * NOTIONAL * oneBps);
} else {
System.out.println("Calcualted delta: " + delta);
}
DoubleMatrix1D gamma = getColumnGamma(swap, index, GBP_LIBOR_KNOT_TIMES, GBP_LIBOR_ZERO_RATES, IM_INTERPOLATOR);
// scale to be in bps^2
gamma = (DoubleMatrix1D) MA.scale(gamma, oneBpsSqr);
// gamma is calculated by finite-difference (on the delta) so the accuracy will not be as high
if (expGamma != null) {
AssertMatrix.assertEqualsVectors(expGamma, gamma, 1e-8 * NOTIONAL * oneBpsSqr);
} else {
System.out.println("Calcualted gamma: " + gamma);
}
}
private void testVmNpv(SwapFixedIborDefinition swapDef, ZonedDateTime tradeDate, double expVmNpv) {
IborIndex index = swapDef.getIborLeg().getIborIndex();
ZonedDateTimeDoubleTimeSeries fixings = FIXINGS.get(index);
SwapFixedCoupon<Coupon> swap = swapDef.toDerivative(tradeDate, new ZonedDateTimeDoubleTimeSeries[] {fixings });
MultipleCurrencyAmount price = swap.accept(PVDC, MULTI_CURVE);
assertEquals(expVmNpv, price.getAmount(CCY), 1e-15 * NOTIONAL);
}
private SwapFixedIborDefinition makeSwapDef(IborIndex index, ZonedDateTime effDate, Period swapTenor, double coupon, double notional) {
// This just ensures the the swap does start on the spot date
ZonedDateTime refDate = ScheduleCalculator.getAdjustedDate(effDate, -index.getSpotLag(), baseCalendar);
GeneratorAttributeIR att = new GeneratorAttributeIR(swapTenor);
Period tenor = index.getTenor();
GeneratorSwapFixedIbor swapGen = new GeneratorSwapFixedIbor(index.toString() + " Swap", tenor, index.getDayCount(), index, baseCalendar);
return swapGen.generateInstrument(refDate, coupon, notional, att);
}
/**
* Creates a function that returns the delta (swap PV's sensitivity to the zero rates) for a set of zero rates
* @param swap The swap
* @param index The Ibor-index of the swap
* @param t The curve knot times
* @param interpolator The interpolator used for the curve
* @return function that maps zero rates to deltas
*/
private Function1D<DoubleMatrix1D, DoubleMatrix1D> getDeltaFunction(final Swap<? extends Payment, ? extends Payment> swap, final IborIndex index, final double[] t, final Interpolator1D interpolator) {
return new Function1D<DoubleMatrix1D, DoubleMatrix1D>() {
String curveName = "GBP Libor";
@Override
public DoubleMatrix1D evaluate(DoubleMatrix1D zeroRates) {
YieldCurve curve = new YieldCurve(curveName, new InterpolatedDoublesCurve(t, zeroRates.getData(), interpolator, true));
MulticurveProviderDiscount multiCurve = new MulticurveProviderDiscount();
multiCurve.setOrReplaceCurve(CCY, curve);
multiCurve.setOrReplaceCurve(index, curve);
MultipleCurrencyParameterSensitivity senseZeroRates = PSC.calculateSensitivity(swap, multiCurve);
return senseZeroRates.getSensitivityByName(curveName).get(CCY);
}
};
}
/**
* The column summed gamma is the sum of the column of the full gamma matrix (second order sensitivity of the swap PV to the
* zero rates). Here we calculate it by bumping the zeros rates up and down in parallel by a small amount, eps.
* @param swap The swap
* @param index The Ibor-index of the swap
* @param t The curve knot times
* @param r The curve sezo rates
* @param interpolator The interpolator used for the curve
* @return The (column summed) gamma for a swap
*/
private DoubleMatrix1D getColumnGamma(final Swap<? extends Payment, ? extends Payment> swap, final IborIndex index, final double[] t, final double[] r, final Interpolator1D interpolator) {
double eps = 1e-6;
double scale = 1 / 2. / eps;
final int n = r.length;
final DoubleMatrix1D zeroRates = new DoubleMatrix1D(r);
final Function1D<DoubleMatrix1D, DoubleMatrix1D> deltaFunc = getDeltaFunction(swap, index, t, interpolator);
Function1D<Double, DoubleMatrix1D> ParellelDeltaFunc = new Function1D<Double, DoubleMatrix1D>() {
@Override
public DoubleMatrix1D evaluate(Double shift) {
DoubleMatrix1D shifts = new DoubleMatrix1D(n, shift);
return deltaFunc.evaluate((DoubleMatrix1D) MA.add(shifts, zeroRates));
}
};
DoubleMatrix1D up = ParellelDeltaFunc.evaluate(eps);
DoubleMatrix1D down = ParellelDeltaFunc.evaluate(-eps);
return (DoubleMatrix1D) MA.scale(MA.subtract(up, down), scale);
}
/*
* The function used for debugging
*/
@SuppressWarnings("unused")
private ZonedDateTime getLastFixing(AnnuityDefinition<?> leg, ZonedDateTime now) {
for (PaymentDefinition p : leg.getPayments()) {
if (p.getPaymentDate().isAfter(now)) {
return ((CouponFloatingDefinition) p).getFixingDate();
}
}
throw new IllegalArgumentException("all payments in past");
}
}