public override void partialRollback(DiscretizedAsset asset, double to) { double from = asset.time(); if (Utils.close(from, to)) { return; } Utils.QL_REQUIRE(from > to, () => " cannot roll the asset back to tile to it is already at time from "); DiscretizedConvertible convertible = asset as DiscretizedConvertible; int iFrom = t_.index(from); int iTo = t_.index(to); for (var i = iFrom - 1; i >= iTo; --i) { Vector newValues = new Vector(size(i)); Vector newSpreadAdjustedRate = new Vector(size(i)); Vector newConversionProbability = new Vector(size(i)); stepback(i, convertible.values(), convertible.conversionProbability(), convertible.spreadAdjustedRate(), newValues, newConversionProbability, newSpreadAdjustedRate); convertible.setTime(t_[i]); convertible.setValues(newValues); convertible.spreadAdjustedRate_ = newSpreadAdjustedRate; convertible.conversionProbability_ = newConversionProbability; // skip the very last adjustement if (i != iTo) { convertible.adjustValues(); } } }
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_.x0(); Utils.QL_REQUIRE(s0 > 0.0, () => "negative or null underlying"); double v = process_.blackVolatility().link.blackVol(arguments_.exercise.lastDate(), s0); Date maturityDate = arguments_.exercise.lastDate(); double riskFreeRate = process_.riskFreeRate().link.zeroRate(maturityDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).value(); double q = process_.dividendYield().link.zeroRate(maturityDate, divdc, Compounding.Continuous, Frequency.NoFrequency).value(); Date referenceDate = process_.riskFreeRate().link.referenceDate(); // substract dividends ConvertibleBond.option.Arguments args = arguments_ as ConvertibleBond.option.Arguments; for (int i = 0; i < args.dividends.Count; i++) { if (args.dividends[i].date() >= referenceDate) { s0 -= args.dividends[i].amount() * process_.riskFreeRate().link.discount(args.dividends[i].date()); } Utils.QL_REQUIRE(s0 > 0.0, () => "negative value after substracting dividends"); } // binomial trees with constant coefficient Handle <Quote> underlying = new Handle <Quote>(new SimpleQuote(s0)); Handle <YieldTermStructure> flatRiskFree = new Handle <YieldTermStructure>(new FlatForward(referenceDate, riskFreeRate, rfdc)); Handle <YieldTermStructure> flatDividends = new Handle <YieldTermStructure>(new FlatForward(referenceDate, q, divdc)); Handle <BlackVolTermStructure> flatVol = new Handle <BlackVolTermStructure>(new BlackConstantVol(referenceDate, volcal, v, voldc)); PlainVanillaPayoff payoff = args.payoff as PlainVanillaPayoff; Utils.QL_REQUIRE(payoff != null, () => " non-plain payoff given "); double maturity = rfdc.yearFraction(args.settlementDate, maturityDate); GeneralizedBlackScholesProcess bs = new GeneralizedBlackScholesProcess(underlying, flatDividends, flatRiskFree, flatVol); T Tree = new T().factory(bs, maturity, timeSteps_, payoff.strike()); double creditSpread = args.creditSpread.link.value(); TsiveriotisFernandesLattice <T> lattice = new TsiveriotisFernandesLattice <T>(Tree, riskFreeRate, maturity, timeSteps_, creditSpread, v, q); DiscretizedConvertible convertible = new DiscretizedConvertible(args, bs, new TimeGrid(maturity, timeSteps_)); convertible.initialize(lattice, maturity); convertible.rollback(0.0); results_.value = convertible.presentValue(); Utils.QL_REQUIRE(results_.value < double.MaxValue, () => "floating-point overflow on tree grid"); }