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 void applyTo(object o, double t) { Vector a = (Vector)o; if (exerciseTimes_.BinarySearch(t) >= 0) { FdmLinearOpLayout layout = mesher_.layout(); FdmLinearOpIterator endIter = layout.end(); int dims = layout.dim().Count; Vector locations = new Vector(dims); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { for (int i = 0; i < dims; ++i) { locations[i] = mesher_.location(iter, i); } double innerValue = calculator_.innerValue(iter, t); if (innerValue > a[iter.index()]) { a[iter.index()] = innerValue; } } } }
public Vector solve_splitting(Vector r, double a, double b = 1.0) { FdmLinearOpLayout layout = mesher_.layout(); Utils.QL_REQUIRE(r.size() == layout.size(), () => "inconsistent size of rhs"); for (FdmLinearOpIterator iter = layout.begin(); iter != layout.end(); ++iter) { List <int> coordinates = iter.coordinates(); Utils.QL_REQUIRE(coordinates[direction_] != 0 || lower_[iter.index()] == 0, () => "removing non zero entry!"); Utils.QL_REQUIRE(coordinates[direction_] != layout.dim()[direction_] - 1 || upper_[iter.index()] == 0, () => "removing non zero entry!"); } Vector retVal = new Vector(r.size()), tmp = new Vector(r.size()); // Thomson algorithm to solve a tridiagonal system. // Example code taken from Tridiagonalopertor and // changed to fit for the triple band operator. int rim1 = reverseIndex_[0]; double bet = 1.0 / (a * diag_[rim1] + b); Utils.QL_REQUIRE(bet != 0.0, () => "division by zero"); retVal[reverseIndex_[0]] = r[rim1] * bet; for (int j = 1; j <= layout.size() - 1; j++) { int ri = reverseIndex_[j]; tmp[j] = a * upper_[rim1] * bet; bet = b + a * (diag_[ri] - tmp[j] * lower_[ri]); Utils.QL_REQUIRE(bet != 0.0, () => "division by zero"); //QL_ENSURE bet = 1.0 / bet; retVal[ri] = (r[ri] - a * lower_[ri] * retVal[rim1]) * bet; rim1 = ri; } // cannot be j>=0 with Size j for (int j = layout.size() - 2; j > 0; --j) { retVal[reverseIndex_[j]] -= tmp[j + 1] * retVal[reverseIndex_[j + 1]]; } retVal[reverseIndex_[0]] -= tmp[1] * retVal[reverseIndex_[1]]; return(retVal); }
public SecondDerivativeOp(int direction, FdmMesher mesher) : base(direction, mesher) { FdmLinearOpLayout layout = mesher.layout(); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int i = iter.index(); double?hm = mesher.dminus(iter, direction_); double?hp = mesher.dplus(iter, direction_); double?zetam1 = hm * (hm + hp); double?zeta0 = hm * hp; double?zetap1 = hp * (hm + hp); int co = iter.coordinates()[direction_]; if (co == 0 || co == layout.dim()[direction] - 1) { lower_[i] = diag_[i] = upper_[i] = 0.0; } else { lower_[i] = 2.0 / zetam1.Value; diag_[i] = -2.0 / zeta0.Value; upper_[i] = 2.0 / zetap1.Value; } } }
public FdmIndicesOnBoundary(FdmLinearOpLayout layout, int direction, FdmDirichletBoundary.Side side) { List <int> newDim = new List <int>(layout.dim()); newDim[direction] = 1; int hyperSize = newDim.accumulate(0, newDim.Count, 1, (a, b) => (a * b)); indices_ = new InitializedList <int>(hyperSize); int i = 0; FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { if ((side == FdmDirichletBoundary.Side.Lower && iter.coordinates()[direction] == 0) || (side == FdmDirichletBoundary.Side.Upper && iter.coordinates()[direction] == layout.dim()[direction] - 1)) { Utils.QL_REQUIRE(hyperSize > i, () => "index missmatch"); indices_[i++] = iter.index(); } } }
public int neighbourhood(FdmLinearOpIterator iterator, int i1, int offset1, int i2, int offset2) { int myIndex = iterator.index() - iterator.coordinates()[i1] * spacing_[i1] - iterator.coordinates()[i2] * spacing_[i2]; int coorOffset1 = iterator.coordinates()[i1] + offset1; if (coorOffset1 < 0) { coorOffset1 = -coorOffset1; } else if (coorOffset1 >= dim_[i1]) { coorOffset1 = 2 * (dim_[i1] - 1) - coorOffset1; } int coorOffset2 = iterator.coordinates()[i2] + offset2; if (coorOffset2 < 0) { coorOffset2 = -coorOffset2; } else if (coorOffset2 >= dim_[i2]) { coorOffset2 = 2 * (dim_[i2] - 1) - coorOffset2; } return(myIndex + coorOffset1 * spacing_[i1] + coorOffset2 * spacing_[i2]); }
protected Vector getLeverageFctSlice(double t1, double t2) { FdmLinearOpLayout layout = mesher_.layout(); Vector v = new Vector(layout.size(), 1.0); if (leverageFct_ == null) { return(v); } double t = 0.5 * (t1 + t2); double time = Math.Min(leverageFct_ == null ? 1000.0 : leverageFct_.maxTime(), t); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int nx = iter.coordinates()[0]; if (iter.coordinates()[1] == 0) { double x = Math.Exp(mesher_.location(iter, 0)); double spot = Math.Min(leverageFct_ == null ? 100000.0 : leverageFct_.maxStrike(), Math.Max(leverageFct_ == null ? -100000.0 : leverageFct_.minStrike(), x)); v[nx] = Math.Max(0.01, leverageFct_ == null ? 0.0 : leverageFct_.localVol(time, spot, true)); } else { v[iter.index()] = v[nx]; } } return(v); }
public FdmHestonEquityPart(FdmMesher mesher, YieldTermStructure rTS, YieldTermStructure qTS, FdmQuantoHelper quantoHelper = null, LocalVolTermStructure leverageFct = null) { varianceValues_ = new Vector(0.5 * mesher.locations(1)); dxMap_ = new FirstDerivativeOp(0, mesher); dxxMap_ = new SecondDerivativeOp(0, mesher).mult(0.5 * mesher.locations(1)); mapT_ = new TripleBandLinearOp(0, mesher); mesher_ = mesher; rTS_ = rTS; qTS_ = qTS; quantoHelper_ = quantoHelper; leverageFct_ = leverageFct; // on the boundary s_min and s_max the second derivative // d^2V/dS^2 is zero and due to Ito's Lemma the variance term // in the drift should vanish. FdmLinearOpLayout layout = mesher_.layout(); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { if (iter.coordinates()[0] == 0 || iter.coordinates()[0] == layout.dim()[0] - 1) { varianceValues_[iter.index()] = 0.0; } } volatilityValues_ = Vector.Sqrt(2 * varianceValues_); }
public void applyTo(object o, double t) { Vector a = (Vector)o; FdmLinearOpLayout layout = mesher_.layout(); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { double innerValue = calculator_.innerValue(iter, t); if (innerValue > a[iter.index()]) { a[iter.index()] = innerValue; } } }
public override Vector locations(int direction) { Vector retVal = new Vector(layout_.size()); FdmLinearOpIterator endIter = layout_.end(); for (FdmLinearOpIterator iter = layout_.begin(); iter != endIter; ++iter) { retVal[iter.index()] = mesher_[direction].locations()[iter.coordinates()[direction]]; } return(retVal); }
public int neighbourhood(FdmLinearOpIterator iterator, int i, int offset) { int myIndex = iterator.index() - iterator.coordinates()[i] * spacing_[i]; int coorOffset = iterator.coordinates()[i] + offset; if (coorOffset < 0) { coorOffset = -coorOffset; } else if (coorOffset >= dim_[i]) { coorOffset = 2 * (dim_[i] - 1) - coorOffset; } return(myIndex + coorOffset * spacing_[i]); }
public NinePointLinearOp(int d0, int d1, FdmMesher mesher) { d0_ = d0; d1_ = d1; i00_ = new InitializedList <int>(mesher.layout().size()); i10_ = new InitializedList <int>(mesher.layout().size()); i20_ = new InitializedList <int>(mesher.layout().size()); i01_ = new InitializedList <int>(mesher.layout().size()); i21_ = new InitializedList <int>(mesher.layout().size()); i02_ = new InitializedList <int>(mesher.layout().size()); i12_ = new InitializedList <int>(mesher.layout().size()); i22_ = new InitializedList <int>(mesher.layout().size()); a00_ = new InitializedList <double>(mesher.layout().size()); a10_ = new InitializedList <double>(mesher.layout().size()); a20_ = new InitializedList <double>(mesher.layout().size()); a01_ = new InitializedList <double>(mesher.layout().size()); a11_ = new InitializedList <double>(mesher.layout().size()); a21_ = new InitializedList <double>(mesher.layout().size()); a02_ = new InitializedList <double>(mesher.layout().size()); a12_ = new InitializedList <double>(mesher.layout().size()); a22_ = new InitializedList <double>(mesher.layout().size()); mesher_ = mesher; Utils.QL_REQUIRE(d0_ != d1_ && d0_ < mesher.layout().dim().Count && d1_ < mesher.layout().dim().Count, () => "inconsistent derivative directions"); FdmLinearOpLayout layout = mesher.layout(); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int i = iter.index(); i10_[i] = layout.neighbourhood(iter, d1_, -1); i01_[i] = layout.neighbourhood(iter, d0_, -1); i21_[i] = layout.neighbourhood(iter, d0_, 1); i12_[i] = layout.neighbourhood(iter, d1_, 1); i00_[i] = layout.neighbourhood(iter, d0_, -1, d1_, -1); i20_[i] = layout.neighbourhood(iter, d0_, 1, d1_, -1); i02_[i] = layout.neighbourhood(iter, d0_, -1, d1_, 1); i22_[i] = layout.neighbourhood(iter, d0_, 1, d1_, 1); } }
public TripleBandLinearOp(int direction, FdmMesher mesher) { direction_ = direction; i0_ = new InitializedList <int>(mesher.layout().size()); i2_ = new InitializedList <int>(mesher.layout().size()); reverseIndex_ = new InitializedList <int>(mesher.layout().size()); lower_ = new InitializedList <double>(mesher.layout().size()); diag_ = new InitializedList <double>(mesher.layout().size()); upper_ = new InitializedList <double>(mesher.layout().size()); mesher_ = mesher; FdmLinearOpLayout layout = mesher.layout(); FdmLinearOpIterator endIter = layout.end(); int tmp; List <int> newDim = new List <int>(layout.dim()); tmp = newDim[direction_]; newDim[direction_] = newDim[0]; newDim[0] = tmp; List <int> newSpacing = new FdmLinearOpLayout(newDim).spacing(); tmp = newSpacing[direction_]; newSpacing[direction_] = newSpacing[0]; newSpacing[0] = tmp; for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int i = iter.index(); i0_[i] = layout.neighbourhood(iter, direction, -1); i2_[i] = layout.neighbourhood(iter, direction, 1); List <int> coordinates = iter.coordinates(); int newIndex = coordinates.inner_product(0, coordinates.Count, 0, newSpacing, 0); reverseIndex_[newIndex] = i; } }
public FirstDerivativeOp(int direction, FdmMesher mesher) : base(direction, mesher) { FdmLinearOpLayout layout = mesher.layout(); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int i = iter.index(); double?hm = mesher.dminus(iter, direction_); double?hp = mesher.dplus(iter, direction_); double?zetam1 = hm * (hm + hp); double?zeta0 = hm * hp; double?zetap1 = hp * (hm + hp); if (iter.coordinates()[direction_] == 0) { //upwinding scheme lower_[i] = 0.0; diag_[i] = -(upper_[i] = 1 / hp.Value); } else if (iter.coordinates()[direction_] == layout.dim()[direction] - 1) { // downwinding scheme lower_[i] = -(diag_[i] = 1 / hm.Value); upper_[i] = 0.0; } else { lower_[i] = -hp.Value / zetam1.Value; diag_[i] = (hp.Value - hm.Value) / zeta0.Value; upper_[i] = hm.Value / zetap1.Value; } } }
//! Time \f$t1 <= t2\f$ is required public override void setTime(double t1, double t2) { double r = rTS_.forwardRate(t1, t2, Compounding.Continuous).rate(); double q = qTS_.forwardRate(t1, t2, Compounding.Continuous).rate(); if (localVol_ != null) { FdmLinearOpLayout layout = mesher_.layout(); FdmLinearOpIterator endIter = layout.end(); Vector v = new Vector(layout.size()); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int i = iter.index(); if (illegalLocalVolOverwrite_ == null) { double t = localVol_.localVol(0.5 * (t1 + t2), x_[i], true); v[i] = t * t; } else { try { double t = localVol_.localVol(0.5 * (t1 + t2), x_[i], true); v[i] = t * t; } catch { v[i] = illegalLocalVolOverwrite_.Value * illegalLocalVolOverwrite_.Value; } } } if (quantoHelper_ != null) { mapT_.axpyb(r - q - 0.5 * v - quantoHelper_.quantoAdjustment(Vector.Sqrt(v), t1, t2), dxMap_, dxxMap_.mult(0.5 * v), new Vector(1, -r)); } else { mapT_.axpyb(r - q - 0.5 * v, dxMap_, dxxMap_.mult(0.5 * v), new Vector(1, -r)); } } else { double vv = volTS_.blackForwardVariance(t1, t2, strike_) / (t2 - t1); if (quantoHelper_ != null) { mapT_.axpyb(new Vector(1, r - q - 0.5 * vv) - quantoHelper_.quantoAdjustment(new Vector(1, Math.Sqrt(vv)), t1, t2), dxMap_, dxxMap_.mult(0.5 * new Vector(mesher_.layout().size(), vv)), new Vector(1, -r)); } else { mapT_.axpyb(new Vector(1, r - q - 0.5 * vv), dxMap_, dxxMap_.mult(0.5 * new Vector(mesher_.layout().size(), vv)), new Vector(1, -r)); } } }
public SecondOrderMixedDerivativeOp(int d0, int d1, FdmMesher mesher) : base(d0, d1, mesher) { FdmLinearOpLayout layout = mesher.layout(); FdmLinearOpIterator endIter = layout.end(); for (FdmLinearOpIterator iter = layout.begin(); iter != endIter; ++iter) { int i = iter.index(); double?hm_d0 = mesher.dminus(iter, d0_); double?hp_d0 = mesher.dplus(iter, d0_); double?hm_d1 = mesher.dminus(iter, d1_); double?hp_d1 = mesher.dplus(iter, d1_); double?zetam1 = hm_d0 * (hm_d0 + hp_d0); double?zeta0 = hm_d0 * hp_d0; double?zetap1 = hp_d0 * (hm_d0 + hp_d0); double?phim1 = hm_d1 * (hm_d1 + hp_d1); double?phi0 = hm_d1 * hp_d1; double?phip1 = hp_d1 * (hm_d1 + hp_d1); int c0 = iter.coordinates()[d0_]; int c1 = iter.coordinates()[d1_]; if (c0 == 0 && c1 == 0) { // lower left corner a00_[i] = a01_[i] = a02_[i] = a10_[i] = a20_[i] = 0.0; a11_[i] = a22_[i] = 1.0 / (hp_d0.Value * hp_d1.Value); a21_[i] = a12_[i] = -a11_[i]; } else if (c0 == layout.dim()[d0_] - 1 && c1 == 0) { // upper left corner a22_[i] = a21_[i] = a20_[i] = a10_[i] = a00_[i] = 0.0; a01_[i] = a12_[i] = 1.0 / (hm_d0.Value * hp_d1.Value); a11_[i] = a02_[i] = -a01_[i]; } else if (c0 == 0 && c1 == layout.dim()[d1_] - 1) { // lower right corner a00_[i] = a01_[i] = a02_[i] = a12_[i] = a22_[i] = 0.0; a10_[i] = a21_[i] = 1.0 / (hp_d0.Value * hm_d1.Value); a20_[i] = a11_[i] = -a10_[i]; } else if (c0 == layout.dim()[d0_] - 1 && c1 == layout.dim()[d1_] - 1) { // upper right corner a20_[i] = a21_[i] = a22_[i] = a12_[i] = a02_[i] = 0.0; a00_[i] = a11_[i] = 1.0 / (hm_d0.Value * hm_d1.Value); a10_[i] = a01_[i] = -a00_[i]; } else if (c0 == 0) { // lower side a00_[i] = a01_[i] = a02_[i] = 0.0; a10_[i] = hp_d1.Value / (hp_d0.Value * phim1.Value); a20_[i] = -a10_[i]; a21_[i] = (hp_d1.Value - hm_d1.Value) / (hp_d0.Value * phi0.Value); a11_[i] = -a21_[i]; a22_[i] = hm_d1.Value / (hp_d0.Value * phip1.Value); a12_[i] = -a22_[i]; } else if (c0 == layout.dim()[d0_] - 1) { // upper side a20_[i] = a21_[i] = a22_[i] = 0.0; a00_[i] = hp_d1.Value / (hm_d0.Value * phim1.Value); a10_[i] = -a00_[i]; a11_[i] = (hp_d1.Value - hm_d1.Value) / (hm_d0.Value * phi0.Value); a01_[i] = -a11_[i]; a12_[i] = hm_d1.Value / (hm_d0.Value * phip1.Value); a02_[i] = -a12_[i]; } else if (c1 == 0) { // left side a00_[i] = a10_[i] = a20_[i] = 0.0; a01_[i] = hp_d0.Value / (zetam1.Value * hp_d1.Value); a02_[i] = -a01_[i]; a12_[i] = (hp_d0.Value - hm_d0.Value) / (zeta0.Value * hp_d1.Value); a11_[i] = -a12_[i]; a22_[i] = hm_d0.Value / (zetap1.Value * hp_d1.Value); a21_[i] = -a22_[i]; } else if (c1 == layout.dim()[d1_] - 1) { // right side a22_[i] = a12_[i] = a02_[i] = 0.0; a00_[i] = hp_d0.Value / (zetam1.Value * hm_d1.Value); a01_[i] = -a00_[i]; a11_[i] = (hp_d0.Value - hm_d0.Value) / (zeta0.Value * hm_d1.Value); a10_[i] = -a11_[i]; a21_[i] = hm_d0.Value / (zetap1.Value * hm_d1.Value); a20_[i] = -a21_[i]; } else { a00_[i] = hp_d0.Value * hp_d1.Value / (zetam1.Value * phim1.Value); a10_[i] = -(hp_d0.Value - hm_d0.Value) * hp_d1.Value / (zeta0.Value * phim1.Value); a20_[i] = -hm_d0.Value * hp_d1.Value / (zetap1.Value * phim1.Value); a01_[i] = -hp_d0.Value * (hp_d1.Value - hm_d1.Value) / (zetam1.Value * phi0.Value); a11_[i] = (hp_d0.Value - hm_d0.Value) * (hp_d1.Value - hm_d1.Value) / (zeta0.Value * phi0.Value); a21_[i] = hm_d0.Value * (hp_d1.Value - hm_d1.Value) / (zetap1.Value * phi0.Value); a02_[i] = -hp_d0.Value * hm_d1.Value / (zetam1.Value * phip1.Value); a12_[i] = hm_d1.Value * (hp_d0.Value - hm_d0.Value) / (zeta0.Value * phip1.Value); a22_[i] = hm_d0.Value * hm_d1.Value / (zetap1.Value * phip1.Value); } } }