public Fdm1DimSolver(FdmSolverDesc solverDesc, FdmSchemeDesc schemeDesc, FdmLinearOpComposite op) { solverDesc_ = solverDesc; schemeDesc_ = schemeDesc; op_ = op; thetaCondition_ = new FdmSnapshotCondition( 0.99 * Math.Min(1.0 / 365.0, solverDesc.condition.stoppingTimes().empty() ? solverDesc.maturity : solverDesc.condition.stoppingTimes().First())); conditions_ = FdmStepConditionComposite.joinConditions(thetaCondition_, solverDesc.condition); x_ = new InitializedList <double>(solverDesc.mesher.layout().size()); initialValues_ = new InitializedList <double>(solverDesc.mesher.layout().size()); resultValues_ = new Vector(solverDesc.mesher.layout().size()); FdmMesher mesher = solverDesc.mesher; FdmLinearOpLayout layout = mesher.layout(); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { initialValues_[iter.index()] = solverDesc_.calculator.avgInnerValue(iter, solverDesc.maturity); x_[iter.index()] = mesher.location(iter, 0); } }
public FdmHullWhiteSolver( Handle <HullWhite> model, FdmSolverDesc solverDesc, FdmSchemeDesc schemeDesc = null) { solverDesc_ = solverDesc; schemeDesc_ = schemeDesc ?? new FdmSchemeDesc().Hundsdorfer(); model_ = model; model_.registerWith(update); }
public override void calculate() { // 1. Mesher StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; double maturity = process_.time(arguments_.exercise.lastDate()); Fdm1dMesher equityMesher = new FdmBlackScholesMesher( xGrid_, process_, maturity, payoff.strike(), null, null, 0.0001, 1.5, new Pair <double?, double?>(payoff.strike(), 0.1)); FdmMesher mesher = new FdmMesherComposite(equityMesher); // 2. Calculator FdmInnerValueCalculator calculator = new FdmLogInnerValue(payoff, mesher, 0); // 3. Step conditions 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(); // 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); }
public FdmBlackScholesSolver( Handle <GeneralizedBlackScholesProcess> process, double strike, FdmSolverDesc solverDesc, FdmSchemeDesc schemeDesc = null, bool localVol = false, double?illegalLocalVolOverwrite = null) { process_ = process; strike_ = strike; solverDesc_ = solverDesc; schemeDesc_ = schemeDesc ?? new FdmSchemeDesc().Douglas(); localVol_ = localVol; illegalLocalVolOverwrite_ = illegalLocalVolOverwrite; }
public FdmBlackScholesSolver( Handle <GeneralizedBlackScholesProcess> process, double strike, FdmSolverDesc solverDesc, FdmSchemeDesc schemeDesc = null, bool localVol = false, double?illegalLocalVolOverwrite = null, Handle <FdmQuantoHelper> quantoHelper = null) { process_ = process; strike_ = strike; solverDesc_ = solverDesc; schemeDesc_ = schemeDesc ?? new FdmSchemeDesc().Douglas(); localVol_ = localVol; illegalLocalVolOverwrite_ = illegalLocalVolOverwrite; quantoHelper_ = quantoHelper; quantoHelper_ = quantoHelper ?? new Handle <FdmQuantoHelper>(); process_.registerWith(update); quantoHelper_.registerWith(update); }
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); FdmMesher mesher = new FdmMesherComposite(equityMesher); // 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_; 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); }
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); 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; } }
public override void calculate() { // 0. Cash dividend model Date exerciseDate = arguments_.exercise.lastDate(); double maturity = process_.time(exerciseDate); Date settlementDate = process_.riskFreeRate().currentLink().referenceDate(); double spotAdjustment = 0.0; DividendSchedule dividendSchedule = new DividendSchedule(); switch (cashDividendModel_) { case CashDividendModel.Spot: dividendSchedule = arguments_.cashFlow; break; case CashDividendModel.Escrowed: foreach (Dividend divIter in dividendSchedule) { Date divDate = divIter.date(); if (divDate <= exerciseDate && divDate >= settlementDate) { double divAmount = divIter.amount(); double discount = process_.riskFreeRate().currentLink().discount(divDate) / process_.dividendYield().currentLink().discount(divDate); spotAdjustment -= divAmount * discount; } } Utils.QL_REQUIRE(process_.x0() + spotAdjustment > 0.0, () => "spot minus dividends becomes negative"); break; default: Utils.QL_FAIL("unknwon cash dividend model"); break; } // 1. Mesher StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; Fdm1dMesher equityMesher = new FdmBlackScholesMesher( xGrid_, process_, maturity, payoff.strike(), null, null, 0.0001, 1.5, new Pair <double?, double?>(payoff.strike(), 0.1), dividendSchedule, quantoHelper_, spotAdjustment); FdmMesher mesher = new FdmMesherComposite(equityMesher); // 2. Calculator FdmInnerValueCalculator calculator = new FdmLogInnerValue(payoff, mesher, 0); // 3. Step conditions 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(); // 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); }
public override void calculate() { // 1. Term structure Handle <YieldTermStructure> ts = model_.currentLink().termStructure(); // 2. Mesher DayCounter dc = ts.currentLink().dayCounter(); Date referenceDate = ts.currentLink().referenceDate(); double maturity = dc.yearFraction(referenceDate, arguments_.exercise.lastDate()); OrnsteinUhlenbeckProcess process = new OrnsteinUhlenbeckProcess(model_.currentLink().a(), model_.currentLink().sigma()); Fdm1dMesher shortRateMesher = new FdmSimpleProcess1DMesher(xGrid_, process, maturity, 1, invEps_); FdmMesher mesher = new FdmMesherComposite(shortRateMesher); // 3. Inner Value Calculator List <Date> exerciseDates = arguments_.exercise.dates(); Dictionary <double, Date> t2d = new Dictionary <double, Date>(); for (int i = 0; i < exerciseDates.Count; ++i) { double t = dc.yearFraction(referenceDate, exerciseDates[i]); Utils.QL_REQUIRE(t >= 0, () => "exercise dates must not contain past date"); t2d.Add(t, exerciseDates[i]); } Handle <YieldTermStructure> disTs = model_.currentLink().termStructure(); Handle <YieldTermStructure> fwdTs = arguments_.swap.iborIndex().forwardingTermStructure(); Utils.QL_REQUIRE(fwdTs.currentLink().dayCounter() == disTs.currentLink().dayCounter(), () => "day counter of forward and discount curve must match"); Utils.QL_REQUIRE(fwdTs.currentLink().referenceDate() == disTs.currentLink().referenceDate(), () => "reference date of forward and discount curve must match"); HullWhite fwdModel = new HullWhite(fwdTs, model_.currentLink().a(), model_.currentLink().sigma()); FdmInnerValueCalculator calculator = new FdmAffineModelSwapInnerValue <HullWhite>( model_.currentLink(), fwdModel, arguments_.swap, t2d, mesher, 0); // 4. Step conditions FdmStepConditionComposite conditions = FdmStepConditionComposite.vanillaComposite( new DividendSchedule(), arguments_.exercise, mesher, calculator, referenceDate, dc); // 5. Boundary conditions FdmBoundaryConditionSet boundaries = new FdmBoundaryConditionSet(); // 6. Solver FdmSolverDesc solverDesc = new FdmSolverDesc(); solverDesc.mesher = mesher; solverDesc.bcSet = boundaries; solverDesc.condition = conditions; solverDesc.calculator = calculator; solverDesc.maturity = maturity; solverDesc.timeSteps = tGrid_; solverDesc.dampingSteps = dampingSteps_; FdmHullWhiteSolver solver = new FdmHullWhiteSolver(model_, solverDesc, schemeDesc_); results_.value = solver.valueAt(0.0); }