/** * Returns a copy of this {@code MultipleCurrencyAmount} with all the amounts multiplied by the * factor. * * <p>This instance is immutable and unaffected by this method. * * @param factor The multiplicative factor. * @return An amount based on this with all the amounts multiplied by the factor. Not null */ public MultipleCurrencyAmount multipliedBy(final double factor) { TreeMap<Currency, Double> map = new TreeMap<Currency, Double>(); for (CurrencyAmount currencyAmount : this) { map.put(currencyAmount.getCurrency(), currencyAmount.getAmount() * factor); } return MultipleCurrencyAmount.of(map); }
/** * Compute the the present value of a fixed payment by discounting to a parallel curve movement. * * @param payment The payment. * @param multicurves The multi-curve provider. * @return The present value. */ public MultipleCurrencyAmount presentValue( final PaymentFixed payment, final MulticurveProviderInterface multicurves) { ArgumentChecker.notNull(payment, "Payment"); ArgumentChecker.notNull(multicurves, "Multi-curves"); final double pv = payment.getAmount() * multicurves.getDiscountFactor(payment.getCurrency(), payment.getPaymentTime()); return MultipleCurrencyAmount.of(payment.getCurrency(), pv); }
/** * Compute the present value of a commodity cash settle forward by discounting. * * @param forward The forward. * @param multicurve The commodity multi-curve provider. * @return The present value. */ public MultipleCurrencyAmount presentValue( final ForwardCommodityCashSettle forward, final CommodityProviderInterface multicurve) { ArgumentChecker.notNull(forward, "Forward"); ArgumentChecker.notNull(multicurve, "Multi-curves provider"); final double fwd = multicurve.getForwardValue(forward.getUnderlying(), forward.getSettlementTime()); final double df = multicurve.getDiscountFactor(forward.getCurrency(), forward.getPaymentTime()); final double pv = forward.getNotional() * (fwd - forward.getRate()) * df; return MultipleCurrencyAmount.of(forward.getCurrency(), pv); }
@Test public void presentValueDiscountingCalculator() { final MultipleCurrencyAmount pvSwap = SWAP_MULTI_LEG.accept(PVDC, MULTICURVES); MultipleCurrencyAmount pvLegs = MultipleCurrencyAmount.of(EUR, 0.0); for (int loopleg = 0; loopleg < NB_LEGS; loopleg++) { pvLegs = pvLegs.plus(SWAP_MULTI_LEG.getLegs()[loopleg].accept(PVDC, MULTICURVES)); } assertEquals( "SwapMultileg: presentValueDiscountingCalculator", pvSwap.getAmount(EUR), pvLegs.getAmount(EUR), TOLERANCE_PV); }
@Test /** Check the conversion of a multiple currency amount. */ public void convert() { final FXMatrix fxMatrix = new FXMatrix(); fxMatrix.addCurrency(EUR, USD, EUR_USD); fxMatrix.addCurrency(GBP, EUR, GBP_EUR); final double amountGBP = 1.0; final double amountEUR = 2.0; final double amountUSD = 3.0; MultipleCurrencyAmount amount = MultipleCurrencyAmount.of(GBP, amountGBP); amount = amount.plus(EUR, amountEUR); amount = amount.plus(USD, amountUSD); final CurrencyAmount totalUSDCalculated = fxMatrix.convert(amount, USD); final double totalUSDExpected = amountUSD + amountEUR * EUR_USD + amountGBP * GBP_EUR * EUR_USD; assertEquals("FXMatrix - convert", totalUSDExpected, totalUSDCalculated.getAmount(), 1.0E-10); assertEquals("FXMatrix - convert", USD, totalUSDCalculated.getCurrency()); }
@Test(enabled = false) /** Tests of performance. "enabled = false" for the standard testing. */ public void performanceCurveSensitivity() { long startTime, endTime; final int nbTest = 25; MultipleCurrencyAmount pvMC = MultipleCurrencyAmount.of(EUR, 0.0); final MultipleCurrencyMulticurveSensitivity pvcsExplicit = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); MultipleCurrencyMulticurveSensitivity pvcsMC = pvcsExplicit; final HullWhiteMonteCarloMethod methodMC = new HullWhiteMonteCarloMethod( new NormalRandomNumberGenerator(0.0, 1.0, new MersenneTwister()), NB_PATH); startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvMC = METHOD_HW_MONTECARLO.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " swaption Hull-White Monte Carlo method (" + NB_PATH + " paths): " + (endTime - startTime) + " ms / price:" + pvMC.toString()); // Performance note: HW approximation: 03-Dec-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 250 // ms for 25 swaptions (12500 paths). startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvcsMC = methodMC.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " curve sensitivity swaption Hull-White MC method: (" + NB_PATH + " paths) " + (endTime - startTime) + " ms / risk:" + pvcsMC.toString()); // Performance note: curve sensitivity (40): 03-Dec-2012: On Mac Pro 3.2 GHz Quad-Core Intel // Xeon: 600 ms for 25 swaptions (12500 paths). }
/** * Compute the present value of a Ibor compounded coupon by discounting. * * @param coupon The coupon. * @param multicurve The multi-curve provider. * @return The present value. */ public MultipleCurrencyAmount presentValue( final CouponIborCompounding coupon, final MulticurveProviderInterface multicurve) { ArgumentChecker.notNull(coupon, "Coupon"); ArgumentChecker.notNull(multicurve, "Multi-curves provider"); final int nbSubPeriod = coupon.getFixingTimes().length; double notionalAccrued = coupon.getNotionalAccrued(); for (int loopsub = 0; loopsub < nbSubPeriod; loopsub++) { final double ratioForward = (1.0 + coupon.getPaymentAccrualFactors()[loopsub] * multicurve.getForwardRate( coupon.getIndex(), coupon.getFixingPeriodStartTimes()[loopsub], coupon.getFixingPeriodEndTimes()[loopsub], coupon.getFixingPeriodAccrualFactors()[loopsub])); notionalAccrued *= ratioForward; } final double df = multicurve.getDiscountFactor(coupon.getCurrency(), coupon.getPaymentTime()); final double pv = (notionalAccrued - coupon.getNotional()) * df; return MultipleCurrencyAmount.of(coupon.getCurrency(), pv); }
@Test(enabled = false) /** Tests of performance. "enabled = false" for the standard testing. */ public void performance() { long startTime, endTime; final int nbTest = 1000; MultipleCurrencyAmount pvPayerLongExplicit = MultipleCurrencyAmount.of(EUR, 0.0); MultipleCurrencyAmount pvPayerLongIntegration = MultipleCurrencyAmount.of(EUR, 0.0); MultipleCurrencyAmount pvPayerLongApproximation = MultipleCurrencyAmount.of(EUR, 0.0); @SuppressWarnings("unused") MultipleCurrencyAmount pvPayerLongMC = MultipleCurrencyAmount.of(EUR, 0.0); double[] pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); MultipleCurrencyMulticurveSensitivity pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvPayerLongExplicit = METHOD_HW.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " pv swaption Hull-White explicit method: " + (endTime - startTime) + " ms"); // Performance note: HW price: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 380 ms for // 10000 swaptions. startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " HW sensitivity swaption Hull-White explicit method: " + (endTime - startTime) + " ms"); // Performance note: HW sensitivity (3): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: // 430 ms for 10000 swaptions. startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " curve sensitivity swaption Hull-White explicit method: " + (endTime - startTime) + " ms"); // Performance note: curve sensitivity (40): 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel // Xeon: 855 ms for 10000 swaptions. startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); pvcs = METHOD_HW.presentValueCurveSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); pvhws = METHOD_HW.presentValueHullWhiteSensitivity(SWAPTION_LONG_PAYER, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " price/delta/vega swaption Hull-White explicit method: " + (endTime - startTime) + " ms"); // Performance note: present value/delta/vega: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel // Xeon: 1730 ms for 10000 swaptions. startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvPayerLongIntegration = METHOD_HW_INTEGRATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " swaption Hull-White numerical integration method: " + (endTime - startTime) + " ms"); // Performance note: HW numerical integration: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel // Xeon: 1700 ms for 10000 swaptions. startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvPayerLongApproximation = METHOD_HW_APPROXIMATION.presentValue(SWAPTION_LONG_PAYER, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " swaption Hull-White approximation method: " + (endTime - startTime) + " ms"); // Performance note: HW approximation: 19-Nov-2012: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 250 // ms for 10000 swaptions. startTime = System.currentTimeMillis(); for (int looptest = 0; looptest < nbTest; looptest++) { pvPayerLongMC = METHOD_HW_MONTECARLO.presentValue(SWAPTION_LONG_PAYER, EUR, HW_MULTICURVES); } endTime = System.currentTimeMillis(); System.out.println( nbTest + " swaption Hull-White Monte Carlo method (" + NB_PATH + " paths): " + (endTime - startTime) + " ms"); // Performance note: HW approximation: 18-Aug-11: On Mac Pro 3.2 GHz Quad-Core Intel Xeon: 9200 // ms for 1000 swaptions (12500 paths). final double difference = pvPayerLongExplicit.getAmount(EUR) - pvPayerLongIntegration.getAmount(EUR); final double difference2 = pvPayerLongExplicit.getAmount(EUR) - pvPayerLongApproximation.getAmount(EUR); // double difference3 = pvPayerLongExplicit.getAmount(CUR) - pvPayerLongMC.getAmount(CUR); System.out.println("Difference explicit-integration: " + difference); System.out.println("Difference explicit-approximation: " + difference2); // System.out.println("Difference explicit-Monte Carlo: " + difference3); System.out.println("Curve sensitivity: " + pvcs.toString()); System.out.println("HW sensitivity: " + Arrays.toString(pvhws)); }
@Test /** * Tests the toDerivative method on the payment date. valuation is at noon, payment set at * midnight... */ public void toDerivativeJustAfterPayment() { final ZonedDateTime referenceDate = DateUtils.getUTCDate(2011, 9, 19); final ZonedDateTime valuationTimeIsNoon = DateUtils.getUTCDate(2011, 9, 19, 12, 0); assertTrue( "valuationTimeIsNoon used to be after paymentDate, which was midnight. Confirm behaviour", valuationTimeIsNoon.isAfter(ON_COMPOUNDED_COUPON_DEFINITION.getPaymentDate())); final double fixingRate = 0.01; final DoubleTimeSeries<ZonedDateTime> fixingTS = ImmutableZonedDateTimeDoubleTimeSeries.ofUTC( new ZonedDateTime[] { DateUtils.getUTCDate(2011, 9, 7), DateUtils.getUTCDate(2011, 9, 8), DateUtils.getUTCDate(2011, 9, 9), DateUtils.getUTCDate(2011, 9, 12), DateUtils.getUTCDate(2011, 9, 13), DateUtils.getUTCDate(2011, 9, 14), DateUtils.getUTCDate(2011, 9, 15) }, new double[] { fixingRate, fixingRate, fixingRate, fixingRate, fixingRate, fixingRate, fixingRate }); final Payment cpnConverted = ON_COMPOUNDED_COUPON_DEFINITION.toDerivative(valuationTimeIsNoon, fixingTS); final double paymentTime = -TimeCalculator.getTimeBetween( referenceDate, EUR_PAYMENT_DATE, EUR_DAY_COUNT, EUR_CALENDAR); final double notionalAccrued = NOTIONAL * Math.pow( 1 + fixingRate, ON_COMPOUNDED_COUPON_DEFINITION.getFixingPeriodAccrualFactors()[0]) * Math.pow( 1 + fixingRate, ON_COMPOUNDED_COUPON_DEFINITION.getFixingPeriodAccrualFactors()[1]) * Math.pow( 1 + fixingRate, ON_COMPOUNDED_COUPON_DEFINITION.getFixingPeriodAccrualFactors()[2]) * Math.pow( 1 + fixingRate, ON_COMPOUNDED_COUPON_DEFINITION.getFixingPeriodAccrualFactors()[3]) * Math.pow( 1 + fixingRate, ON_COMPOUNDED_COUPON_DEFINITION.getFixingPeriodAccrualFactors()[4]); final CouponFixed cpnExpected = new CouponFixed( EUR_CUR, paymentTime, EUR_PAYMENT_YEAR_FRACTION, NOTIONAL, (notionalAccrued / NOTIONAL - 1.0) / EUR_PAYMENT_YEAR_FRACTION); assertEquals("CouponONCompounded definition: toDerivative", cpnExpected, cpnConverted); // Test pricing, too. Notice that the value of a coupon on its payment date is non-zero final MulticurveProviderDiscount curves = MulticurveProviderDiscountDataSets.createMulticurveEurUsd(); final MultipleCurrencyAmount pvConverted = com.opengamma.analytics.financial.interestrate.payments.provider .CouponFixedDiscountingMethod.getInstance() .presentValue((CouponFixed) cpnConverted, curves); final MultipleCurrencyAmount pvExpected = com.opengamma.analytics.financial.interestrate.payments.provider .CouponFixedDiscountingMethod.getInstance() .presentValue(cpnExpected, curves); assertEquals("CouponONCompounded definition: toDerivative", pvConverted, pvExpected); assertEquals( "CouponONCompounded definition: toDerivative", pvConverted, MultipleCurrencyAmount.of(EUR_CUR, 19744.6689499392)); }
/** * Computes the present value of an Ibor cap/floor in arrears by replication based on the paper, * "Swap and Cap/Floors with Fixing in Arrears or Payment Delay," OpenGamma Quantitative * Documentation * http://developers.opengamma.com/quantitative-research/In-Arrears-and-Payment-Delay-Swaps-and-Caps-OpenGamma.pdf * * @param cap The cap/floor * @param curves The curves * @return The present value */ public MultipleCurrencyAmount presentValue( final CapFloorIbor cap, final MulticurveProviderInterface curves) { ArgumentChecker.notNull(cap, "The cap/floor shoud not be null"); ArgumentChecker.notNull(curves, "curves"); final Currency ccy = cap.getCurrency(); // Construct a "standard" CapFloorIbor whose paymentTime is set to be fixingPeriodEndTime CapFloorIbor capStandard = new CapFloorIbor( cap.getCurrency(), cap.getFixingPeriodEndTime(), cap.getPaymentYearFraction(), cap.getNotional(), cap.getFixingTime(), cap.getIndex(), cap.getFixingPeriodStartTime(), cap.getFixingPeriodEndTime(), cap.getFixingAccrualFactor(), cap.getStrike(), cap.isCap()); final double forward = curves.getSimplyCompoundForwardRate( cap.getIndex(), cap.getFixingPeriodStartTime(), cap.getFixingPeriodEndTime(), cap.getFixingAccrualFactor()); final double beta = (1.0 + cap.getFixingAccrualFactor() * forward) * curves.getDiscountFactor(ccy, cap.getFixingPeriodEndTime()) / curves.getDiscountFactor(ccy, cap.getFixingPeriodStartTime()); final double df = curves.getDiscountFactor(capStandard.getCurrency(), capStandard.getPaymentTime()); final double strikePart = (1.0 + cap.getFixingAccrualFactor() * capStandard.getStrike()) * presentValueStandard( forward, capStandard.getStrike(), capStandard.getFixingTime(), capStandard.isCap(), df, capStandard.getNotional(), capStandard.getPaymentYearFraction()); final InArrearsIntegrant integrant = new InArrearsIntegrant(capStandard, curves); double integralPart; try { if (cap.isCap()) { double atmVol = _smileFunction.getVolatility(forward); double upper = forward * Math.exp(6.0 * atmVol * Math.sqrt(cap.getFixingTime())); double strike = cap.getStrike(); integralPart = INTEGRATOR.integrate(integrant, strike, upper); double reminder = integrant.evaluate(upper) * upper; double error = reminder / integralPart; int count = 0; while (Math.abs(error) > REL_ERROR && count < MAX_COUNT) { integralPart += INTEGRATOR.integrate(integrant, upper, 2.0 * upper); upper *= 2.0; // The increase of integralPart in the next loop is bounded by reminder reminder = integrant.evaluate(upper) * upper; error = reminder / integralPart; ++count; if (count == MAX_COUNT) { LOGGER.info( "Maximum iteration count, " + MAX_COUNT + ", has been reached. Relative error is greater than " + REL_ERROR); } } } else { double strike = cap.getStrike(); integralPart = INTEGRATOR.integrate(integrant, REL_TOL * strike, strike); } } catch (final Exception e) { throw new MathException(e); } integralPart *= 2.0 * cap.getFixingAccrualFactor(); final double pv = (strikePart + integralPart) / beta; return MultipleCurrencyAmount.of(cap.getCurrency(), pv); }