VanillaOption makeOption(StrikedTypePayoff payoff, Exercise exercise, Quote u, YieldTermStructure q, YieldTermStructure r, BlackVolTermStructure vol, EngineType engineType, int binomialSteps, int samples) { GeneralizedBlackScholesProcess stochProcess = makeProcess(u, q, r, vol); IPricingEngine engine; switch (engineType) { case EngineType.Analytic: engine = new AnalyticEuropeanEngine(stochProcess); break; case EngineType.JR: engine = new BinomialVanillaEngine<JarrowRudd>(stochProcess, binomialSteps); break; case EngineType.CRR: engine = new BinomialVanillaEngine<CoxRossRubinstein>(stochProcess, binomialSteps); break; case EngineType.EQP: engine = new BinomialVanillaEngine<AdditiveEQPBinomialTree>(stochProcess, binomialSteps); break; case EngineType.TGEO: engine = new BinomialVanillaEngine<Trigeorgis>(stochProcess, binomialSteps); break; case EngineType.TIAN: engine = new BinomialVanillaEngine<Tian>(stochProcess, binomialSteps); break; case EngineType.LR: engine = new BinomialVanillaEngine<LeisenReimer>(stochProcess, binomialSteps); break; case EngineType.JOSHI: engine = new BinomialVanillaEngine<Joshi4>(stochProcess, binomialSteps); break; case EngineType.FiniteDifferences: engine = new FDEuropeanEngine(stochProcess, binomialSteps, samples); break; case EngineType.Integral: engine = new IntegralEngine(stochProcess); break; //case EngineType.PseudoMonteCarlo: // engine = MakeMCEuropeanEngine<PseudoRandom>(stochProcess) // .withSteps(1) // .withSamples(samples) // .withSeed(42); // break; //case EngineType.QuasiMonteCarlo: // engine = MakeMCEuropeanEngine<LowDiscrepancy>(stochProcess) // .withSteps(1) // .withSamples(samples); // break; default: throw new ArgumentException("unknown engine type"); } VanillaOption option = new EuropeanOption(payoff, exercise); option.setPricingEngine(engine); return option; }
public override void calculate() { PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff; Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given"); Utils.QL_REQUIRE(payoff.strike() > 0.0, () => "strike must be positive"); double K = payoff.strike(); double S = process_.x0(); Utils.QL_REQUIRE(S >= 0.0, () => "negative or null underlying given"); Utils.QL_REQUIRE(!triggered(S), () => "barrier touched"); DoubleBarrier.Type barrierType = arguments_.barrierType; Utils.QL_REQUIRE(barrierType == DoubleBarrier.Type.KnockOut || barrierType == DoubleBarrier.Type.KnockIn, () => "only KnockIn and KnockOut options supported"); double L = arguments_.barrier_lo.GetValueOrDefault(); double H = arguments_.barrier_hi.GetValueOrDefault(); double K_up = Math.Min(H, K); double K_down = Math.Max(L, K); double T = residualTime(); double rd = riskFreeRate(); double dd = riskFreeDiscount(); double rf = dividendYield(); double df = dividendDiscount(); double vol = volatility(); double mu = rd - rf - vol * vol / 2.0; double sgn = mu > 0 ? 1.0 :(mu < 0 ? -1.0: 0.0); //rebate double R_L = arguments_.rebate.GetValueOrDefault(); double R_H = arguments_.rebate.GetValueOrDefault(); //european option EuropeanOption europeanOption = new EuropeanOption(payoff, arguments_.exercise); IPricingEngine analyticEuropeanEngine = new AnalyticEuropeanEngine(process_); europeanOption.setPricingEngine(analyticEuropeanEngine); double european = europeanOption.NPV(); double barrierOut = 0; double rebateIn = 0; for (int n = -series_; n < series_; n++) { double d1 = D(S / H * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T); double d2 = d1 - vol * Math.Sqrt(T); double g1 = D(H / S * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T); double g2 = g1 - vol * Math.Sqrt(T); double h1 = D(S / H * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T); double h2 = h1 - vol * Math.Sqrt(T); double k1 = D(L / S * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T); double k2 = k1 - vol * Math.Sqrt(T); double d1_down = D(S / K_down * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T); double d2_down = d1_down - vol * Math.Sqrt(T); double d1_up = D(S / K_up * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T); double d2_up = d1_up - vol * Math.Sqrt(T); double k1_down = D((H * H) / (K_down * S) * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T); double k2_down = k1_down - vol * Math.Sqrt(T); double k1_up = D((H * H) / (K_up * S) * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T); double k2_up = k1_up - vol * Math.Sqrt(T); if (payoff.optionType() == Option.Type.Call) { barrierOut += Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) * (df * S * Math.Pow(L / H, 2.0 * n) * (f_.value(d1_down) - f_.value(d1)) - dd * K * (f_.value(d2_down) - f_.value(d2)) - df * Math.Pow(L / H, 2.0 * n) * H * H / S * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(k1_down) - f_.value(k1)) + dd * K * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(k2_down) - f_.value(k2))); } else if (payoff.optionType() == Option.Type.Put) { barrierOut += Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) * (dd * K * (f_.value(h2) - f_.value(d2_up)) - df * S * Math.Pow(L / H, 2.0 * n) * (f_.value(h1) - f_.value(d1_up)) - dd * K * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(g2) - f_.value(k2_up)) + df * Math.Pow(L / H, 2.0 * n) * H * H / S * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(g1) - f_.value(k1_up))); } else { Utils.QL_FAIL("option type not recognized"); } double v1 = D(H / S * Math.Pow(H / L, 2.0 * n), -mu, vol, T); double v2 = D(H / S * Math.Pow(H / L, 2.0 * n), mu, vol, T); double v3 = D(S / L * Math.Pow(H / L, 2.0 * n), -mu, vol, T); double v4 = D(S / L * Math.Pow(H / L, 2.0 * n), mu, vol, T); rebateIn += dd * R_H * sgn * (Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) * f_.value(sgn * v1) - Math.Pow(H / S, 2.0 * mu / (vol * vol)) * f_.value(-sgn * v2)) + dd * R_L * sgn * (Math.Pow(L / S, 2.0 * mu / (vol * vol)) * f_.value(-sgn * v3) - Math.Pow(H / L, 2.0 * n * mu / (vol * vol)) * f_.value(sgn * v4)); } //rebate paid at maturity if (barrierType == DoubleBarrier.Type.KnockOut) { results_.value = barrierOut; } else { results_.value = european - barrierOut; } results_.additionalResults["vanilla"] = european; results_.additionalResults["barrierOut"] = barrierOut; results_.additionalResults["barrierIn"] = european - barrierOut; }