/** * Computes the interest rate sensitivity of future price. * * @param future The future security. * @param curves The curves. * @return The curve sensitivity. */ @Override public InterestRateCurveSensitivity priceCurveSensitivity( final FederalFundsFutureSecurity future, final YieldCurveBundle curves) { Validate.notNull(future, "Future"); Validate.notNull(curves, "Curves"); int nbFixing = future.getFixingPeriodAccrualFactor().length; YieldAndDiscountCurve ois = curves.getCurve(future.getOISCurveName()); double[] df = new double[nbFixing + 1]; for (int loopfix = 0; loopfix < nbFixing + 1; loopfix++) { df[loopfix] = ois.getDiscountFactor(future.getFixingPeriodTime()[loopfix]); } // Backward sweep double priceBar = 1.0; double interestBar = -1.0 / future.getFixingTotalAccrualFactor() * priceBar; double[] dfBar = new double[nbFixing + 1]; for (int loopfix = 0; loopfix < nbFixing; loopfix++) { dfBar[loopfix] += 1.0 / df[loopfix + 1] * interestBar; dfBar[loopfix + 1] += -df[loopfix] / (df[loopfix + 1] * df[loopfix + 1]) * interestBar; } Map<String, List<DoublesPair>> resultMap = new HashMap<String, List<DoublesPair>>(); List<DoublesPair> listOIS = new ArrayList<DoublesPair>(); for (int loopfix = 0; loopfix < nbFixing + 1; loopfix++) { listOIS.add( new DoublesPair( future.getFixingPeriodTime()[loopfix], -future.getFixingPeriodTime()[loopfix] * df[loopfix] * dfBar[loopfix])); } resultMap.put(future.getOISCurveName(), listOIS); InterestRateCurveSensitivity result = new InterestRateCurveSensitivity(resultMap); return result; }
@Test /** Test the price computed from the curves */ public void price() { final YieldCurveBundle curves = TestsDataSets.createCurves1(); final double price = METHOD.price(ERU2, curves); final YieldAndDiscountCurve forwardCurve = curves.getCurve(FORWARD_CURVE_NAME); final double forward = (forwardCurve.getDiscountFactor(FIXING_START_TIME) / forwardCurve.getDiscountFactor(FIXING_END_TIME) - 1) / FIXING_ACCRUAL; final double factor = MODEL.futureConvexityFactor(ERU2, MODEL_PARAMETERS); final double expectedPrice = 1.0 - factor * forward + (1 - factor) / FIXING_ACCRUAL; assertEquals("Future price from curves in Hull-White one factor model", expectedPrice, price); }
public void test() { final ConvectionDiffusionPDESolver solver = new ThetaMethodFiniteDifference(0.5, false); final int tNodes = 20; final int xNodes = 101; final PDEGrid1D grid = new PDEGrid1D(tNodes, xNodes, T, LOWER.getLevel(), UPPER.getLevel()); final PDEResults1D res = solver.solve(DATA, grid, LOWER, UPPER); final int i = (int) (xNodes * SPOT / UPPER.getLevel()); final double spot = res.getSpaceValue(i); final double price = res.getFunctionValue(i); final double df = YIELD_CURVE.getDiscountFactor(T); assertEquals(SPOT, spot, 1e-9); assertEquals(SABR_PRICE_SURFACE.getPrice(T, STRIKE), price, price * 2e-3); final BlackFunctionData data = new BlackFunctionData(spot / df, df, 0.0); double impVol; try { impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(data, OPTION, price); } catch (final Exception e) { impVol = 0.0; } assertEquals(SABR_VOL_SURFACE.getVolatility(T, STRIKE), impVol, 1e-3); }
static { ALPHA = ATM_VOL * Math.pow(SPOT, 1 - BETA); final Function<Double, Double> sabrSurface = new Function<Double, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final Double... x) { final double t = x[0]; final double k = x[1]; final SABRFormulaData sabrdata = new SABRFormulaData(SPOT * Math.exp(RATE * t), ALPHA, BETA, NU, RHO); final EuropeanVanillaOption option = new EuropeanVanillaOption(k, t, true); final Function1D<SABRFormulaData, Double> func = SABR.getVolatilityFunction(option); return func.evaluate(sabrdata); } }; SABR_VOL_SURFACE = new BlackVolatilitySurface(FunctionalDoublesSurface.from(sabrSurface)); final Function<Double, Double> priceSurface = new Function<Double, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final Double... x) { final double t = x[0]; final double k = x[1]; final double sigma = sabrSurface.evaluate(x); final double df = YIELD_CURVE.getDiscountFactor(t); final BlackFunctionData data = new BlackFunctionData(SPOT / df, df, sigma); final EuropeanVanillaOption option = new EuropeanVanillaOption(k, t, true); final Function1D<BlackFunctionData, Double> pfunc = BLACK_PRICE_FUNCTION.getPriceFunction(option); final double price = pfunc.evaluate(data); return price; } }; SABR_PRICE_SURFACE = new PriceSurface(FunctionalDoublesSurface.from(priceSurface)); final DupireLocalVolatilityCalculator cal = new DupireLocalVolatilityCalculator(); SABR_LOCAL_VOL = cal.getAbsoluteLocalVolatilitySurface(SABR_VOL_SURFACE, SPOT, RATE); STRIKE = SPOT / YIELD_CURVE.getDiscountFactor(T); OPTION = new EuropeanVanillaOption(STRIKE, T, true); LOWER = new DirichletBoundaryCondition(0, 0.0); UPPER = new FixedSecondDerivativeBoundaryCondition(0.0, 5.0 * SPOT, false); DATA = PDE_DATA_PROVIDER.getBackwardsLocalVol(FORWARD, STRIKE, T, 0.0, true, SABR_LOCAL_VOL); }
/** * Computes the price of a future from the curves using an estimation of the future rate without * convexity adjustment. * * @param future The future. * @param curves The Hull-White parameters and the curves. * @return The price. */ public double price( final InterestRateFuture future, final HullWhiteOneFactorPiecewiseConstantDataBundle curves) { Validate.notNull(future, "Future"); Validate.notNull(curves, "Curves"); final YieldAndDiscountCurve forwardCurve = curves.getCurve(future.getForwardCurveName()); double dfForwardStart = forwardCurve.getDiscountFactor(future.getFixingPeriodStartTime()); double dfForwardEnd = forwardCurve.getDiscountFactor(future.getFixingPeriodEndTime()); double forward = (dfForwardStart / dfForwardEnd - 1) / future.getFixingPeriodAccrualFactor(); double futureConvexityFactor = MODEL.futureConvexityFactor( future.getLastTradingTime(), future.getFixingPeriodStartTime(), future.getFixingPeriodEndTime(), curves.getHullWhiteParameter()); double price = 1.0 - futureConvexityFactor * forward + (1 - futureConvexityFactor) / future.getFixingPeriodAccrualFactor(); return price; }
@Override public Set<ComputedValue> execute( FunctionExecutionContext executionContext, FunctionInputs inputs, ComputationTarget target, Set<ValueRequirement> desiredValues) { // 1. Get the expiry _time_ from the trade SimpleTrade trade = (SimpleTrade) target.getTrade(); // confirms that the ComputationTargetType == TRADE EquityVarianceSwapSecurity security = (EquityVarianceSwapSecurity) trade.getSecurity(); double expiry = TimeCalculator.getTimeBetween( executionContext.getValuationClock().zonedDateTime(), security.getLastObservationDate()); // ExternalId id = security.getSpotUnderlyingIdentifier(); // 2. Get the discount curve and spot value Object discountObject = inputs.getValue(getDiscountRequirement(security)); if (discountObject == null) { throw new OpenGammaRuntimeException("Could not get Discount Curve"); } YieldAndDiscountCurve discountCurve = (YieldAndDiscountCurve) discountObject; Object spotObject = inputs.getValue(getSpotRequirement(security)); if (spotObject == null) { throw new OpenGammaRuntimeException("Could not get Underlying's Spot value"); } double spot = (Double) spotObject; // 3. Compute the forward final double discountFactor = discountCurve.getDiscountFactor(expiry); Validate.isTrue( discountFactor != 0, "The discount curve has returned a zero value for a discount bond. Check rates."); final double forward = spot / discountFactor; ValueSpecification valueSpec = getValueSpecification(security); return Collections.singleton(new ComputedValue(valueSpec, forward)); }
/** * Compute the price sensitivity to rates of a interest rate future by discounting. * * @param future The future. * @param curves The Hull-White parameters and the curves. * @return The price rate sensitivity. */ public InterestRateCurveSensitivity priceCurveSensitivity( final InterestRateFuture future, final HullWhiteOneFactorPiecewiseConstantDataBundle curves) { Validate.notNull(future, "Future"); Validate.notNull(curves, "Curves"); final YieldAndDiscountCurve forwardCurve = curves.getCurve(future.getForwardCurveName()); double dfForwardStart = forwardCurve.getDiscountFactor(future.getFixingPeriodStartTime()); double dfForwardEnd = forwardCurve.getDiscountFactor(future.getFixingPeriodEndTime()); double futureConvexityFactor = MODEL.futureConvexityFactor( future.getLastTradingTime(), future.getFixingPeriodStartTime(), future.getFixingPeriodEndTime(), curves.getHullWhiteParameter()); // Backward sweep double priceBar = 1.0; double forwardBar = -futureConvexityFactor * priceBar; double dfForwardEndBar = -dfForwardStart / (dfForwardEnd * dfForwardEnd) / future.getFixingPeriodAccrualFactor() * forwardBar; double dfForwardStartBar = 1.0 / (future.getFixingPeriodAccrualFactor() * dfForwardEnd) * forwardBar; Map<String, List<DoublesPair>> resultMap = new HashMap<String, List<DoublesPair>>(); List<DoublesPair> listForward = new ArrayList<DoublesPair>(); listForward.add( new DoublesPair( future.getFixingPeriodStartTime(), -future.getFixingPeriodStartTime() * dfForwardStart * dfForwardStartBar)); listForward.add( new DoublesPair( future.getFixingPeriodEndTime(), -future.getFixingPeriodEndTime() * dfForwardEnd * dfForwardEndBar)); resultMap.put(future.getForwardCurveName(), listForward); InterestRateCurveSensitivity result = new InterestRateCurveSensitivity(resultMap); return result; }
@Override /** * Computes the Federal Funds future price using average of forward rates (not convexity * adjustment). * * @param future The future security. * @param curves The curves. * @return The price. */ public double price(final FederalFundsFutureSecurity future, final YieldCurveBundle curves) { Validate.notNull(future, "Future"); Validate.notNull(curves, "Curves"); int nbFixing = future.getFixingPeriodAccrualFactor().length; YieldAndDiscountCurve ois = curves.getCurve(future.getOISCurveName()); double[] df = new double[nbFixing + 1]; for (int loopfix = 0; loopfix < nbFixing + 1; loopfix++) { df[loopfix] = ois.getDiscountFactor(future.getFixingPeriodTime()[loopfix]); } double interest = future.getAccruedInterest(); for (int loopfix = 0; loopfix < nbFixing; loopfix++) { interest += df[loopfix] / df[loopfix + 1] - 1.0; } return 1.0 - interest / future.getFixingTotalAccrualFactor(); }
@Test /** * Test the present value sensitivity to rate for a swaption with strike above the cut-off strike. */ public void testPresentValueSensitivityExtra() { final YieldCurveBundle curves = TestsDataSetsSABR.createCurves1(); final SABRInterestRateParameters sabrParameter = TestsDataSetsSABR.createSABR1(); final SABRInterestRateDataBundle sabrBundle = new SABRInterestRateDataBundle(sabrParameter, curves); final double highStrike = 0.10; final SwapFixedIborDefinition swapDefinitionPayerHighStrike = SwapFixedIborDefinition.from( SETTLEMENT_DATE, CMS_INDEX, NOTIONAL, highStrike, FIXED_IS_PAYER); final SwaptionCashFixedIborDefinition swaptionDefinitionLongPayerHighStrike = SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, IS_LONG); final SwaptionCashFixedIborDefinition swaptionDefinitionShortPayerHighStrike = SwaptionCashFixedIborDefinition.from(EXPIRY_DATE, swapDefinitionPayerHighStrike, !IS_LONG); final SwaptionCashFixedIbor swaptionLongPayerHighStrike = swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME); final SwaptionCashFixedIbor swaptionShortPayerHighStrike = swaptionDefinitionShortPayerHighStrike.toDerivative(REFERENCE_DATE, CURVES_NAME); final SwaptionCashFixedIborSABRExtrapolationRightMethod methodExtra = new SwaptionCashFixedIborSABRExtrapolationRightMethod(CUT_OFF_STRIKE, MU); // Swaption sensitivity InterestRateCurveSensitivity pvsLongPayerExtra = methodExtra.presentValueSensitivity(swaptionLongPayerHighStrike, sabrBundle); final InterestRateCurveSensitivity pvsShortPayerExtra = methodExtra.presentValueSensitivity(swaptionShortPayerHighStrike, sabrBundle); // Long/short parity final InterestRateCurveSensitivity pvsShortPayer_1 = pvsShortPayerExtra.multiply(-1); assertEquals(pvsLongPayerExtra.getSensitivities(), pvsShortPayer_1.getSensitivities()); // Present value sensitivity comparison with finite difference. final double deltaTolerance = 5.0E+4; // Testing note: Sensitivity is for a movement of 1. 1E+2 = 1 cent for a 1 bp move. Tolerance // increased to cope with numerical imprecision of finite difference. final double deltaShift = 1.0E-5; pvsLongPayerExtra = pvsLongPayerExtra.clean(); final double pv = methodExtra.presentValue(swaptionLongPayerHighStrike, sabrBundle); // 1. Forward curve sensitivity final String bumpedCurveName = "Bumped Curve"; final String[] bumpedCurvesForwardName = {FUNDING_CURVE_NAME, bumpedCurveName}; final SwaptionCashFixedIbor swaptionBumpedForward = swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, bumpedCurvesForwardName); final YieldAndDiscountCurve curveForward = curves.getCurve(FORWARD_CURVE_NAME); final Set<Double> timeForwardSet = new TreeSet<Double>(); for (final Payment pay : swaptionLongPayerHighStrike.getUnderlyingSwap().getSecondLeg().getPayments()) { final CouponIbor coupon = (CouponIbor) pay; timeForwardSet.add(coupon.getFixingPeriodStartTime()); timeForwardSet.add(coupon.getFixingPeriodEndTime()); } final int nbForwardDate = timeForwardSet.size(); final List<Double> timeForwardList = new ArrayList<Double>(timeForwardSet); Double[] timeForwardArray = new Double[nbForwardDate]; timeForwardArray = timeForwardList.toArray(timeForwardArray); final double[] yieldsForward = new double[nbForwardDate + 1]; final double[] nodeTimesForward = new double[nbForwardDate + 1]; yieldsForward[0] = curveForward.getInterestRate(0.0); for (int i = 0; i < nbForwardDate; i++) { nodeTimesForward[i + 1] = timeForwardArray[i]; yieldsForward[i + 1] = curveForward.getInterestRate(nodeTimesForward[i + 1]); } final YieldAndDiscountCurve tempCurveForward = new YieldCurve( InterpolatedDoublesCurve.fromSorted( nodeTimesForward, yieldsForward, new LinearInterpolator1D())); final List<DoublesPair> tempForward = pvsLongPayerExtra.getSensitivities().get(FORWARD_CURVE_NAME); final double[] resFwd = new double[nbForwardDate]; for (int i = 0; i < nbForwardDate; i++) { final YieldAndDiscountCurve bumpedCurveForward = tempCurveForward.withSingleShift(nodeTimesForward[i + 1], deltaShift); final YieldCurveBundle curvesBumpedForward = new YieldCurveBundle(); curvesBumpedForward.addAll(curves); curvesBumpedForward.setCurve("Bumped Curve", bumpedCurveForward); final SABRInterestRateDataBundle sabrBundleBumped = new SABRInterestRateDataBundle(sabrParameter, curvesBumpedForward); final double bumpedpv = methodExtra.presentValue(swaptionBumpedForward, sabrBundleBumped); resFwd[i] = (bumpedpv - pv) / deltaShift; final DoublesPair pair = tempForward.get(i); assertEquals( "Sensitivity to forward curve: Node " + i, nodeTimesForward[i + 1], pair.getFirst(), 1E-8); assertEquals( "Sensitivity to forward curve: Node " + i, resFwd[i], pair.getSecond(), deltaTolerance); } // 2. Funding curve sensitivity final String[] bumpedCurvesFundingName = {bumpedCurveName, FORWARD_CURVE_NAME}; final SwaptionCashFixedIbor swaptionBumpedFunding = swaptionDefinitionLongPayerHighStrike.toDerivative(REFERENCE_DATE, bumpedCurvesFundingName); final int nbPayDate = swaptionDefinitionLongPayerHighStrike.getUnderlyingSwap().getIborLeg().getPayments().length; final YieldAndDiscountCurve curveFunding = curves.getCurve(FUNDING_CURVE_NAME); final double[] yieldsFunding = new double[nbPayDate + 2]; final double[] nodeTimesFunding = new double[nbPayDate + 2]; yieldsFunding[0] = curveFunding.getInterestRate(0.0); nodeTimesFunding[1] = swaptionLongPayerHighStrike.getSettlementTime(); yieldsFunding[1] = curveFunding.getInterestRate(nodeTimesFunding[1]); for (int i = 0; i < nbPayDate; i++) { nodeTimesFunding[i + 2] = swaptionLongPayerHighStrike .getUnderlyingSwap() .getSecondLeg() .getNthPayment(i) .getPaymentTime(); yieldsFunding[i + 2] = curveFunding.getInterestRate(nodeTimesFunding[i + 2]); } final YieldAndDiscountCurve tempCurveFunding = new YieldCurve( InterpolatedDoublesCurve.fromSorted( nodeTimesFunding, yieldsFunding, new LinearInterpolator1D())); final List<DoublesPair> tempFunding = pvsLongPayerExtra.getSensitivities().get(FUNDING_CURVE_NAME); final double[] resDsc = new double[nbPayDate]; for (int i = 0; i < nbPayDate; i++) { final YieldAndDiscountCurve bumpedCurve = tempCurveFunding.withSingleShift(nodeTimesFunding[i + 1], deltaShift); final YieldCurveBundle curvesBumped = new YieldCurveBundle(); curvesBumped.addAll(curves); curvesBumped.setCurve("Bumped Curve", bumpedCurve); final SABRInterestRateDataBundle sabrBundleBumped = new SABRInterestRateDataBundle(sabrParameter, curvesBumped); final double bumpedpv = methodExtra.presentValue(swaptionBumpedFunding, sabrBundleBumped); resDsc[i] = (bumpedpv - pv) / deltaShift; final DoublesPair pair = tempFunding.get(i); assertEquals( "Sensitivity to discounting curve: Node " + i, nodeTimesFunding[i + 1], pair.getFirst(), 1E-8); assertEquals( "Sensitivity to discounting curve: Node " + i, resDsc[i], pair.getSecond(), deltaTolerance); } }