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); }
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 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 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); }
//! 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); // vMin = value - 1.0; // vMax = value + 1.0; theta.change(value); } }
public TreeCallableFixedRateBondEngine(ShortRateModel model, TimeGrid timeGrid, Handle <YieldTermStructure> termStructure) : base(model, timeGrid) { termStructure_ = termStructure; termStructure_.registerWith(update); }
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 MultiPath(int nAsset, TimeGrid timeGrid) { multiPath_ = new List<Path>(nAsset); for (int i = 0; i < nAsset; i++) multiPath_.Add(new Path(timeGrid)); if (!(nAsset > 0)) throw new ApplicationException("number of asset must be positive"); }
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); // vMin = value - 10.0; // vMax = value + 10.0; } return numericTree; }
//! Return by default a trinomial recombining tree public override Lattice tree(TimeGrid grid) { //throw new NotImplementedException(); TrinomialTree trinomial = new TrinomialTree(dynamics().process(), grid); return(new ShortRateTree(trinomial, dynamics(), grid)); }
//! 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 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))); }
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 Path(TimeGrid timeGrid, Vector values) { timeGrid_ = timeGrid; values_ = (Vector)values.Clone(); if (values_.empty()) values_ = new Vector(timeGrid_.size()); if (values_.size() != timeGrid_.size()) throw new ApplicationException("different number of times and asset values"); }
public TreeLattice(TimeGrid timeGrid, int n) : base(timeGrid) { n_ = n; if (!(n > 0)) { throw new Exception("there is no zeronomial lattice!"); } statePrices_ = new InitializedList <Vector>(1, new Vector(1, 1.0)); statePricesLimit_ = 0; }
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_ = (Vector)values.Clone(); if (values_.empty()) { values_ = new Vector(timeGrid_.size()); } Utils.QL_REQUIRE(values_.size() == timeGrid_.size(), () => "different number of times and asset values"); }
public MultiPath(int nAsset, TimeGrid timeGrid) { multiPath_ = new List <Path>(nAsset); for (int i = 0; i < nAsset; i++) { multiPath_.Add(new Path(timeGrid)); } if (!(nAsset > 0)) { throw new Exception("number of asset must be positive"); } }
public DiscretizedVanillaOption(VanillaOption.Arguments args, StochasticProcess process, TimeGrid grid) { arguments_ = args; stoppingTimes_ = new InitializedList<double>(args.exercise.dates().Count); for (int i=0; i<stoppingTimes_.Count; ++i) { stoppingTimes_[i] = process.time(args.exercise.date(i)); if (!grid.empty()) { // adjust to the given grid stoppingTimes_[i] = grid.closestTime(stoppingTimes_[i]); } } }
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)); }
// 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 + ")"); }
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 Path(TimeGrid timeGrid, Vector values) { timeGrid_ = timeGrid; values_ = (Vector)values.Clone(); if (values_.empty()) { values_ = new Vector(timeGrid_.size()); } if (values_.size() != timeGrid_.size()) { throw new ApplicationException("different number of times and asset values"); } }
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"); }
//! 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(); }
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]); } }
private void pathGenerator(UnderlyingInfo under) { ulong seed = 1; int timeSteps = 365; // int dimensions = this.processArr_.factors(); double t = processArr_.time(maturity); TimeGrid grid = new TimeGrid(t, timeSteps); IRNG rndGenerator = (IRNG)new PseudoRandom().make_sequence_generator(dimensions * (grid.size() - 1), seed); this.pathGenerator_ = new MultiPathGenerator<IRNG>(this.processArr_, grid, rndGenerator, false); }
public PathGenerator(StochasticProcess process, TimeGrid timeGrid, GSG generator, bool brownianBridge) { brownianBridge_ = brownianBridge; generator_ = generator; dimension_ = generator_.dimension(); timeGrid_ = timeGrid; process_ = process as StochasticProcess1D; next_ = new Sample <IPath>(new Path(timeGrid_), 1.0); temp_ = new InitializedList <double>(dimension_); bb_ = new BrownianBridge(timeGrid_); if (dimension_ != timeGrid_.size() - 1) { throw new Exception("sequence generator dimensionality (" + dimension_ + ") != timeSteps (" + (timeGrid_.size() - 1) + ")"); } }
//! 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(); }
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); if (generator_.dimension() != process.factors() * (times.size() - 1)) { throw new Exception("dimension (" + generator_.dimension() + ") is not equal to (" + process.factors() + " * " + (times.size() - 1) + ") the number of factors " + "times the number of time steps"); } if (!(times.size() > 1)) { throw new Exception("no times given"); } }
//@} 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(); if (!(s0 > 0.0)) { throw new ApplicationException("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; if (payoff == null) { throw new ApplicationException("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 = new T().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()); if (!(va2.size() == 3)) { throw new ApplicationException("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()); if (!(va.size() == 2)) { throw new ApplicationException("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()); }
override public void setPosition(TimeGrid timeGrid, DayCounter dayCounter, Calendar calendar) { }
public override Lattice tree(TimeGrid grid){ TrinomialTree trinomial = new TrinomialTree(dynamics().process(), grid, true); return new ShortRateTree(trinomial, dynamics(), grid); }
public void testLambdaBootstrapping() { //"Testing caplet LMM lambda bootstrapping..." //SavedSettings backup; double tolerance = 1e-10; double[] lambdaExpected = {14.3010297550, 19.3821411939, 15.9816590141, 15.9953118303, 14.0570815635, 13.5687599894, 12.7477197786, 13.7056638165, 11.6191989567}; LiborForwardModelProcess process = makeProcess(); Matrix covar = process.covariance(0.0, null, 1.0); for (int i=0; i<9; ++i) { double calculated = Math.Sqrt(covar[i+1,i+1]); double expected = lambdaExpected[i]/100; if (Math.Abs(calculated - expected) > tolerance) Assert.Fail("Failed to reproduce expected lambda values" + "\n calculated: " + calculated + "\n expected: " + expected); } LfmCovarianceParameterization param = process.covarParam(); List<double> tmp = process.fixingTimes(); TimeGrid grid= new TimeGrid(tmp.Last(), 14); for (int t=0; t<grid.size(); ++t) { //verifier la presence du null Matrix diff = param.integratedCovariance(grid[t],null) - param.integratedCovariance(grid[t], null); for (int i=0; i<diff.rows(); ++i) { for (int j=0; j<diff.columns(); ++j) { if (Math.Abs(diff[i,j]) > tolerance) { Assert.Fail("Failed to reproduce integrated covariance" + "\n calculated: " + diff[i,j] + "\n expected: " + 0); } } } } }
public void testMonteCarloCapletPricing() { //"Testing caplet LMM Monte-Carlo caplet pricing..." //SavedSettings backup; /* factor loadings are taken from Hull & White article plus extra normalisation to get orthogonal eigenvectors http://www.rotman.utoronto.ca/~amackay/fin/libormktmodel2.pdf */ double[] compValues = {0.85549771, 0.46707264, 0.22353259, 0.91915359, 0.37716089, 0.11360610, 0.96438280, 0.26413316,-0.01412414, 0.97939148, 0.13492952,-0.15028753, 0.95970595,-0.00000000,-0.28100621, 0.97939148,-0.13492952,-0.15028753, 0.96438280,-0.26413316,-0.01412414, 0.91915359,-0.37716089, 0.11360610, 0.85549771,-0.46707264, 0.22353259}; Matrix volaComp=new Matrix(9,3); List<double> lcompValues=new InitializedList<double>(27,0); List<double> ltemp = new InitializedList<double>(3, 0); lcompValues=compValues.ToList(); //std::copy(compValues, compValues+9*3, volaComp.begin()); for (int i = 0; i < 9; i++) { ltemp = lcompValues.GetRange(3*i, 3); for (int j = 0; j < 3; j++) volaComp[i, j] = ltemp[j]; } LiborForwardModelProcess process1 = makeProcess(); LiborForwardModelProcess process2 = makeProcess(volaComp); List<double> tmp = process1.fixingTimes(); TimeGrid grid=new TimeGrid(tmp ,12); List<int> location=new List<int>(); for (int i=0; i < tmp.Count; ++i) { location.Add(grid.index(tmp[i])) ; } // set-up a small Monte-Carlo simulation to price caplets // and ratchet caps using a one- and a three factor libor market model ulong seed = 42; LowDiscrepancy.icInstance = new InverseCumulativeNormal(); IRNG rsg1 = (IRNG)new LowDiscrepancy().make_sequence_generator( process1.factors()*(grid.size()-1), seed); IRNG rsg2 = (IRNG)new LowDiscrepancy().make_sequence_generator( process2.factors()*(grid.size()-1), seed); MultiPathGenerator<IRNG> generator1=new MultiPathGenerator<IRNG> (process1, grid, rsg1, false); MultiPathGenerator<IRNG> generator2=new MultiPathGenerator<IRNG> (process2, grid, rsg2, false); const int nrTrails = 250000; List<GeneralStatistics> stat1 = new InitializedList<GeneralStatistics>(process1.size()); List<GeneralStatistics> stat2 = new InitializedList<GeneralStatistics>(process2.size()); List<GeneralStatistics> stat3 = new InitializedList<GeneralStatistics>(process2.size() - 1); for (int i=0; i<nrTrails; ++i) { Sample<MultiPath> path1 = generator1.next(); Sample<MultiPath> path2 = generator2.next(); List<double> rates1=new InitializedList<double>(len); List<double> rates2 = new InitializedList<double>(len); for (int j=0; j<process1.size(); ++j) { rates1[j] = path1.value[j][location[j]]; rates2[j] = path2.value[j][location[j]]; } List<double> dis1 = process1.discountBond(rates1); List<double> dis2 = process2.discountBond(rates2); for (int k=0; k<process1.size(); ++k) { double accrualPeriod = process1.accrualEndTimes()[k] - process1.accrualStartTimes()[k]; // caplet payoff function, cap rate at 4% double payoff1 = Math.Max(rates1[k] - 0.04, 0.0) * accrualPeriod; double payoff2 = Math.Max(rates2[k] - 0.04, 0.0) * accrualPeriod; stat1[k].add(dis1[k] * payoff1); stat2[k].add(dis2[k] * payoff2); if (k != 0) { // ratchet cap payoff function double payoff3 = Math.Max(rates2[k] - (rates2[k-1]+0.0025), 0.0) * accrualPeriod; stat3[k-1].add(dis2[k] * payoff3); } } } double[] capletNpv = {0.000000000000, 0.000002841629, 0.002533279333, 0.009577143571, 0.017746502618, 0.025216116835, 0.031608230268, 0.036645683881, 0.039792254012, 0.041829864365}; double[] ratchetNpv = {0.0082644895, 0.0082754754, 0.0082159966, 0.0082982822, 0.0083803357, 0.0084366961, 0.0084173270, 0.0081803406, 0.0079533814}; for (int k=0; k < process1.size(); ++k) { double calculated1 = stat1[k].mean(); double tolerance1 = stat1[k].errorEstimate(); double expected = capletNpv[k]; if (Math.Abs(calculated1 - expected) > tolerance1) { Assert.Fail("Failed to reproduce expected caplet NPV" + "\n calculated: " + calculated1 + "\n error int: " + tolerance1 + "\n expected: " + expected); } double calculated2 = stat2[k].mean(); double tolerance2 = stat2[k].errorEstimate(); if (Math.Abs(calculated2 - expected) > tolerance2) { Assert.Fail("Failed to reproduce expected caplet NPV" + "\n calculated: " + calculated2 + "\n error int: " + tolerance2 + "\n expected: " + expected); } if (k != 0) { double calculated3 = stat3[k-1].mean(); double tolerance3 = stat3[k-1].errorEstimate(); expected = ratchetNpv[k-1]; double refError = 1e-5; // 1e-5. error bars of the reference values if (Math.Abs(calculated3 - expected) > tolerance3 + refError) { Assert.Fail("Failed to reproduce expected caplet NPV" + "\n calculated: " + calculated3 + "\n error int: " + tolerance3 + refError + "\n expected: " + expected); } } } }
public abstract Lattice tree(TimeGrid t);
public void testSwaptionPricing() { //"Testing forward swap and swaption pricing..."); //SavedSettings backup; const int size = 10; const int steps = 8*size; #if QL_USE_INDEXED_COUPON const double tolerance = 1e-6; #else const double tolerance = 1e-12; #endif List<Date> dates = new List<Date>(); List<double> rates = new List<double>(); dates.Add(new Date(4,9,2005)); dates.Add(new Date(4,9,2011)); rates.Add(0.04); rates.Add(0.08); IborIndex index = makeIndex(dates, rates); LiborForwardModelProcess process = new LiborForwardModelProcess(size, index); LmCorrelationModel corrModel = new LmExponentialCorrelationModel(size, 0.5); LmVolatilityModel volaModel = new LmLinearExponentialVolatilityModel(process.fixingTimes(), 0.291, 1.483, 0.116, 0.00001); // set-up pricing engine process.setCovarParam((LfmCovarianceParameterization) new LfmCovarianceProxy(volaModel, corrModel)); // set-up a small Monte-Carlo simulation to price swations List<double> tmp = process.fixingTimes(); TimeGrid grid=new TimeGrid(tmp ,steps); List<int> location=new List<int>(); for (int i=0; i < tmp.Count; ++i) { location.Add(grid.index(tmp[i])) ; } ulong seed=42; const int nrTrails = 5000; LowDiscrepancy.icInstance = new InverseCumulativeNormal(); IRNG rsg = (InverseCumulativeRsg<RandomSequenceGenerator<MersenneTwisterUniformRng> ,InverseCumulativeNormal>) new PseudoRandom().make_sequence_generator(process.factors()*(grid.size()-1),seed); MultiPathGenerator<IRNG> generator=new MultiPathGenerator<IRNG>(process, grid, rsg, false); LiborForwardModel liborModel = new LiborForwardModel(process, volaModel, corrModel); Calendar calendar = index.fixingCalendar(); DayCounter dayCounter = index.forwardingTermStructure().link.dayCounter(); BusinessDayConvention convention = index.businessDayConvention(); Date settlement = index.forwardingTermStructure().link.referenceDate(); SwaptionVolatilityMatrix m = liborModel.getSwaptionVolatilityMatrix(); for (int i=1; i < size; ++i) { for (int j=1; j <= size-i; ++j) { Date fwdStart = settlement + new Period(6*i, TimeUnit.Months); Date fwdMaturity = fwdStart + new Period(6*j, TimeUnit.Months); Schedule schedule =new Schedule(fwdStart, fwdMaturity, index.tenor(), calendar, convention, convention, DateGeneration.Rule.Forward, false); double swapRate = 0.0404; VanillaSwap forwardSwap = new VanillaSwap(VanillaSwap.Type.Receiver, 1.0, schedule, swapRate, dayCounter, schedule, index, 0.0, index.dayCounter()); forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure())); // check forward pricing first double expected = forwardSwap.fairRate(); double calculated = liborModel.S_0(i-1,i+j-1); if (Math.Abs(expected - calculated) > tolerance) Assert.Fail("Failed to reproduce fair forward swap rate" + "\n calculated: " + calculated + "\n expected: " + expected); swapRate = forwardSwap.fairRate(); forwardSwap = new VanillaSwap(VanillaSwap.Type.Receiver, 1.0, schedule, swapRate, dayCounter, schedule, index, 0.0, index.dayCounter()); forwardSwap.setPricingEngine(new DiscountingSwapEngine(index.forwardingTermStructure())); if (i == j && i<=size/2) { IPricingEngine engine = new LfmSwaptionEngine(liborModel, index.forwardingTermStructure()); Exercise exercise = new EuropeanExercise(process.fixingDates()[i]); Swaption swaption = new Swaption(forwardSwap, exercise); swaption.setPricingEngine(engine); GeneralStatistics stat = new GeneralStatistics(); for (int n=0; n<nrTrails; ++n) { Sample<MultiPath> path = (n%2!=0) ? generator.antithetic() : generator.next(); //Sample<MultiPath> path = generator.next(); List<double> rates_ = new InitializedList<double>(size); for (int k=0; k<process.size(); ++k) { rates_[k] = path.value[k][location[i]]; } List<double> dis = process.discountBond(rates_); double npv=0.0; for (int k=i; k < i+j; ++k) { npv += (swapRate - rates_[k]) * ( process.accrualEndTimes()[k] - process.accrualStartTimes()[k])*dis[k]; } stat.add(Math.Max(npv, 0.0)); } if (Math.Abs(swaption.NPV() - stat.mean()) > stat.errorEstimate()*2.35) Assert.Fail("Failed to reproduce swaption npv" + "\n calculated: " + stat.mean() + "\n expected: " + swaption.NPV()); } } } }
static void Main(string[] args) { DateTime timer = DateTime.Now; Date todaysDate = new Date(15, 2, 2002); Calendar calendar = new TARGET(); Date settlementDate = new Date(19, 2, 2002); Settings.setEvaluationDate(todaysDate); // flat yield term structure impling 1x5 swap at 5% Quote flatRate = new SimpleQuote(0.04875825); Handle<YieldTermStructure> rhTermStructure = new Handle<YieldTermStructure>( new FlatForward(settlementDate, new Handle<Quote>(flatRate), new Actual365Fixed())); // Define the ATM/OTM/ITM swaps Frequency fixedLegFrequency = Frequency.Annual; BusinessDayConvention fixedLegConvention = BusinessDayConvention.Unadjusted; BusinessDayConvention floatingLegConvention = BusinessDayConvention.ModifiedFollowing; DayCounter fixedLegDayCounter = new Thirty360(Thirty360.Thirty360Convention.European); Frequency floatingLegFrequency = Frequency.Semiannual; VanillaSwap.Type type = VanillaSwap.Type.Payer; double dummyFixedRate = 0.03; IborIndex indexSixMonths = new Euribor6M(rhTermStructure); Date startDate = calendar.advance(settlementDate, 1, TimeUnit.Years, floatingLegConvention); Date maturity = calendar.advance(startDate, 5, TimeUnit.Years, floatingLegConvention); Schedule fixedSchedule = new Schedule(startDate, maturity, new Period(fixedLegFrequency), calendar, fixedLegConvention, fixedLegConvention, DateGeneration.Rule.Forward, false); Schedule floatSchedule = new Schedule(startDate, maturity, new Period(floatingLegFrequency), calendar, floatingLegConvention, floatingLegConvention, DateGeneration.Rule.Forward, false); VanillaSwap swap = new VanillaSwap( type, 1000.0, fixedSchedule, dummyFixedRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); swap.setPricingEngine(new DiscountingSwapEngine(rhTermStructure)); double fixedAtmRate = swap.fairRate(); double fixedOtmRate = fixedAtmRate * 1.2; double fixedItmRate = fixedAtmRate * 0.8; VanillaSwap atmSwap = new VanillaSwap( type, 1000.0, fixedSchedule, fixedAtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap otmSwap = new VanillaSwap( type, 1000.0, fixedSchedule, fixedOtmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); VanillaSwap itmSwap = new VanillaSwap( type, 1000.0, fixedSchedule, fixedItmRate, fixedLegDayCounter, floatSchedule, indexSixMonths, 0.0, indexSixMonths.dayCounter()); // defining the swaptions to be used in model calibration List<Period> swaptionMaturities = new List<Period>(5); swaptionMaturities.Add(new Period(1, TimeUnit.Years)); swaptionMaturities.Add(new Period(2, TimeUnit.Years)); swaptionMaturities.Add(new Period(3, TimeUnit.Years)); swaptionMaturities.Add(new Period(4, TimeUnit.Years)); swaptionMaturities.Add(new Period(5, TimeUnit.Years)); List<CalibrationHelper> swaptions = new List<CalibrationHelper>(); // List of times that have to be included in the timegrid List<double> times = new List<double>(); for (int i = 0; i < NumRows; i++) { int j = NumCols - i - 1; // 1x5, 2x4, 3x3, 4x2, 5x1 int k = i * NumCols + j; Quote vol = new SimpleQuote(SwaptionVols[k]); swaptions.Add(new SwaptionHelper(swaptionMaturities[i], new Period(SwapLenghts[j], TimeUnit.Years), new Handle<Quote>(vol), indexSixMonths, indexSixMonths.tenor(), indexSixMonths.dayCounter(), indexSixMonths.dayCounter(), rhTermStructure, false)); swaptions.Last().addTimesTo(times); } // Building time-grid TimeGrid grid = new TimeGrid(times, 30); // defining the models G2 modelG2 = new G2(rhTermStructure); HullWhite modelHw = new HullWhite(rhTermStructure); HullWhite modelHw2 = new HullWhite(rhTermStructure); BlackKarasinski modelBk = new BlackKarasinski(rhTermStructure); // model calibrations Console.WriteLine("G2 (analytic formulae) calibration"); for (int i = 0; i < swaptions.Count; i++) swaptions[i].setPricingEngine(new G2SwaptionEngine(modelG2, 6.0, 16)); CalibrateModel(modelG2, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.0000000}\n" + "b = {2:0.000000}, " + "eta = {3:0.0000000}\n" + "rho = {4:0.00000}\n", modelG2.parameters()[0], modelG2.parameters()[1], modelG2.parameters()[2], modelG2.parameters()[3], modelG2.parameters()[4]); Console.WriteLine("Hull-White (analytic formulae) calibration"); for (int i = 0; i < swaptions.Count; i++) swaptions[i].setPricingEngine(new JamshidianSwaptionEngine(modelHw)); CalibrateModel(modelHw, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.0000000}\n", modelHw.parameters()[0], modelHw.parameters()[1]); Console.WriteLine("Hull-White (numerical) calibration"); for (int i = 0; i < swaptions.Count(); i++) swaptions[i].setPricingEngine(new TreeSwaptionEngine(modelHw2, grid)); CalibrateModel(modelHw2, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.0000000}\n", modelHw2.parameters()[0], modelHw2.parameters()[1]); Console.WriteLine("Black-Karasinski (numerical) calibration"); for (int i = 0; i < swaptions.Count; i++) swaptions[i].setPricingEngine(new TreeSwaptionEngine(modelBk, grid)); CalibrateModel(modelBk, swaptions); Console.WriteLine("calibrated to:\n" + "a = {0:0.000000}, " + "sigma = {1:0.00000}\n", modelBk.parameters()[0], modelBk.parameters()[1]); // ATM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption " + "struck at {0:0.00000 %} (ATM)", fixedAtmRate); List<Date> bermudanDates = new List<Date>(); List<CashFlow> leg = swap.fixedLeg(); for (int i = 0; i < leg.Count; i++) { Coupon coupon = (Coupon)leg[i]; bermudanDates.Add(coupon.accrualStartDate()); } Exercise bermudanExercise = new BermudanExercise(bermudanDates); Swaption bermudanSwaption = new Swaption(atmSwap, bermudanExercise); // Do the pricing for each model // G2 price the European swaption here, it should switch to bermudan bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelG2, 50)); Console.WriteLine("G2: {0:0.00}", bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: {0:0.000}", bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): {0:0.000}", bermudanSwaption.NPV()); bermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK: {0:0.000}", bermudanSwaption.NPV()); // OTM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption " + "struck at {0:0.00000 %} (OTM)", fixedOtmRate); Swaption otmBermudanSwaption = new Swaption(otmSwap, bermudanExercise); // Do the pricing for each model otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelG2, 50)); Console.WriteLine("G2: {0:0.0000}", otmBermudanSwaption.NPV()); otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: {0:0.0000}", otmBermudanSwaption.NPV()); otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): {0:0.000}", otmBermudanSwaption.NPV()); otmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK: {0:0.0000}", otmBermudanSwaption.NPV()); // ITM Bermudan swaption pricing Console.WriteLine("Payer bermudan swaption " + "struck at {0:0.00000 %} (ITM)", fixedItmRate); Swaption itmBermudanSwaption = new Swaption(itmSwap, bermudanExercise); // Do the pricing for each model itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelG2, 50)); Console.WriteLine("G2: {0:0.000}", itmBermudanSwaption.NPV()); itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw, 50)); Console.WriteLine("HW: {0:0.000}", itmBermudanSwaption.NPV()); itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelHw2, 50)); Console.WriteLine("HW (num): {0:0.000}", itmBermudanSwaption.NPV()); itmBermudanSwaption.setPricingEngine(new TreeSwaptionEngine(modelBk, 50)); Console.WriteLine("BK: {0:0.000}", itmBermudanSwaption.NPV()); Console.WriteLine(" \nRun completed in {0}", DateTime.Now - timer); Console.WriteLine(); Console.Write("Press any key to continue ..."); Console.ReadKey(); }
public Path(TimeGrid timeGrid) : this(timeGrid, new Vector()) { }
public Lattice(TimeGrid timeGrid) { t_ = timeGrid; }