private void initialize() { Utils.QL_REQUIRE(dates_.Count >= interpolator_.requiredPoints, () => "not enough input dates givesn"); Utils.QL_REQUIRE(this.data_.Count == this.dates_.Count, () => "dates/data count mismatch"); Utils.QL_REQUIRE(this.data_[0] == 1.0, () => "the first discount must be == 1.0 " + "to flag the corrsponding date as settlement date"); times_ = new InitializedList <double>(dates_.Count - 1); times_.Add(0.0); for (int i = 1; i < dates_.Count; i++) { Utils.QL_REQUIRE(dates_[i] > dates_[i - 1], () => "invalid date (" + dates_[i] + ", vs " + dates_[i - 1] + ")"); times_[i] = dayCounter().yearFraction(dates_[0], dates_[i]); Utils.QL_REQUIRE(!Utils.close(this.times_[i], this.times_[i - 1]), () => "two dates correspond to the same time " + "under this curve's day count convention"); Utils.QL_REQUIRE(this.data_[i] > 0.0, () => "negative discount"); #if !QL_NEGATIVE_RATES Utils.QL_REQUIRE(this.data_[i] <= this.data_[i - 1], () => "negative forward rate implied by the discount " + this.data_[i] + " at " + dates_[i] + " (t=" + this.times_[i] + ") after the discount " + this.data_[i - 1] + " at " + dates_[i - 1] + " (t=" + this.times_[i - 1] + ")"); #endif } setupInterpolation(); interpolation_.update(); }
//public InterpolatedDiscountCurve(List<Date> dates, List<double> discounts, DayCounter dayCounter, // Calendar cal = Calendar(), Interpolator interpolator = Interpolator()) public InterpolatedDiscountCurve(List <Date> dates, List <double> discounts, DayCounter dayCounter, Calendar cal, List <Handle <Quote> > jumps = null, List <Date> jumpDates = null, Interpolator interpolator = default(Interpolator)) : base(dates.First(), cal, dayCounter, jumps, jumpDates) { times_ = new List <double>(); data_ = discounts; interpolator_ = interpolator; dates_ = dates; if (dates_.empty()) { throw new ApplicationException("no input dates given"); } if (data_.empty()) { throw new ApplicationException("no input discount factors given"); } if (data_.Count != dates_.Count) { throw new ApplicationException("dates/discount factors count mismatch"); } if (data_[0] != 1.0) { throw new ApplicationException("the first discount must be == 1.0 " + "to flag the corrsponding date as settlement date"); } times_ = new InitializedList <double>(dates_.Count - 1); times_.Add(0.0); for (int i = 1; i < dates_.Count; i++) { if (!(dates_[i] > dates_[i - 1])) { throw new ApplicationException("invalid date (" + dates_[i] + ", vs " + dates_[i - 1] + ")"); } if (!(data_[i] > 0.0)) { throw new ApplicationException("negative discount"); } times_[i] = dayCounter.yearFraction(dates_[0], dates_[i]); if (Utils.close(times_[i], times_[i - 1])) { throw new ApplicationException("two dates correspond to the same time " + "under this curve's day count convention"); } } setupInterpolation(); interpolation_.update(); }
/// Spline /// public void splincalculation() { double rightConditionValue = 0.0; double leftConditionValue = 0.0; int size = strikes_.Count + 2; List <List <double> > bspriceSpline = new InitializedList <List <double> >(); gamma_ = new InitializedList <Vector>(); g_ = new InitializedList <Vector>(); for (int i = 0; i < fwMoneynessGrid_.rows(); i++) { leftConditionValue = spot_ * dividendTS_.link.discount(times_[i], true) / riskFreeTS_.link.discount(times_[i], true); bspriceSpline.Add(new InitializedList <double>()); strikesSpline_.Add(new InitializedList <double>()); bspriceSpline[i].Add(leftConditionValue); strikesSpline_[i].Add(0.0); for (int j = 0; j < fwMoneynessGrid_.columns(); j++) { bspriceSpline[i].Add(X_[i, j]); strikesSpline_[i].Add(strikes_[j]); } rightConditionValue = 0.0; bspriceSpline[i].Add(rightConditionValue); strikesSpline_[i].Add(spot_ * 10000); g_i_.Add(new CubicInterpolation(strikesSpline_[i], size, bspriceSpline[i], CubicInterpolation.DerivativeApprox.Spline, true, CubicInterpolation.BoundaryCondition.SecondDerivative, leftConditionValue, CubicInterpolation.BoundaryCondition.SecondDerivative, rightConditionValue)); List <double> tempList = new List <double>(); tempList = g_i_[i].bCoefficients(); tempList[0] = 0.0; tempList[tempList.Count - 1] = 0.0; gamma_.Add(new Vector(tempList)); g_.Add(new Vector(strikes_)); } }
// McSimulation implementation protected override TimeGrid timeGrid() { Date referenceDate = process_.riskFreeRate().link.referenceDate(); DayCounter voldc = process_.blackVolatility().link.dayCounter(); List <double> fixingTimes = new InitializedList <double>(arguments_.fixingDates.Count); for (int i = 0; i < arguments_.fixingDates.Count; i++) { if (arguments_.fixingDates[i] >= referenceDate) { double t = voldc.yearFraction(referenceDate, arguments_.fixingDates[i]); fixingTimes.Add(t); } } // handle here maxStepsPerYear return(new TimeGrid(fixingTimes.Last(), fixingTimes.Count)); }
public Concentrating1dMesher(double start, double end, int size, List <Tuple <double?, double?, bool> > cPoints, double tol = 1e-8) : base(size) { Utils.QL_REQUIRE(end > start, () => "end must be larger than start"); List <double?> points = new List <double?>(), betas = new List <double?>(); foreach (Tuple <double?, double?, bool> iter in cPoints) { points.Add(iter.Item1); betas.Add((iter.Item2 * (end - start)) * (iter.Item2 * (end - start))); } // get scaling factor a so that y(1) = end double aInit = 0.0; for (int i = 0; i < points.Count; ++i) { double c1 = Utils.Asinh((start - points[i].GetValueOrDefault()) / betas[i].GetValueOrDefault()); double c2 = Utils.Asinh((end - points[i].GetValueOrDefault()) / betas[i].GetValueOrDefault()); aInit += (c2 - c1) / points.Count; } OdeIntegrationFct fct = new OdeIntegrationFct(points, betas, tol); double a = new Brent().solve( new OdeSolver(fct, start, 0.0, 1.0, end), tol, aInit, 0.1 * aInit); // solve ODE for all grid points Vector x = new Vector(size), y = new Vector(size); x[0] = 0.0; y[0] = start; double dx = 1.0 / (size - 1); for (int i = 1; i < size; ++i) { x[i] = i * dx; y[i] = fct.solve(a, y[i - 1], x[i - 1], x[i]); } // eliminate numerical noise and ensure y(1) = end double dy = y[y.Count - 1] - end; for (int i = 1; i < size; ++i) { y[i] -= i * dx * dy; } LinearInterpolation odeSolution = new LinearInterpolation(x, x.Count, y); // ensure required points are part of the grid List <Pair <double?, double?> > w = new InitializedList <Pair <double?, double?> >(1, new Pair <double?, double?>(0.0, 0.0)); for (int i = 0; i < points.Count; ++i) { if (cPoints[i].Item3 && points[i] > start && points[i] < end) { int j = y.distance(y[0], y.BinarySearch(points[i].Value)); double e = new Brent().solve( new OdeSolver2(odeSolution.value, points[i].Value), Const.QL_EPSILON, x[j], 0.5 / size); w.Add(new Pair <double?, double?>(Math.Min(x[size - 2], x[j]), e)); } } w.Add(new Pair <double?, double?>(1.0, 1.0)); w = w.OrderBy(xx => xx.first).Distinct(new equal_on_first()).ToList(); List <double> u = new List <double>(w.Count), z = new List <double>(w.Count); for (int i = 0; i < w.Count; ++i) { u[i] = w[i].first.GetValueOrDefault(); z[i] = w[i].second.GetValueOrDefault(); } LinearInterpolation transform = new LinearInterpolation(u, u.Count, z); for (int i = 0; i < size; ++i) { locations_[i] = odeSolution.value(transform.value(i * dx)); } for (int i = 0; i < size - 1; ++i) { dplus_[i] = dminus_[i + 1] = locations_[i + 1] - locations_[i]; } dplus_[dplus_.Count] = null; dminus_[0] = null; }
protected Cube sabrCalibration(Cube marketVolCube) { List <double> optionTimes = marketVolCube.optionTimes(); List <double> swapLengths = marketVolCube.swapLengths(); List <Date> optionDates = marketVolCube.optionDates(); List <Period> swapTenors = marketVolCube.swapTenors(); Matrix alphas = new Matrix(optionTimes.Count, swapLengths.Count, 0.0); Matrix betas = new Matrix(alphas); Matrix nus = new Matrix(alphas); Matrix rhos = new Matrix(alphas); Matrix forwards = new Matrix(alphas); Matrix errors = new Matrix(alphas); Matrix maxErrors = new Matrix(alphas); Matrix endCriteria = new Matrix(alphas); List <Matrix> tmpMarketVolCube = marketVolCube.points(); List <double> strikes = new InitializedList <double>(strikeSpreads_.Count); List <double> volatilities = new InitializedList <double>(strikeSpreads_.Count); for (int j = 0; j < optionTimes.Count; j++) { for (int k = 0; k < swapLengths.Count; k++) { double atmForward = atmStrike(optionDates[j], swapTenors[k]); double shiftTmp = atmVol_.link.shift(optionTimes[j], swapLengths[k]); strikes.Clear(); volatilities.Clear(); for (int i = 0; i < nStrikes_; i++) { double strike = atmForward + strikeSpreads_[i]; if (strike + shiftTmp >= cutoffStrike_) { strikes.Add(strike); Matrix matrix = tmpMarketVolCube[i]; volatilities.Add(matrix[j, k]); } } List <double> guess = parametersGuess_.value(optionTimes[j], swapLengths[k]); SABRInterpolation sabrInterpolation = new SABRInterpolation(strikes, strikes.Count, volatilities, optionTimes[j], atmForward, guess[0], guess[1], guess[2], guess[3], isParameterFixed_[0], isParameterFixed_[1], isParameterFixed_[2], isParameterFixed_[3], vegaWeightedSmileFit_, endCriteria_, optMethod_, errorAccept_, useMaxError_, maxGuesses_ );// shiftTmp sabrInterpolation.update(); double rmsError = sabrInterpolation.rmsError(); double maxError = sabrInterpolation.maxError(); alphas [j, k] = sabrInterpolation.alpha(); betas [j, k] = sabrInterpolation.beta(); nus [j, k] = sabrInterpolation.nu(); rhos [j, k] = sabrInterpolation.rho(); forwards [j, k] = atmForward; errors [j, k] = rmsError; maxErrors [j, k] = maxError; endCriteria[j, k] = (double)sabrInterpolation.endCriteria(); Utils.QL_REQUIRE(endCriteria[j, k].IsNotEqual((double)EndCriteria.Type.MaxIterations), () => "global swaptions calibration failed: " + "MaxIterations reached: " + "\n" + "option maturity = " + optionDates[j] + ", \n" + "swap tenor = " + swapTenors[k] + ", \n" + "error = " + (errors[j, k]) + ", \n" + "max error = " + (maxErrors[j, k]) + ", \n" + " alpha = " + alphas[j, k] + "n" + " beta = " + betas[j, k] + "\n" + " nu = " + nus[j, k] + "\n" + " rho = " + rhos[j, k] + "\n" ); Utils.QL_REQUIRE(useMaxError_ ? maxError > 0 : rmsError < maxErrorTolerance_, () => "global swaptions calibration failed: " + "option tenor " + optionDates[j] + ", swap tenor " + swapTenors[k] + (useMaxError_ ? ": max error " : ": error") + (useMaxError_ ? maxError : rmsError) + " alpha = " + alphas[j, k] + "\n" + " beta = " + betas[j, k] + "\n" + " nu = " + nus[j, k] + "\n" + " rho = " + rhos[j, k] + "\n" + (useMaxError_ ? ": error" : ": max error ") + (useMaxError_ ? rmsError :maxError) ); } } Cube sabrParametersCube = new Cube(optionDates, swapTenors, optionTimes, swapLengths, 8, true, backwardFlat_); sabrParametersCube.setLayer(0, alphas); sabrParametersCube.setLayer(1, betas); sabrParametersCube.setLayer(2, nus); sabrParametersCube.setLayer(3, rhos); sabrParametersCube.setLayer(4, forwards); sabrParametersCube.setLayer(5, errors); sabrParametersCube.setLayer(6, maxErrors); sabrParametersCube.setLayer(7, endCriteria); return(sabrParametersCube); }
public override void calculate() { /* this engine cannot really check for the averageType==Geometric * since it can be used as control variate for the Arithmetic version * QL_REQUIRE(arguments_.averageType == Average::Geometric, * "not a geometric average option"); */ if (!(arguments_.exercise.type() == Exercise.Type.European)) { throw new ApplicationException("not an European Option"); } double runningLog; int pastFixings; if (arguments_.averageType == Average.Type.Geometric) { if (!(arguments_.runningAccumulator > 0.0)) { throw new ApplicationException("positive running product required: " + arguments_.runningAccumulator + " not allowed"); } runningLog = Math.Log(arguments_.runningAccumulator.GetValueOrDefault()); pastFixings = arguments_.pastFixings.GetValueOrDefault(); } else // it is being used as control variate { runningLog = 1.0; pastFixings = 0; } PlainVanillaPayoff payoff = (PlainVanillaPayoff)(arguments_.payoff); if (payoff == null) { throw new ApplicationException("non-plain payoff given"); } Date referenceDate = process_.riskFreeRate().link.referenceDate(); DayCounter rfdc = process_.riskFreeRate().link.dayCounter(); DayCounter divdc = process_.dividendYield().link.dayCounter(); DayCounter voldc = process_.blackVolatility().link.dayCounter(); List <double> fixingTimes = new InitializedList <double>(arguments_.fixingDates.Count()); int i; for (i = 0; i < arguments_.fixingDates.Count(); i++) { if (arguments_.fixingDates[i] >= referenceDate) { double t = voldc.yearFraction(referenceDate, arguments_.fixingDates[i]); fixingTimes.Add(t); } } int remainingFixings = fixingTimes.Count(); int numberOfFixings = pastFixings + remainingFixings; double N = numberOfFixings; double pastWeight = pastFixings / N; double futureWeight = 1.0 - pastWeight; /*double timeSum = std::accumulate(fixingTimes.begin(), * fixingTimes.end(), 0.0);*/ double timeSum = 0; fixingTimes.ForEach((ii, vv) => timeSum += fixingTimes[ii]); double vola = process_.blackVolatility().link.blackVol( arguments_.exercise.lastDate(), payoff.strike()); double temp = 0.0; for (i = pastFixings + 1; i < numberOfFixings; i++) { temp += fixingTimes[i - pastFixings - 1] * (N - i); } double variance = vola * vola / N / N * (timeSum + 2.0 * temp); double dsigG_dsig = Math.Sqrt((timeSum + 2.0 * temp)) / N; double sigG = vola * dsigG_dsig; double dmuG_dsig = -(vola * timeSum) / N; Date exDate = arguments_.exercise.lastDate(); double dividendRate = process_.dividendYield().link. zeroRate(exDate, divdc, Compounding.Continuous, Frequency.NoFrequency).rate(); double riskFreeRate = process_.riskFreeRate().link. zeroRate(exDate, rfdc, Compounding.Continuous, Frequency.NoFrequency).rate(); double nu = riskFreeRate - dividendRate - 0.5 * vola * vola; double s = process_.stateVariable().link.value(); if (!(s > 0.0)) { throw new ApplicationException("positive underlying value required"); } int M = (pastFixings == 0 ? 1 : pastFixings); double muG = pastWeight * runningLog / M + futureWeight * Math.Log(s) + nu * timeSum / N; double forwardPrice = Math.Exp(muG + variance / 2.0); double riskFreeDiscount = process_.riskFreeRate().link.discount( arguments_.exercise.lastDate()); BlackCalculator black = new BlackCalculator(payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount); results_.value = black.value(); results_.delta = futureWeight * black.delta(forwardPrice) * forwardPrice / s; results_.gamma = forwardPrice * futureWeight / (s * s) * (black.gamma(forwardPrice) * futureWeight * forwardPrice - pastWeight * black.delta(forwardPrice)); double Nx_1, nx_1; CumulativeNormalDistribution CND = new CumulativeNormalDistribution(); NormalDistribution ND = new NormalDistribution(); if (sigG > Const.QL_Epsilon) { double x_1 = (muG - Math.Log(payoff.strike()) + variance) / sigG; Nx_1 = CND.value(x_1); nx_1 = ND.value(x_1); } else { Nx_1 = (muG > Math.Log(payoff.strike()) ? 1.0 : 0.0); nx_1 = 0.0; } results_.vega = forwardPrice * riskFreeDiscount * ((dmuG_dsig + sigG * dsigG_dsig) * Nx_1 + nx_1 * dsigG_dsig); if (payoff.optionType() == Option.Type.Put) { results_.vega -= riskFreeDiscount * forwardPrice * (dmuG_dsig + sigG * dsigG_dsig); } double tRho = rfdc.yearFraction(process_.riskFreeRate().link.referenceDate(), arguments_.exercise.lastDate()); results_.rho = black.rho(tRho) * timeSum / (N * tRho) - (tRho - timeSum / N) * results_.value; double tDiv = divdc.yearFraction( process_.dividendYield().link.referenceDate(), arguments_.exercise.lastDate()); results_.dividendRho = black.dividendRho(tDiv) * timeSum / (N * tDiv); results_.strikeSensitivity = black.strikeSensitivity(); results_.theta = Utils.blackScholesTheta(process_, results_.value.GetValueOrDefault(), results_.delta.GetValueOrDefault(), results_.gamma.GetValueOrDefault()); }
protected GMRESResult solveImpl(Vector b, Vector x0) { double bn = Vector.Norm2(b); GMRESResult result; if (bn.IsEqual(0.0)) { result = new GMRESResult(new InitializedList <double>(1, 0.0), b); return(result); } Vector x = !x0.empty() ? x0 : new Vector(b.size(), 0.0); Vector r = b - A_(x); double g = Vector.Norm2(r); if (g / bn < relTol_) { result = new GMRESResult(new InitializedList <double>(1, g / bn), x); return(result); } List <Vector> v = new InitializedList <Vector>(1, r / g); List <Vector> h = new InitializedList <Vector>(1, new Vector(maxIter_, 0.0)); List <double> c = new List <double>(maxIter_ + 1), s = new List <double>(maxIter_ + 1), z = new List <double>(maxIter_ + 1); z[0] = g; List <double> errors = new InitializedList <double>(1, g / bn); for (int j = 0; j < maxIter_ && errors.Last() >= relTol_; ++j) { h.Add(new Vector(maxIter_, 0.0)); Vector w = A_((M_ != null) ? M_(v[j]) : v[j]); for (int i = 0; i <= j; ++i) { h[i][j] = Vector.DotProduct(w, v[i]); w -= h[i][j] * v[i]; } h[j + 1][j] = Vector.Norm2(w); if (h[j + 1][j] < Const.QL_EPSILON * Const.QL_EPSILON) { break; } v.Add(w / h[j + 1][j]); for (int i = 0; i < j; ++i) { double h0 = c[i] * h[i][j] + s[i] * h[i + 1][j]; double h1 = -s[i] * h[i][j] + c[i] * h[i + 1][j]; h[i][j] = h0; h[i + 1][j] = h1; } double nu = Math.Sqrt((h[j][j]) * (h[j][j]) + (h[j + 1][j]) * (h[j + 1][j])); c[j] = h[j][j] / nu; s[j] = h[j + 1][j] / nu; h[j][j] = nu; h[j + 1][j] = 0.0; z[j + 1] = -s[j] * z[j]; z[j] = c[j] * z[j]; errors.Add(Math.Abs(z[j + 1] / bn)); } int k = v.Count - 1; Vector y = new Vector(k, 0.0); y[k - 1] = z[k - 1] / h[k - 1][k - 1]; for (int i = k - 2; i >= 0; --i) { y[i] = (z[i] - h[i].inner_product( i + 1, k, i + 1, y, 0.0)) / h[i][i]; } Vector xm = new Vector(x.Count, 0.0); for (int i = 0; i < x.Count; i++) { xm[i] = v[i].inner_product(0, k, 0, y, 0.0); } xm = x + ((M_ != null) ? M_(xm) : xm); result = new GMRESResult(errors, xm); return(result); }