public double value(IPath path) { Utils.QL_REQUIRE(!(path as Path).empty(), () => "the path cannot be empty"); TimeGrid doubleGrid = (path as Path).timeGrid(); int startIndex = doubleGrid.closestIndex(lookbackStart_); double underlying; switch (payoff_.optionType()) { case Option.Type.Put: underlying = (path as Path).values().GetRange(startIndex, (path as Path).values().Count - startIndex).Min(); break; case Option.Type.Call: underlying = (path as Path).values().GetRange(startIndex, (path as Path).values().Count - startIndex).Max(); break; default: underlying = 0.0; Utils.QL_FAIL("unknown option type"); break; } return(payoff_.value(underlying) * discount_); }
protected override PathPricer <IPath> pathPricer() { TimeGrid grid = this.timeGrid(); double discount = (this.process_ as GeneralizedBlackScholesProcess) .riskFreeRate().currentLink().discount(grid.Last()); ContinuousFixedLookbackOption.Arguments arg1 = this.arguments_ as ContinuousFixedLookbackOption.Arguments; ContinuousPartialFixedLookbackOption.Arguments arg2 = this.arguments_ as ContinuousPartialFixedLookbackOption.Arguments; ContinuousFloatingLookbackOption.Arguments arg3 = this.arguments_ as ContinuousFloatingLookbackOption.Arguments; ContinuousPartialFloatingLookbackOption.Arguments arg4 = this.arguments_ as ContinuousPartialFloatingLookbackOption.Arguments; if (arg2 != null) { return(mc_looback_path_pricer(arg2, this.process_ as GeneralizedBlackScholesProcess, discount)); } else if (arg1 != null) { return(mc_looback_path_pricer(arg1, this.process_ as GeneralizedBlackScholesProcess, discount)); } else if (arg4 != null) { return(mc_looback_path_pricer(arg4, this.process_ as GeneralizedBlackScholesProcess, discount)); } else if (arg3 != null) { return(mc_looback_path_pricer(arg3, this.process_ as GeneralizedBlackScholesProcess, discount)); } else { return(null); } }
public PiecewiseTimeDependentHestonModel(Handle <YieldTermStructure> riskFreeRate, Handle <YieldTermStructure> dividendYield, Handle <Quote> s0, double v0, Parameter theta, Parameter kappa, Parameter sigma, Parameter rho, TimeGrid timeGrid) : base(5) { s0_ = s0; riskFreeRate_ = riskFreeRate; dividendYield_ = dividendYield; timeGrid_ = timeGrid; arguments_[0] = theta; arguments_[1] = kappa; arguments_[2] = sigma; arguments_[3] = rho; arguments_[4] = new ConstantParameter(v0, new PositiveConstraint()); s0.registerWith(update); riskFreeRate.registerWith(update); dividendYield.registerWith(update); }
public override Lattice tree(TimeGrid grid) { TermStructureFittingParameter phi = new TermStructureFittingParameter(termStructure()); ShortRateDynamics numericDynamics = new Dynamics(phi, a(), sigma()); TrinomialTree trinomial = new TrinomialTree(numericDynamics.process(), grid); ShortRateTree numericTree = new ShortRateTree(trinomial, numericDynamics, grid); TermStructureFittingParameter.NumericalImpl impl = (TermStructureFittingParameter.NumericalImpl)phi.implementation(); impl.reset(); for (int i = 0; i < (grid.size() - 1); i++) { double discountBond = termStructure().link.discount(grid[i + 1]); Vector statePrices = numericTree.statePrices(i); int size = numericTree.size(i); double dt = numericTree.timeGrid().dt(i); double dx = trinomial.dx(i); double x = trinomial.underlying(i, 0); double value = 0.0; for (int j = 0; j < size; j++) { value += statePrices[j] * Math.Exp(-x * dt); x += dx; } value = Math.Log(value / discountBond) / dt; impl.setvalue(grid[i], value); } return(numericTree); }
public override Lattice tree(TimeGrid grid) { TermStructureFittingParameter phi = new TermStructureFittingParameter(termStructure()); ShortRateDynamics numericDynamics = new Dynamics(phi, a(), sigma()); TrinomialTree trinomial = new TrinomialTree(numericDynamics.process(), grid); ShortRateTree numericTree = new ShortRateTree(trinomial, numericDynamics, grid); TermStructureFittingParameter.NumericalImpl impl = (TermStructureFittingParameter.NumericalImpl)phi.implementation(); impl.reset(); double value = 1.0; double vMin = -50.0; double vMax = 50.0; for (int i = 0; i < (grid.size() - 1); i++) { double discountBond = termStructure().link.discount(grid[i + 1]); double xMin = trinomial.underlying(i, 0); double dx = trinomial.dx(i); Helper finder = new Helper(i, xMin, dx, discountBond, numericTree); Brent s1d = new Brent(); s1d.setMaxEvaluations(1000); value = s1d.solve(finder, 1e-7, value, vMin, vMax); impl.setvalue(grid[i], value); } return(numericTree); }
protected override IPathGenerator <IRNG> pathGenerator() { TimeGrid grid = timeGrid(); IRNG gen = new RNG().make_sequence_generator(grid.size() - 1, seed_); return(new PathGenerator <IRNG>(process_, grid, gen, brownianBridge_)); }
public double value(IPath path) { Utils.QL_REQUIRE(!(path as Path).empty(), () => "the path cannot be empty"); TimeGrid doubleGrid = (path as Path).timeGrid(); int endIndex = doubleGrid.closestIndex(lookbackEnd_); double terminalPrice = (path as Path).back(); double strike; switch (payoff_.optionType()) { case Option.Type.Call: strike = (path as Path).values().GetRange(0, endIndex).Min(); break; case Option.Type.Put: strike = (path as Path).values().GetRange(0, endIndex).Max(); break; default: strike = 0.0; Utils.QL_FAIL("unknown option type"); break; } return(payoff_.value(terminalPrice, strike) * discount_); }
public TreeLattice(TimeGrid timeGrid, int n) : base(timeGrid) { n_ = n; Utils.QL_REQUIRE(n > 0, () => "there is no zeronomial lattice!"); statePrices_ = new InitializedList <Vector>(1, new Vector(1, 1.0)); statePricesLimit_ = 0; }
public TreeCallableFixedRateBondEngine(ShortRateModel model, TimeGrid timeGrid, Handle <YieldTermStructure> termStructure) : base(model, timeGrid) { termStructure_ = termStructure; termStructure_.registerWith(update); }
public override Lattice tree(TimeGrid grid) { ShortRateDynamics dyn = dynamics(); TrinomialTree tree1 = new TrinomialTree(dyn.xProcess(), grid); TrinomialTree tree2 = new TrinomialTree(dyn.yProcess(), grid); return((Lattice)(new ShortRateTree(tree1, tree2, dyn))); }
protected override IPathGenerator <IRNG> pathGenerator() { int dimensions = process_.factors(); TimeGrid grid = timeGrid(); IRNG generator = (IRNG)FastActivator <RNG> .Create().make_sequence_generator(dimensions * (grid.size() - 1), seed_); return(new PathGenerator <IRNG>(process_, grid, generator, brownianBridge_)); }
//! Plain tree build-up from short-rate dynamics public ShortRateTree(TrinomialTree tree, ShortRateDynamics dynamics, TimeGrid timeGrid) : base(timeGrid, tree.size(1)) { tree_ = tree; dynamics_ = dynamics; }
public TreeVanillaSwapEngine(ShortRateModel model, TimeGrid timeGrid, Handle <YieldTermStructure> termStructure) : base(model, timeGrid) { termStructure_ = termStructure; termStructure_.registerWith(update); }
public MultiPath(int nAsset, TimeGrid timeGrid) { multiPath_ = new List <Path>(nAsset); for (int i = 0; i < nAsset; i++) { multiPath_.Add(new Path(timeGrid)); } Utils.QL_REQUIRE(nAsset > 0, () => "number of asset must be positive"); }
public LatticeShortRateModelEngine(ShortRateModel model, TimeGrid timeGrid) : base(model) { timeGrid_ = new TimeGrid(timeGrid.Last(), timeGrid.size() - 1 /*timeGrid.dt(1) - timeGrid.dt(0)*/); timeGrid_ = timeGrid; timeSteps_ = 0; lattice_ = this.model_.link.tree(timeGrid); }
public TrinomialTree(StochasticProcess1D process, TimeGrid timeGrid, bool isPositive /*= false*/) : base(timeGrid.size()) { branchings_ = new List <Branching>(); dx_ = new InitializedList <double>(1); timeGrid_ = timeGrid; x0_ = process.x0(); int nTimeSteps = timeGrid.size() - 1; int jMin = 0; int jMax = 0; for (int i = 0; i < nTimeSteps; i++) { double t = timeGrid[i]; double dt = timeGrid.dt(i); //Variance must be independent of x double v2 = process.variance(t, 0.0, dt); double v = Math.Sqrt(v2); dx_.Add(v * Math.Sqrt(3.0)); Branching branching = new Branching(); for (int j = jMin; j <= jMax; j++) { double x = x0_ + j * dx_[i]; double m = process.expectation(t, x, dt); int temp = (int)(Math.Floor((m - x0_) / dx_[i + 1] + 0.5)); if (isPositive) { while (x0_ + (temp - 1) * dx_[i + 1] <= 0) { temp++; } } double e = m - (x0_ + temp * dx_[i + 1]); double e2 = e * e; double e3 = e * Math.Sqrt(3.0); double p1 = (1.0 + e2 / v2 - e3 / v) / 6.0; double p2 = (2.0 - e2 / v2) / 3.0; double p3 = (1.0 + e2 / v2 + e3 / v) / 6.0; branching.add(temp, p1, p2, p3); } branchings_.Add(branching); jMin = branching.jMin(); jMax = branching.jMax(); } }
private Sample <IPath> next(bool antithetic) { if (brownianBridge_) { Utils.QL_FAIL("Brownian bridge not supported"); return(null); } Sample <List <double> > sequence_ = antithetic ? generator_.lastSequence() : generator_.nextSequence(); int m = process_.size(); int n = process_.factors(); MultiPath path = (MultiPath)next_.value; Vector asset = process_.initialValues(); for (int j = 0; j < m; j++) { path[j].setFront(asset[j]); } Vector temp; next_.weight = sequence_.weight; TimeGrid timeGrid = path[0].timeGrid(); double t, dt; for (int i = 1; i < path.pathSize(); i++) { int offset = (i - 1) * n; t = timeGrid[i - 1]; dt = timeGrid.dt(i - 1); if (antithetic) { temp = -1 * new Vector(sequence_.value.GetRange(offset, n)); } else { temp = new Vector(sequence_.value.GetRange(offset, n)); } asset = process_.evolve(t, asset, dt, temp); for (int j = 0; j < m; j++) { path[j][i] = asset[j]; } } return(next_); }
public Path(TimeGrid timeGrid, Vector values) { timeGrid_ = timeGrid; values_ = values.Clone(); if (values_.empty()) { values_ = new Vector(timeGrid_.size()); } Utils.QL_REQUIRE(values_.size() == timeGrid_.size(), () => "different number of times and asset values"); }
// constructors public PathGenerator(StochasticProcess process, double length, int timeSteps, GSG generator, bool brownianBridge) { brownianBridge_ = brownianBridge; generator_ = generator; dimension_ = generator_.dimension(); timeGrid_ = new TimeGrid(length, timeSteps); process_ = process as StochasticProcess1D; next_ = new Sample <IPath>(new Path(timeGrid_), 1.0); temp_ = new InitializedList <double>(dimension_); bb_ = new BrownianBridge(timeGrid_); Utils.QL_REQUIRE(dimension_ == timeSteps, () => "sequence generator dimensionality (" + dimension_ + ") != timeSteps (" + timeSteps + ")"); }
protected override IPathGenerator <IRNG> controlPathGenerator() { int dimensions = process_.factors(); TimeGrid grid = this.timeGrid(); IRNG generator = (IRNG) new RNG().make_sequence_generator(dimensions * (grid.size() - 1), this.seed_); HybridHestonHullWhiteProcess process = process_ as HybridHestonHullWhiteProcess; Utils.QL_REQUIRE(process != null, () => "invalid process"); HybridHestonHullWhiteProcess cvProcess = new HybridHestonHullWhiteProcess(process.hestonProcess(), process.hullWhiteProcess(), 0.0, process.discretization()); return(new MultiPathGenerator <IRNG>(cvProcess, grid, generator, false)); }
public override void calculate() { if (base.model_ == null) { throw new ArgumentException("no model specified"); } Date referenceDate; DayCounter dayCounter; ITermStructureConsistentModel tsmodel = (ITermStructureConsistentModel)base.model_.link; try { if (tsmodel != null) { referenceDate = tsmodel.termStructure().link.referenceDate(); dayCounter = tsmodel.termStructure().link.dayCounter(); } else { referenceDate = termStructure_.link.referenceDate(); dayCounter = termStructure_.link.dayCounter(); } } catch { referenceDate = termStructure_.link.referenceDate(); dayCounter = termStructure_.link.dayCounter(); } DiscretizedSwap swap = new DiscretizedSwap(arguments_, referenceDate, dayCounter); List <double> times = swap.mandatoryTimes(); Lattice lattice; if (lattice_ != null) { lattice = lattice_; } else { TimeGrid timeGrid = new TimeGrid(times, times.Count, timeSteps_); lattice = model_.link.tree(timeGrid); } swap.initialize(lattice, times.Last()); swap.rollback(0.0); results_.value = swap.presentValue(); }
public MultiPathGenerator(StochasticProcess process, TimeGrid times, GSG generator, bool brownianBridge) { brownianBridge_ = brownianBridge; process_ = process; generator_ = generator; next_ = new Sample <IPath>(new MultiPath(process.size(), times), 1.0); Utils.QL_REQUIRE(generator_.dimension() == process.factors() * (times.size() - 1), () => "dimension (" + generator_.dimension() + ") is not equal to (" + process.factors() + " * " + (times.size() - 1) + ") the number of factors " + "times the number of time steps"); Utils.QL_REQUIRE(times.size() > 1, () => "no times given"); }
public LongstaffSchwartzPathPricer(TimeGrid times, IEarlyExercisePathPricer <PathType, double> pathPricer, YieldTermStructure termStructure) { calibrationPhase_ = true; pathPricer_ = pathPricer; coeff_ = new InitializedList <Vector>(times.size() - 1); dF_ = new InitializedList <double>(times.size() - 1); v_ = pathPricer_.basisSystem(); for (int i = 0; i < times.size() - 1; ++i) { dF_[i] = termStructure.discount(times[i + 1]) / termStructure.discount(times[i]); } }
//! generic times public BrownianBridge(TimeGrid timeGrid) { size_ = timeGrid.size() - 1; t_ = new InitializedList <double>(size_); sqrtdt_ = new InitializedList <double>(size_); sqrtdt_ = new InitializedList <double>(size_); bridgeIndex_ = new InitializedList <int>(size_); leftIndex_ = new InitializedList <int>(size_); rightIndex_ = new InitializedList <int>(size_); leftWeight_ = new InitializedList <double>(size_); rightWeight_ = new InitializedList <double>(size_); stdDev_ = new InitializedList <double>(size_); for (int i = 0; i < size_; ++i) { t_[i] = timeGrid[i + 1]; } initialize(); }
//! Tree build-up + numerical fitting to term-structure public ShortRateTree(TrinomialTree tree, ShortRateDynamics dynamics, TermStructureFittingParameter.NumericalImpl theta, TimeGrid timeGrid) : base(timeGrid, tree.size(1)) { tree_ = tree; dynamics_ = dynamics; theta.reset(); double value = 1.0; double vMin = -100.0; double vMax = 100.0; for (int i = 0; i < (timeGrid.size() - 1); i++) { double discountBond = theta.termStructure().link.discount(t_[i + 1]); Helper finder = new Helper(i, discountBond, theta, this); Brent s1d = new Brent(); s1d.setMaxEvaluations(1000); value = s1d.solve(finder, 1e-7, value, vMin, vMax); theta.change(value); } }
public override void calculate() { Utils.QL_REQUIRE(model_ != null, () => "no model specified"); Date referenceDate; DayCounter dayCounter; ITermStructureConsistentModel tsmodel = (ITermStructureConsistentModel)base.model_.link; if (tsmodel != null) { referenceDate = tsmodel.termStructure().link.referenceDate(); dayCounter = tsmodel.termStructure().link.dayCounter(); } else { referenceDate = termStructure_.link.referenceDate(); dayCounter = termStructure_.link.dayCounter(); } DiscretizedCallableFixedRateBond callableBond = new DiscretizedCallableFixedRateBond(arguments_, referenceDate, dayCounter); Lattice lattice; if (lattice_ != null) { lattice = lattice_; } else { List <double> times = callableBond.mandatoryTimes(); TimeGrid timeGrid = new TimeGrid(times, times.Count, timeSteps_); lattice = model_.link.tree(timeGrid); } double redemptionTime = dayCounter.yearFraction(referenceDate, arguments_.redemptionDate); callableBond.initialize(lattice, redemptionTime); callableBond.rollback(0.0); results_.value = results_.settlementValue = callableBond.presentValue(); }
protected override PathPricer <IPath> pathPricer() { PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff; Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given"); TimeGrid grid = timeGrid(); List <double> discounts = new InitializedList <double>(grid.size()); for (int i = 0; i < grid.size(); i++) { discounts[i] = process_.riskFreeRate().currentLink().discount(grid[i]); } // do this with template parameters? if (isBiased_) { return(new BiasedBarrierPathPricer(arguments_.barrierType, arguments_.barrier, arguments_.rebate, payoff.optionType(), payoff.strike(), discounts)); } else { IRNG sequenceGen = new RandomSequenceGenerator <MersenneTwisterUniformRng>(grid.size() - 1, 5); return(new BarrierPathPricer(arguments_.barrierType, arguments_.barrier, arguments_.rebate, payoff.optionType(), payoff.strike(), discounts, process_, sequenceGen)); } }
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).value(); double q = process_.dividendYield().link.zeroRate(maturityDate, divdc, Compounding.Continuous, Frequency.NoFrequency).value(); Date referenceDate = process_.riskFreeRate().link.referenceDate(); // binomial trees with constant coefficient Handle <YieldTermStructure> flatRiskFree = new Handle <YieldTermStructure>(new FlatForward(referenceDate, r, rfdc)); Handle <YieldTermStructure> flatDividends = new Handle <YieldTermStructure>(new FlatForward(referenceDate, q, divdc)); Handle <BlackVolTermStructure> flatVol = new Handle <BlackVolTermStructure>(new BlackConstantVol(referenceDate, volcal, v, voldc)); StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff; Utils.QL_REQUIRE(payoff != null, () => "non-striked payoff given"); double maturity = rfdc.yearFraction(referenceDate, maturityDate); StochasticProcess1D bs = new GeneralizedBlackScholesProcess(process_.stateVariable(), flatDividends, flatRiskFree, flatVol); // correct timesteps to ensure a (local) minimum, using Boyle and Lau // approach. See Journal of Derivatives, 1/1994, // "Bumping up against the barrier with the binomial method" // Note: this approach works only for CoxRossRubinstein lattices, so // is disabled if T is not a CoxRossRubinstein or derived from it. int optimum_steps = timeSteps_; if (maxTimeSteps_ > timeSteps_ && s0 > 0 && arguments_.barrier > 0) // boost::is_base_of<CoxRossRubinstein, T>::value && { double divisor; if (s0 > arguments_.barrier) { divisor = Math.Pow(Math.Log(s0 / arguments_.barrier.Value), 2); } else { divisor = Math.Pow(Math.Log(arguments_.barrier.Value / s0), 2); } if (!Utils.close(divisor, 0)) { for (int i = 1; i < timeSteps_; ++i) { int optimum = (int)((i * i * v * v * maturity) / divisor); if (timeSteps_ < optimum) { optimum_steps = optimum; break; // found first minimum with iterations>=timesteps } } } if (optimum_steps > maxTimeSteps_) { optimum_steps = maxTimeSteps_; // too high, limit } } TimeGrid grid = new TimeGrid(maturity, optimum_steps); ITree tree = getTree_(bs, maturity, optimum_steps, payoff.strike()); BlackScholesLattice <ITree> lattice = new BlackScholesLattice <ITree>(tree, r, maturity, optimum_steps); DiscretizedAsset option = getAsset_(arguments_, process_, grid); option.initialize(lattice, maturity); // Partial derivatives calculated from various points in the // binomial tree // (see J.C.Hull, "Options, Futures and other derivatives", 6th edition, pp 397/398) // Rollback to third-last step, and get underlying prices (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 p2u = va2[2]; // up double p2m = va2[1]; // mid double p2d = va2[0]; // down (low) double s2u = lattice.underlying(2, 2); // up price double s2m = lattice.underlying(2, 1); // middle price double s2d = lattice.underlying(2, 0); // down (low) price // calculate gamma by taking the first derivate of the two deltas double delta2u = (p2u - p2m) / (s2u - s2m); double delta2d = (p2m - p2d) / (s2m - s2d); double gamma = (delta2u - delta2d) / ((s2u - s2d) / 2); // Rollback to second-last step, and get option values (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 p1u = va[1]; double p1d = va[0]; double s1u = lattice.underlying(1, 1); // up (high) price double s1d = lattice.underlying(1, 0); // down (low) price double delta = (p1u - p1d) / (s1u - s1d); // Finally, rollback to t=0 option.rollback(0.0); double p0 = option.presentValue(); // Store results results_.value = p0; results_.delta = delta; results_.gamma = gamma; // theta can be approximated by calculating the numerical derivative // between mid value at third-last step and at t0. The underlying price // is the same, only time varies. results_.theta = (p2m - p0) / grid[2]; }
public override Lattice tree(TimeGrid grid) { TrinomialTree trinomial = new TrinomialTree(dynamics().process(), grid, true); return(new ShortRateTree(trinomial, dynamics(), grid)); }
public abstract Lattice tree(TimeGrid t);