static InterpolatedStrikeSmileDeltaTermStructureTest() { for (int loopexp = 0; loopexp < NB_EXP; loopexp++) { VOLATILITY_TERM.Add(SmileDeltaParameters.of(TIME_TO_EXPIRY.get(loopexp), ATM.get(loopexp), DELTA, DoubleArray.copyOf(RISK_REVERSAL.toArray()[loopexp]), DoubleArray.copyOf(STRANGLE.toArray()[loopexp]))); } }
/// <summary> /// Tests the interpolation in the time and strike dimensions. /// </summary> public virtual void volatilityTimeInterpolation() { double forward = 1.40; double timeToExpiry = 0.75; double strike = 1.50; double[] vol050 = SMILE_TERM.VolatilityTerm.get(2).Volatility.toArray(); double[] vol100 = SMILE_TERM.VolatilityTerm.get(3).Volatility.toArray(); double[] vol = new double[vol050.Length]; for (int loopvol = 0; loopvol < vol050.Length; loopvol++) { vol[loopvol] = Math.Sqrt(((vol050[loopvol] * vol050[loopvol] * TIME_TO_EXPIRY.get(2) + vol100[loopvol] * vol100[loopvol] * TIME_TO_EXPIRY.get(3)) / 2.0) / timeToExpiry); } SmileDeltaParameters smile = SmileDeltaParameters.of(timeToExpiry, DELTA, DoubleArray.copyOf(vol)); DoubleArray strikes = smile.strike(forward); double volExpected = INTERPOLATOR_STRIKE.bind(strikes, DoubleArray.copyOf(vol), FLAT, FLAT).interpolate(strike); double volComputed = SMILE_TERM.volatility(timeToExpiry, strike, forward); assertEquals(volComputed, volExpected, TOLERANCE_VOL, "Smile by delta term structure: vol interpolation on strike"); double volTriple = SMILE_TERM.volatility(timeToExpiry, strike, forward); assertEquals(volTriple, volComputed, TOLERANCE_VOL, "Smile by delta term structure: vol interpolation on strike"); InterpolatedStrikeSmileDeltaTermStructure smileTerm2 = InterpolatedStrikeSmileDeltaTermStructure.of(VOLATILITY_TERM, ACT_360); double volComputed2 = smileTerm2.volatility(timeToExpiry, strike, forward); assertEquals(volComputed2, volComputed, TOLERANCE_VOL, "Smile by delta term structure: vol interp on strike"); }
/// <summary> /// Tests the constructor directly from volatilities (not RR and S). /// </summary> public virtual void constructorVolatility() { DoubleArray volatility = SMILE.Volatility; SmileDeltaParameters smileFromVolatility = SmileDeltaParameters.of(TIME_TO_EXPIRY, DELTA, volatility, PARAMETER_METADATA); assertEquals(smileFromVolatility, SMILE, "Smile by delta: constructor"); }
/// <summary> /// Tests the getters. /// </summary> public virtual void getter() { assertEquals(SMILE.Expiry, TIME_TO_EXPIRY, "Smile by delta: time to expiry"); assertEquals(SMILE.Delta, DELTA, "Smile by delta: delta"); SmileDeltaParameters smile2 = SmileDeltaParameters.of(TIME_TO_EXPIRY, DELTA, SMILE.Volatility); assertEquals(smile2.Volatility, SMILE.Volatility, "Smile by delta: volatility"); }
/// <summary> /// Tests the extrapolation above the last expiry. /// </summary> public virtual void volatilityAboveLastExpiry() { double forward = 1.40; double timeToExpiry = 5.00; double strike = 1.45; SmileDeltaParameters smile = SmileDeltaParameters.of(timeToExpiry, ATM.toArray()[NB_EXP - 1], DELTA, DoubleArray.copyOf(RISK_REVERSAL.toArray()[NB_EXP - 1]), DoubleArray.copyOf(STRANGLE.toArray()[NB_EXP - 1])); DoubleArray strikes = smile.strike(forward); DoubleArray vol = smile.Volatility; double volExpected = INTERPOLATOR_STRIKE.bind(strikes, vol, FLAT, FLAT).interpolate(strike); double volComputed = SMILE_TERM.volatility(timeToExpiry, strike, forward); assertEquals(volComputed, volExpected, TOLERANCE_VOL, "Smile by delta term structure: vol interpolation on strike"); }
/// <summary> /// Tests the interpolation and its derivative with respect to the data by comparison to finite difference. /// </summary> public virtual void volatilityAjoint() { double forward = 1.40; double[] timeToExpiry = new double[] { 0.75, 1.00, 2.50 }; double[] strike = new double[] { 1.50, 1.70, 2.20 }; double[] tolerance = new double[] { 3e-2, 1e-1, 1e-5 }; int nbTest = strike.Length; double shift = 0.00001; for (int looptest = 0; looptest < nbTest; looptest++) { double vol = SMILE_TERM.volatility(timeToExpiry[looptest], strike[looptest], forward); //JAVA TO C# CONVERTER NOTE: The following call to the 'RectangularArrays' helper class reproduces the rectangular array initialization that is automatic in Java: //ORIGINAL LINE: double[][] bucketTest = new double[TIME_TO_EXPIRY.size()][2 * DELTA.size() + 1]; double[][] bucketTest = RectangularArrays.ReturnRectangularDoubleArray(TIME_TO_EXPIRY.size(), 2 * DELTA.size() + 1); VolatilityAndBucketedSensitivities volComputed = SMILE_TERM.volatilityAndSensitivities(timeToExpiry[looptest], strike[looptest], forward); DoubleMatrix bucketSensi = volComputed.Sensitivities; assertEquals(volComputed.Volatility, vol, 1.0E-10, "Smile by delta term structure: volatility adjoint"); SmileDeltaParameters[] volData = new SmileDeltaParameters[TIME_TO_EXPIRY.size()]; double[] volBumped = new double[2 * DELTA.size() + 1]; for (int loopexp = 0; loopexp < TIME_TO_EXPIRY.size(); loopexp++) { for (int loopsmile = 0; loopsmile < 2 * DELTA.size() + 1; loopsmile++) { Array.Copy(SMILE_TERM.VolatilityTerm.toArray(), 0, volData, 0, TIME_TO_EXPIRY.size()); Array.Copy(SMILE_TERM.VolatilityTerm.get(loopexp).Volatility.toArray(), 0, volBumped, 0, 2 * DELTA.size() + 1); volBumped[loopsmile] += shift; volData[loopexp] = SmileDeltaParameters.of(TIME_TO_EXPIRY.get(loopexp), DELTA, DoubleArray.copyOf(volBumped)); InterpolatedStrikeSmileDeltaTermStructure smileTermBumped = InterpolatedStrikeSmileDeltaTermStructure.of(ImmutableList.copyOf(volData), ACT_360); bucketTest[loopexp][loopsmile] = (smileTermBumped.volatility(timeToExpiry[looptest], strike[looptest], forward) - volComputed.Volatility) / shift; assertEquals(bucketSensi.get(loopexp, loopsmile), bucketTest[loopexp][loopsmile], tolerance[looptest], "Smile by delta term structure: (test: " + looptest + ") volatility bucket sensitivity " + loopexp + " - " + loopsmile); } } } }
//------------------------------------------------------------------------- // bumping a node point at (nodeExpiry, nodeDelta) private double nodeSensitivity(BlackFxOptionSmileVolatilities provider, CurrencyPair pair, ZonedDateTime expiry, double strike, double forward, double nodeExpiry, double nodeDelta) { double strikeMod = provider.CurrencyPair.Equals(pair) ? strike : 1.0 / strike; double forwardMod = provider.CurrencyPair.Equals(pair) ? forward : 1.0 / forward; InterpolatedStrikeSmileDeltaTermStructure smileTerm = (InterpolatedStrikeSmileDeltaTermStructure)provider.Smile; double[] times = smileTerm.Expiries.toArray(); int nTimes = times.Length; SmileDeltaParameters[] volTermUp = new SmileDeltaParameters[nTimes]; SmileDeltaParameters[] volTermDw = new SmileDeltaParameters[nTimes]; int deltaIndex = -1; for (int i = 0; i < nTimes; ++i) { DoubleArray deltas = smileTerm.VolatilityTerm.get(i).Delta; int nDeltas = deltas.size(); int nDeltasTotal = 2 * nDeltas + 1; double[] deltasTotal = new double[nDeltasTotal]; deltasTotal[nDeltas] = 0.5d; for (int j = 0; j < nDeltas; ++j) { deltasTotal[j] = 1d - deltas.get(j); deltasTotal[2 * nDeltas - j] = deltas.get(j); } double[] volsUp = smileTerm.VolatilityTerm.get(i).Volatility.toArray(); double[] volsDw = smileTerm.VolatilityTerm.get(i).Volatility.toArray(); if (Math.Abs(times[i] - nodeExpiry) < TOLERANCE) { for (int j = 0; j < nDeltasTotal; ++j) { if (Math.Abs(deltasTotal[j] - nodeDelta) < TOLERANCE) { deltaIndex = j; volsUp[j] += EPS; volsDw[j] -= EPS; } } } volTermUp[i] = SmileDeltaParameters.of(times[i], deltas, DoubleArray.copyOf(volsUp)); volTermDw[i] = SmileDeltaParameters.of(times[i], deltas, DoubleArray.copyOf(volsDw)); } InterpolatedStrikeSmileDeltaTermStructure smileTermUp = InterpolatedStrikeSmileDeltaTermStructure.of(ImmutableList.copyOf(volTermUp), ACT_365F); InterpolatedStrikeSmileDeltaTermStructure smileTermDw = InterpolatedStrikeSmileDeltaTermStructure.of(ImmutableList.copyOf(volTermDw), ACT_365F); BlackFxOptionSmileVolatilities provUp = BlackFxOptionSmileVolatilities.of(NAME, CURRENCY_PAIR, VAL_DATE_TIME, smileTermUp); BlackFxOptionSmileVolatilities provDw = BlackFxOptionSmileVolatilities.of(NAME, CURRENCY_PAIR, VAL_DATE_TIME, smileTermDw); double volUp = provUp.volatility(pair, expiry, strike, forward); double volDw = provDw.volatility(pair, expiry, strike, forward); double totalSensi = 0.5 * (volUp - volDw) / EPS; double expiryTime = provider.relativeTime(expiry); SmileDeltaParameters singleSmile = smileTerm.smileForExpiry(expiryTime); double[] strikesUp = singleSmile.strike(forwardMod).toArray(); double[] strikesDw = strikesUp.Clone(); double[] vols = singleSmile.Volatility.toArray(); strikesUp[deltaIndex] += EPS; strikesDw[deltaIndex] -= EPS; double volStrikeUp = LINEAR.bind(DoubleArray.ofUnsafe(strikesUp), DoubleArray.ofUnsafe(vols), FLAT, FLAT).interpolate(strikeMod); double volStrikeDw = LINEAR.bind(DoubleArray.ofUnsafe(strikesDw), DoubleArray.ofUnsafe(vols), FLAT, FLAT).interpolate(strikeMod); double sensiStrike = 0.5 * (volStrikeUp - volStrikeDw) / EPS; SmileDeltaParameters singleSmileUp = smileTermUp.smileForExpiry(expiryTime); double strikeUp = singleSmileUp.strike(forwardMod).get(deltaIndex); SmileDeltaParameters singleSmileDw = smileTermDw.smileForExpiry(expiryTime); double strikeDw = singleSmileDw.strike(forwardMod).get(deltaIndex); double sensiVol = 0.5 * (strikeUp - strikeDw) / EPS; return(totalSensi - sensiStrike * sensiVol); }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test(expectedExceptions = IllegalArgumentException.class) public void testStrangleLength() public virtual void testStrangleLength() { SmileDeltaParameters.of(TIME_TO_EXPIRY, ATM, DELTA, RISK_REVERSAL, DoubleArray.filled(3)); }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test(expectedExceptions = IllegalArgumentException.class) public void testRRLength() public virtual void testRRLength() { SmileDeltaParameters.of(TIME_TO_EXPIRY, ATM, DELTA, DoubleArray.filled(3), STRANGLE); }
//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes: //ORIGINAL LINE: @Test(expectedExceptions = IllegalArgumentException.class) public void testNullDelta() public virtual void testNullDelta() { SmileDeltaParameters.of(TIME_TO_EXPIRY, ATM, null, RISK_REVERSAL, STRANGLE); }