public FdmBlackScholesMesher(int size, GeneralizedBlackScholesProcess process, double maturity, double strike, double?xMinConstraint = null, double?xMaxConstraint = null, double eps = 0.0001, double scaleFactor = 1.5, Pair <double?, double?> cPoint = null, DividendSchedule dividendSchedule = null, FdmQuantoHelper fdmQuantoHelper = null, double spotAdjustment = 0.0) : base(size) { double S = process.x0(); Utils.QL_REQUIRE(S > 0.0, () => "negative or null underlying given"); dividendSchedule = dividendSchedule == null ? new DividendSchedule() : dividendSchedule; List <pair_double> intermediateSteps = new List <pair_double>(); for (int i = 0; i < dividendSchedule.Count && process.time(dividendSchedule[i].date()) <= maturity; ++i) { intermediateSteps.Add( new pair_double( process.time(dividendSchedule[i].date()), dividendSchedule[i].amount() )); } int intermediateTimeSteps = (int)Math.Max(2, 24.0 * maturity); for (int i = 0; i < intermediateTimeSteps; ++i) { intermediateSteps.Add( new pair_double((i + 1) * (maturity / intermediateTimeSteps), 0.0)); } intermediateSteps.Sort(); Handle <YieldTermStructure> rTS = process.riskFreeRate(); Handle <YieldTermStructure> qTS = fdmQuantoHelper != null ? new Handle <YieldTermStructure>( new QuantoTermStructure(process.dividendYield(), process.riskFreeRate(), new Handle <YieldTermStructure>(fdmQuantoHelper.foreignTermStructure()), process.blackVolatility(), strike, new Handle <BlackVolTermStructure>(fdmQuantoHelper.fxVolatilityTermStructure()), fdmQuantoHelper.exchRateATMlevel(), fdmQuantoHelper.equityFxCorrelation())) : process.dividendYield(); double lastDivTime = 0.0; double fwd = S + spotAdjustment; double mi = fwd, ma = fwd; for (int i = 0; i < intermediateSteps.Count; ++i) { double divTime = intermediateSteps[i].first; double divAmount = intermediateSteps[i].second; fwd = fwd / rTS.currentLink().discount(divTime) * rTS.currentLink().discount(lastDivTime) * qTS.currentLink().discount(divTime) / qTS.currentLink().discount(lastDivTime); mi = Math.Min(mi, fwd); ma = Math.Max(ma, fwd); fwd -= divAmount; mi = Math.Min(mi, fwd); ma = Math.Max(ma, fwd); lastDivTime = divTime; } // Set the grid boundaries double normInvEps = new InverseCumulativeNormal().value(1 - eps); double sigmaSqrtT = process.blackVolatility().currentLink().blackVol(maturity, strike) * Math.Sqrt(maturity); double?xMin = Math.Log(mi) - sigmaSqrtT * normInvEps * scaleFactor; double?xMax = Math.Log(ma) + sigmaSqrtT * normInvEps * scaleFactor; if (xMinConstraint != null) { xMin = xMinConstraint; } if (xMaxConstraint != null) { xMax = xMaxConstraint; } Fdm1dMesher helper; if (cPoint != null && cPoint.first != null && Math.Log(cPoint.first.Value) >= xMin && Math.Log(cPoint.first.Value) <= xMax) { helper = new Concentrating1dMesher(xMin.Value, xMax.Value, size, new Pair <double?, double?>(Math.Log(cPoint.first.Value), cPoint.second)); } else { helper = new Uniform1dMesher(xMin.Value, xMax.Value, size); } locations_ = helper.locations(); for (int i = 0; i < locations_.Count; ++i) { dplus_[i] = helper.dplus(i); dminus_[i] = helper.dminus(i); } }
public override void calculate() { DayCounter rfdc = process_.riskFreeRate().link.dayCounter(); DayCounter divdc = process_.dividendYield().link.dayCounter(); DayCounter voldc = process_.blackVolatility().link.dayCounter(); Calendar volcal = process_.blackVolatility().link.calendar(); double s0 = process_.stateVariable().link.value(); Utils.QL_REQUIRE(s0 > 0.0, () => "negative or null underlying given"); double v = process_.blackVolatility().link.blackVol(arguments_.exercise.lastDate(), s0); Date maturityDate = arguments_.exercise.lastDate(); double r = process_.riskFreeRate().link.zeroRate(maturityDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).rate(); double q = process_.dividendYield().link.zeroRate(maturityDate, divdc, Compounding.Continuous, Frequency.NoFrequency).rate(); Date referenceDate = process_.riskFreeRate().link.referenceDate(); // binomial trees with constant coefficient var flatRiskFree = new Handle <YieldTermStructure>(new FlatForward(referenceDate, r, rfdc)); var flatDividends = new Handle <YieldTermStructure>(new FlatForward(referenceDate, q, divdc)); var flatVol = new Handle <BlackVolTermStructure>(new BlackConstantVol(referenceDate, volcal, v, voldc)); PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff; Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given"); double maturity = rfdc.yearFraction(referenceDate, maturityDate); StochasticProcess1D bs = new GeneralizedBlackScholesProcess(process_.stateVariable(), flatDividends, flatRiskFree, flatVol); TimeGrid grid = new TimeGrid(maturity, timeSteps_); T tree = FastActivator <T> .Create().factory(bs, maturity, timeSteps_, payoff.strike()); BlackScholesLattice <T> lattice = new BlackScholesLattice <T>(tree, r, maturity, timeSteps_); DiscretizedVanillaOption option = new DiscretizedVanillaOption(arguments_, process_, grid); option.initialize(lattice, maturity); // Partial derivatives calculated from various points in the // binomial tree (Odegaard) // Rollback to third-last step, and get underlying price (s2) & // option values (p2) at this point option.rollback(grid[2]); Vector va2 = new Vector(option.values()); Utils.QL_REQUIRE(va2.size() == 3, () => "Expect 3 nodes in grid at second step"); double p2h = va2[2]; // high-price double s2 = lattice.underlying(2, 2); // high price // Rollback to second-last step, and get option value (p1) at // this point option.rollback(grid[1]); Vector va = new Vector(option.values()); Utils.QL_REQUIRE(va.size() == 2, () => "Expect 2 nodes in grid at first step"); double p1 = va[1]; // Finally, rollback to t=0 option.rollback(0.0); double p0 = option.presentValue(); double s1 = lattice.underlying(1, 1); // Calculate partial derivatives double delta0 = (p1 - p0) / (s1 - s0); // dp/ds double delta1 = (p2h - p1) / (s2 - s1); // dp/ds // Store results results_.value = p0; results_.delta = delta0; results_.gamma = 2.0 * (delta1 - delta0) / (s2 - s0); //d(delta)/ds results_.theta = Utils.blackScholesTheta(process_, results_.value.GetValueOrDefault(), results_.delta.GetValueOrDefault(), results_.gamma.GetValueOrDefault()); }
public YoYInflationIndex clone(Handle <YoYInflationTermStructure> h) { return(new YoYInflationIndex(familyName_, region_, revised_, interpolated_, ratio_, frequency_, availabilityLag_, currency_, h)); }