public static FdmStepConditionComposite vanillaComposite(DividendSchedule cashFlow, Exercise exercise, FdmMesher mesher, FdmInnerValueCalculator calculator, Date refDate, DayCounter dayCounter) { List <List <double> > stoppingTimes = new List <List <double> >(); List <IStepCondition <Vector> > stepConditions = new List <IStepCondition <Vector> >(); if (!cashFlow.empty()) { FdmDividendHandler dividendCondition = new FdmDividendHandler(cashFlow, mesher, refDate, dayCounter, 0); stepConditions.Add(dividendCondition); stoppingTimes.Add(dividendCondition.dividendTimes()); } Utils.QL_REQUIRE(exercise.type() == Exercise.Type.American || exercise.type() == Exercise.Type.European || exercise.type() == Exercise.Type.Bermudan, () => "exercise type is not supported"); if (exercise.type() == Exercise.Type.American) { stepConditions.Add(new FdmAmericanStepCondition(mesher, calculator)); } else if (exercise.type() == Exercise.Type.Bermudan) { FdmBermudanStepCondition bermudanCondition = new FdmBermudanStepCondition(exercise.dates(), refDate, dayCounter, mesher, calculator); stepConditions.Add(bermudanCondition); stoppingTimes.Add(bermudanCondition.exerciseTimes()); } return(new FdmStepConditionComposite(stoppingTimes, stepConditions)); }
public override void calculate() { // 1. Mesher StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; double maturity = process_.time(arguments_.exercise.lastDate()); 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_, process_, maturity, payoff.strike(), xMin, xMax, 0.0001, 1.5, new Pair <double?, double?>(), arguments_.cashFlow); FdmMesher mesher = new FdmMesherComposite(equityMesher); // 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_; FdmBlackScholesSolver solver = new FdmBlackScholesSolver( new Handle <GeneralizedBlackScholesProcess>(process_), payoff.strike(), solverDesc, schemeDesc_, localVol_, illegalLocalVolOverwrite_); double spot = process_.x0(); results_.value = solver.valueAt(spot); results_.delta = solver.deltaAt(spot); results_.gamma = solver.gammaAt(spot); results_.theta = solver.thetaAt(spot); // 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 FdBlackScholesVanillaEngine( process_, tGrid_, xGrid_, 0, // dampingSteps schemeDesc_, localVol_, illegalLocalVolOverwrite_)); // Calculate the rebate value DividendBarrierOption rebateOption = new DividendBarrierOption(arguments_.barrierType, arguments_.barrier.Value, arguments_.rebate.Value, castedPayoff, arguments_.exercise, dividendCondition.dividendDates(), dividendCondition.dividends()); int min_grid_size = 50; int rebateDampingSteps = (dampingSteps_ > 0) ? Math.Min(1, dampingSteps_ / 2) : 0; rebateOption.setPricingEngine(new FdBlackScholesRebateEngine( process_, tGrid_, Math.Max(min_grid_size, xGrid_ / 5), rebateDampingSteps, schemeDesc_, localVol_, illegalLocalVolOverwrite_)); 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; } }