public void testAnalyticContinuousGeometricAveragePrice() { //("Testing analytic continuous geometric average-price Asians..."); // data from "Option Pricing Formulas", Haug, pag.96-97 DayCounter dc = new Actual360(); Date today = Date.Today; SimpleQuote spot = new SimpleQuote(80.0); SimpleQuote qRate = new SimpleQuote(-0.03); YieldTermStructure qTS = Utilities.flatRate(today, qRate, dc); SimpleQuote rRate = new SimpleQuote(0.05); YieldTermStructure rTS = Utilities.flatRate(today, rRate, dc); SimpleQuote vol = new SimpleQuote(0.20); BlackVolTermStructure volTS = Utilities.flatVol(today, vol, dc); BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(new Handle<Quote>(spot), new Handle<YieldTermStructure>(qTS), new Handle<YieldTermStructure>(rTS), new Handle<BlackVolTermStructure>(volTS)); IPricingEngine engine = new AnalyticContinuousGeometricAveragePriceAsianEngine(stochProcess); Average.Type averageType = Average.Type.Geometric; Option.Type type = Option.Type.Put; double strike = 85.0; Date exerciseDate = today + 90; int pastFixings = 0; //Null<int>(); double runningAccumulator = 0.0; //Null<Real>(); StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike); Exercise exercise = new EuropeanExercise(exerciseDate); ContinuousAveragingAsianOption option = new ContinuousAveragingAsianOption(averageType, payoff, exercise); option.setPricingEngine(engine); double calculated = option.NPV(); double expected = 4.6922; double tolerance = 1.0e-4; if (Math.Abs(calculated - expected) > tolerance) { REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings, new List<Date>(), payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, tolerance); } // trying to approximate the continuous version with the discrete version runningAccumulator = 1.0; pastFixings = 0; List<Date> fixingDates = new InitializedList<Date>(exerciseDate - today + 1); for (int i = 0; i < fixingDates.Count; i++) { fixingDates[i] = today + i; } IPricingEngine engine2 = new AnalyticDiscreteGeometricAveragePriceAsianEngine(stochProcess); DiscreteAveragingAsianOption option2 = new DiscreteAveragingAsianOption(averageType, runningAccumulator, pastFixings, fixingDates, payoff, exercise); option2.setPricingEngine(engine2); calculated = option2.NPV(); tolerance = 3.0e-3; /*if (Math.Abs(calculated - expected) > tolerance) { REPORT_FAILURE("value", averageType, runningAccumulator, pastFixings, fixingDates, payoff, exercise, spot.value(), qRate.value(), rRate.value(), today, vol.value(), expected, calculated, tolerance); }*/ }
public void testAnalyticContinuousGeometricAveragePriceGreeks() { //BOOST_MESSAGE("Testing analytic continuous geometric average-price Asian " // "greeks..."); //std::map<std::string,Real> Dictionary<string, double> calculated, expected, tolerance; calculated = new Dictionary<string, double>(6); expected = new Dictionary<string, double>(6); tolerance = new Dictionary<string, double>(6); 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[] underlyings = { 100.0 }; double[] strikes = { 90.0, 100.0, 110.0 }; double[] qRates = { 0.04, 0.05, 0.06 }; double[] rRates = { 0.01, 0.05, 0.15 }; int[] lengths = { 1, 2 }; 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 process = new BlackScholesMertonProcess(new Handle<Quote>(spot), qTS, rTS, volTS); for (int i = 0; i < types.Length; i++) { for (int j = 0; j < strikes.Length; j++) { for (int k = 0; k < lengths.Length; k++) { EuropeanExercise maturity = //new EuropeanExercise(today + lengths[k]*Years); new EuropeanExercise(today + new Period(lengths[k], TimeUnit.Years)); PlainVanillaPayoff payoff = new PlainVanillaPayoff(types[i], strikes[j]); IPricingEngine engine = new AnalyticContinuousGeometricAveragePriceAsianEngine(process); ContinuousAveragingAsianOption option = new ContinuousAveragingAsianOption(Average.Type.Geometric, payoff, maturity); option.setPricingEngine(engine); int pastFixings = 0; //Null<Size>(); double runningAverage = 0; //Null<Real>(); 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 foreach (KeyValuePair<string, double> kvp in calculated) { string greek = kvp.Key; double expct = expected[greek], calcl = calculated[greek], tol = tolerance[greek]; double error = Utilities.relativeError(expct, calcl, u); if (error > tol) { REPORT_FAILURE(greek, Average.Type.Geometric, runningAverage, pastFixings, new List<Date>(), payoff, maturity, u, q, r, today, v, expct, calcl, tol); } } } } } } } } } } }