public void testGreeksInitialization() { // Testing forward option greeks initialization DayCounter dc = new Actual360(); SavedSettings backup = new SavedSettings(); Date today = Date.Today; Settings.setEvaluationDate(today); SimpleQuote spot = new SimpleQuote(100.0); SimpleQuote qRate = new SimpleQuote(0.04); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc)); SimpleQuote rRate = new SimpleQuote(0.01); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc)); SimpleQuote vol = new SimpleQuote(0.11); Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc)); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS); IPricingEngine engine = new ForwardVanillaEngine(stochProcess, process => new TestBinomialEngine(process)); Date exDate = today + new Period(1, TimeUnit.Years); Exercise exercise = new EuropeanExercise(exDate); Date reset = today + new Period(6, TimeUnit.Months); StrikedTypePayoff payoff = new PlainVanillaPayoff(Option.Type.Call, 0.0); ForwardVanillaOption option = new ForwardVanillaOption(0.9, reset, payoff, exercise); option.setPricingEngine(engine); IPricingEngine ctrlengine = new TestBinomialEngine(stochProcess); VanillaOption ctrloption = new VanillaOption(payoff, exercise); ctrloption.setPricingEngine(ctrlengine); double?delta = 0; try { delta = ctrloption.delta(); } catch (Exception) { // if normal option can't calculate delta, // nor should forward try { delta = option.delta(); } catch (Exception) { delta = null; } Utils.QL_REQUIRE(delta == null, () => "Forward delta invalid"); } double?rho = 0; try { rho = ctrloption.rho(); } catch (Exception) { // if normal option can't calculate rho, // nor should forward try { rho = option.rho(); } catch (Exception) { rho = null; } Utils.QL_REQUIRE(rho == null, () => "Forward rho invalid"); } double?divRho = 0; try { divRho = ctrloption.dividendRho(); } catch (Exception) { // if normal option can't calculate divRho, // nor should forward try { divRho = option.dividendRho(); } catch (Exception) { divRho = null; } Utils.QL_REQUIRE(divRho == null, () => "Forward dividendRho invalid"); } double?vega = 0; try { vega = ctrloption.vega(); } catch (Exception) { // if normal option can't calculate vega, // nor should forward try { vega = option.vega(); } catch (Exception) { vega = null; } Utils.QL_REQUIRE(vega == null, () => "Forward vega invalid"); } }
private void testForwardGreeks(Type engine_type) { Dictionary <String, double> calculated = new Dictionary <string, double>(), expected = new Dictionary <string, double>(), tolerance = new Dictionary <string, double>(); tolerance["delta"] = 1.0e-5; tolerance["gamma"] = 1.0e-5; tolerance["theta"] = 1.0e-5; tolerance["rho"] = 1.0e-5; tolerance["divRho"] = 1.0e-5; tolerance["vega"] = 1.0e-5; Option.Type[] types = { Option.Type.Call, Option.Type.Put }; double[] moneyness = { 0.9, 1.0, 1.1 }; double[] underlyings = { 100.0 }; double[] qRates = { 0.04, 0.05, 0.06 }; double[] rRates = { 0.01, 0.05, 0.15 }; int[] lengths = { 1, 2 }; int[] startMonths = { 6, 9 }; double[] vols = { 0.11, 0.50, 1.20 }; DayCounter dc = new Actual360(); Date today = Date.Today; Settings.setEvaluationDate(today); SimpleQuote spot = new SimpleQuote(0.0); SimpleQuote qRate = new SimpleQuote(0.0); Handle <YieldTermStructure> qTS = new Handle <YieldTermStructure>(Utilities.flatRate(qRate, dc)); SimpleQuote rRate = new SimpleQuote(0.0); Handle <YieldTermStructure> rTS = new Handle <YieldTermStructure>(Utilities.flatRate(rRate, dc)); SimpleQuote vol = new SimpleQuote(0.0); Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(Utilities.flatVol(vol, dc)); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle <Quote>(spot), qTS, rTS, volTS); IPricingEngine engine = engine_type == typeof(ForwardVanillaEngine) ? new ForwardVanillaEngine(stochProcess, process => new AnalyticEuropeanEngine(process)) : new ForwardPerformanceVanillaEngine(stochProcess, process => new AnalyticEuropeanEngine(process)); for (int i = 0; i < types.Length; i++) { for (int j = 0; j < moneyness.Length; j++) { for (int k = 0; k < lengths.Length; k++) { for (int h = 0; h < startMonths.Length; h++) { Date exDate = today + new Period(lengths[k], TimeUnit.Years); Exercise exercise = new EuropeanExercise(exDate); Date reset = today + new Period(startMonths[h], TimeUnit.Months); StrikedTypePayoff payoff = new PlainVanillaPayoff(types[i], 0.0); ForwardVanillaOption option = new ForwardVanillaOption(moneyness[j], reset, payoff, exercise); option.setPricingEngine(engine); for (int l = 0; l < underlyings.Length; l++) { for (int m = 0; m < qRates.Length; m++) { for (int n = 0; n < rRates.Length; n++) { for (int p = 0; p < vols.Length; p++) { double u = underlyings[l]; double q = qRates[m], r = rRates[n]; double v = vols[p]; spot.setValue(u); qRate.setValue(q); rRate.setValue(r); vol.setValue(v); double value = option.NPV(); calculated["delta"] = option.delta(); calculated["gamma"] = option.gamma(); calculated["theta"] = option.theta(); calculated["rho"] = option.rho(); calculated["divRho"] = option.dividendRho(); calculated["vega"] = option.vega(); if (value > spot.value() * 1.0e-5) { // perturb spot and get delta and gamma double du = u * 1.0e-4; spot.setValue(u + du); double value_p = option.NPV(), delta_p = option.delta(); spot.setValue(u - du); double value_m = option.NPV(), delta_m = option.delta(); spot.setValue(u); expected["delta"] = (value_p - value_m) / (2 * du); expected["gamma"] = (delta_p - delta_m) / (2 * du); // perturb rates and get rho and dividend rho double dr = r * 1.0e-4; rRate.setValue(r + dr); value_p = option.NPV(); rRate.setValue(r - dr); value_m = option.NPV(); rRate.setValue(r); expected["rho"] = (value_p - value_m) / (2 * dr); double dq = q * 1.0e-4; qRate.setValue(q + dq); value_p = option.NPV(); qRate.setValue(q - dq); value_m = option.NPV(); qRate.setValue(q); expected["divRho"] = (value_p - value_m) / (2 * dq); // perturb volatility and get vega double dv = v * 1.0e-4; vol.setValue(v + dv); value_p = option.NPV(); vol.setValue(v - dv); value_m = option.NPV(); vol.setValue(v); expected["vega"] = (value_p - value_m) / (2 * dv); // perturb date and get theta double dT = dc.yearFraction(today - 1, today + 1); Settings.setEvaluationDate(today - 1); value_m = option.NPV(); Settings.setEvaluationDate(today + 1); value_p = option.NPV(); Settings.setEvaluationDate(today); expected["theta"] = (value_p - value_m) / dT; // compare //std::map<std::string,double>::iterator it; foreach (KeyValuePair <string, double> it in calculated) { String greek = it.Key; double expct = expected [greek], calcl = calculated[greek], tol = tolerance [greek]; double error = Utilities.relativeError(expct, calcl, u); if (error > tol) { REPORT_FAILURE(greek, payoff, exercise, u, q, r, today, v, moneyness[j], reset, expct, calcl, error, tol); } } } } } } } } } } } }