public override void calculate() { // cache lookup for precalculated results for (int i = 0; i < cachedArgs2results_.Count; ++i) { if (cachedArgs2results_[i].first.exercise.type() == arguments_.exercise.type() && cachedArgs2results_[i].first.exercise.dates() == arguments_.exercise.dates()) { PlainVanillaPayoff p1 = arguments_.payoff as PlainVanillaPayoff; PlainVanillaPayoff p2 = cachedArgs2results_[i].first.payoff as PlainVanillaPayoff; if (p1 != null && p1.strike() == p2.strike() && p1.optionType() == p2.optionType()) { Utils.QL_REQUIRE(arguments_.cashFlow.empty(), () => "multiple strikes engine does " + "not work with discrete dividends"); results_ = cachedArgs2results_[i].second; return; } } } HestonProcess process = model_.currentLink().process(); FdmHestonSolver solver = new FdmHestonSolver( new Handle <HestonProcess>(process), getSolverDesc(1.5), schemeDesc_, new Handle <FdmQuantoHelper>(), leverageFct_); double v0 = process.v0(); double spot = process.s0().currentLink().value(); results_.value = solver.valueAt(spot, v0); results_.delta = solver.deltaAt(spot, v0); results_.gamma = solver.gammaAt(spot, v0); results_.theta = solver.thetaAt(spot, v0); cachedArgs2results_ = new InitializedList <Pair <DividendVanillaOption.Arguments, DividendVanillaOption.Results> >(strikes_.Count); StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; for (int i = 0; i < strikes_.Count; ++i) { cachedArgs2results_[i] = new Pair <DividendVanillaOption.Arguments, OneAssetOption.Results>(new DividendVanillaOption.Arguments(), new OneAssetOption.Results()); cachedArgs2results_[i].first.exercise = arguments_.exercise; cachedArgs2results_[i].first.payoff = new PlainVanillaPayoff(payoff.optionType(), strikes_[i]); double d = payoff.strike() / strikes_[i]; cachedArgs2results_[i].second.value = solver.valueAt(spot * d, v0) / d; cachedArgs2results_[i].second.delta = solver.deltaAt(spot * d, v0); cachedArgs2results_[i].second.gamma = solver.gammaAt(spot * d, v0) * d; cachedArgs2results_[i].second.theta = solver.thetaAt(spot * d, v0) / d; } }
public override void calculate() { // 1. Mesher HestonProcess process = model_.currentLink().process(); double maturity = process.time(arguments_.exercise.lastDate()); // 1.1 The variance mesher int tGridMin = 5; int tGridAvgSteps = Math.Max(tGridMin, tGrid_ / 50); FdmHestonLocalVolatilityVarianceMesher varianceMesher = new FdmHestonLocalVolatilityVarianceMesher(vGrid_, process, leverageFct_, maturity, tGridAvgSteps); // 1.2 the equity mesher StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; double?xMin = null; double?xMax = null; if (arguments_.barrierType == Barrier.Type.DownIn || arguments_.barrierType == Barrier.Type.DownOut) { xMin = Math.Log(arguments_.barrier.Value); } if (arguments_.barrierType == Barrier.Type.UpIn || arguments_.barrierType == Barrier.Type.UpOut) { xMax = Math.Log(arguments_.barrier.Value); } Fdm1dMesher equityMesher = new FdmBlackScholesMesher(xGrid_, FdmBlackScholesMesher.processHelper(process.s0(), process.dividendYield(), process.riskFreeRate(), varianceMesher.volaEstimate()), maturity, payoff.strike(), xMin, xMax, 0.0001, 1.5, new Pair <double?, double?>(), arguments_.cashFlow); FdmMesher mesher = new FdmMesherComposite(equityMesher, varianceMesher); // 2. Calculator StrikedTypePayoff rebatePayoff = new CashOrNothingPayoff(Option.Type.Call, 0.0, arguments_.rebate.Value); FdmInnerValueCalculator calculator = new FdmLogInnerValue(rebatePayoff, mesher, 0); // 3. Step conditions Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "only european style option are supported"); FdmStepConditionComposite conditions = FdmStepConditionComposite.vanillaComposite( arguments_.cashFlow, arguments_.exercise, mesher, calculator, process.riskFreeRate().currentLink().referenceDate(), process.riskFreeRate().currentLink().dayCounter()); // 4. Boundary conditions FdmBoundaryConditionSet boundaries = new FdmBoundaryConditionSet(); if (arguments_.barrierType == Barrier.Type.DownIn || arguments_.barrierType == Barrier.Type.DownOut) { boundaries.Add(new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0, FdmDirichletBoundary.Side.Lower)); } if (arguments_.barrierType == Barrier.Type.UpIn || arguments_.barrierType == Barrier.Type.UpOut) { boundaries.Add(new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0, FdmDirichletBoundary.Side.Upper)); } // 5. Solver FdmSolverDesc solverDesc = new FdmSolverDesc(); solverDesc.mesher = mesher; solverDesc.bcSet = boundaries; solverDesc.condition = conditions; solverDesc.calculator = calculator; solverDesc.maturity = maturity; solverDesc.dampingSteps = dampingSteps_; solverDesc.timeSteps = tGrid_; FdmHestonSolver solver = new FdmHestonSolver( new Handle <HestonProcess>(process), solverDesc, schemeDesc_, new Handle <FdmQuantoHelper>(), leverageFct_); double spot = process.s0().currentLink().value(); results_.value = solver.valueAt(spot, process.v0()); results_.delta = solver.deltaAt(spot, process.v0()); results_.gamma = solver.gammaAt(spot, process.v0()); results_.theta = solver.thetaAt(spot, process.v0()); }
public override void calculate() { // 1. Mesher HestonProcess process = model_.currentLink().process(); double maturity = process.time(arguments_.exercise.lastDate()); // 1.1 Variance Mesher int tGridMin = 5; int tGridAvgSteps = Math.Max(tGridMin, tGrid_ / 50); FdmHestonLocalVolatilityVarianceMesher varianceMesher = new FdmHestonLocalVolatilityVarianceMesher(vGrid_, process, leverageFct_, maturity, tGridAvgSteps); // 1.2 Equity Mesher StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; double?xMin = null; double?xMax = null; if (arguments_.barrierType == Barrier.Type.DownIn || arguments_.barrierType == Barrier.Type.DownOut) { xMin = Math.Log(arguments_.barrier.Value); } if (arguments_.barrierType == Barrier.Type.UpIn || arguments_.barrierType == Barrier.Type.UpOut) { xMax = Math.Log(arguments_.barrier.Value); } Fdm1dMesher equityMesher = new FdmBlackScholesMesher(xGrid_, FdmBlackScholesMesher.processHelper(process.s0(), process.dividendYield(), process.riskFreeRate(), varianceMesher.volaEstimate()), maturity, payoff.strike(), xMin, xMax, 0.0001, 1.5, new Pair <double?, double?>(), arguments_.cashFlow); FdmMesher mesher = new FdmMesherComposite(equityMesher, varianceMesher); // 2. Calculator FdmInnerValueCalculator calculator = new FdmLogInnerValue(payoff, mesher, 0); // 3. Step conditions List <IStepCondition <Vector> > stepConditions = new List <IStepCondition <Vector> >(); List <List <double> > stoppingTimes = new List <List <double> >(); // 3.1 Step condition if discrete dividends FdmDividendHandler dividendCondition = new FdmDividendHandler(arguments_.cashFlow, mesher, process.riskFreeRate().currentLink().referenceDate(), process.riskFreeRate().currentLink().dayCounter(), 0); if (!arguments_.cashFlow.empty()) { stepConditions.Add(dividendCondition); stoppingTimes.Add(dividendCondition.dividendTimes()); } Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "only european style option are supported"); FdmStepConditionComposite conditions = new FdmStepConditionComposite(stoppingTimes, stepConditions); // 4. Boundary conditions FdmBoundaryConditionSet boundaries = new FdmBoundaryConditionSet(); if (arguments_.barrierType == Barrier.Type.DownIn || arguments_.barrierType == Barrier.Type.DownOut) { boundaries.Add( new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0, FdmDirichletBoundary.Side.Lower)); } if (arguments_.barrierType == Barrier.Type.UpIn || arguments_.barrierType == Barrier.Type.UpOut) { boundaries.Add( new FdmDirichletBoundary(mesher, arguments_.rebate.Value, 0, FdmDirichletBoundary.Side.Upper)); } // 5. Solver FdmSolverDesc solverDesc = new FdmSolverDesc(); solverDesc.mesher = mesher; solverDesc.bcSet = boundaries; solverDesc.condition = conditions; solverDesc.calculator = calculator; solverDesc.maturity = maturity; solverDesc.dampingSteps = dampingSteps_; solverDesc.timeSteps = tGrid_; FdmHestonSolver solver = new FdmHestonSolver( new Handle <HestonProcess>(process), solverDesc, schemeDesc_, new Handle <FdmQuantoHelper>(), leverageFct_); double spot = process.s0().currentLink().value(); results_.value = solver.valueAt(spot, process.v0()); results_.delta = solver.deltaAt(spot, process.v0()); results_.gamma = solver.gammaAt(spot, process.v0()); results_.theta = solver.thetaAt(spot, process.v0()); // 6. Calculate vanilla option and rebate for in-barriers if (arguments_.barrierType == Barrier.Type.DownIn || arguments_.barrierType == Barrier.Type.UpIn) { // Cast the payoff StrikedTypePayoff castedPayoff = arguments_.payoff as StrikedTypePayoff; // Calculate the vanilla option DividendVanillaOption vanillaOption = new DividendVanillaOption(castedPayoff, arguments_.exercise, dividendCondition.dividendDates(), dividendCondition.dividends()); vanillaOption.setPricingEngine( new FdHestonVanillaEngine( model_, tGrid_, xGrid_, vGrid_, dampingSteps_, schemeDesc_)); // Calculate the rebate value DividendBarrierOption rebateOption = new DividendBarrierOption(arguments_.barrierType, arguments_.barrier.Value, arguments_.rebate.Value, castedPayoff, arguments_.exercise, dividendCondition.dividendDates(), dividendCondition.dividends()); int xGridMin = 20; int vGridMin = 10; int rebateDampingSteps = (dampingSteps_ > 0) ? Math.Min(1, dampingSteps_ / 2) : 0; rebateOption.setPricingEngine(new FdHestonRebateEngine( model_, tGrid_, Math.Max(xGridMin, xGrid_ / 4), Math.Max(vGridMin, vGrid_ / 4), rebateDampingSteps, schemeDesc_)); results_.value = vanillaOption.NPV() + rebateOption.NPV() - results_.value; results_.delta = vanillaOption.delta() + rebateOption.delta() - results_.delta; results_.gamma = vanillaOption.gamma() + rebateOption.gamma() - results_.gamma; results_.theta = vanillaOption.theta() + rebateOption.theta() - results_.theta; } }