/// <summary> /// Calculate the Option Adjusted Spread (OAS) /// <remarks> /// Calculates the spread that needs to be added to the the /// reference curve so that the theoretical model value /// matches the marketPrice. /// </remarks> /// </summary> /// <param name="cleanPrice"></param> /// <param name="engineTS"></param> /// <param name="dayCounter"></param> /// <param name="compounding"></param> /// <param name="frequency"></param> /// <param name="settlement"></param> /// <param name="accuracy"></param> /// <param name="maxIterations"></param> /// <param name="guess"></param> /// <returns></returns> public double OAS(double cleanPrice, Handle <YieldTermStructure> engineTS, DayCounter dayCounter, Compounding compounding, Frequency frequency, Date settlement = null, double accuracy = 1.0e-10, int maxIterations = 100, double guess = 0.0) { if (settlement == null) { settlement = settlementDate(); } double dirtyPrice = cleanPrice + accruedAmount(settlement); var f = new NpvSpreadHelper(this); OasHelper obj = new OasHelper(f, dirtyPrice); Brent solver = new Brent(); solver.setMaxEvaluations(maxIterations); double step = 0.001; double oas = solver.solve(obj, accuracy, guess, step); return(continuousToConv(oas, this, engineTS, dayCounter, compounding, frequency)); }
//! 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); } }
private double strikeFromPrice(double price, Option.Type optionType, double referenceStrike) { double a, b, min, max, k; if (optionType == Option.Type.Call) { a = swapRateValue_; min = referenceStrike; b = max = k = Math.Min(smileSection_.maxStrike(), shiftedUpperBound_); } else { a = min = k = Math.Max(smileSection_.minStrike(), shiftedLowerBound_); b = swapRateValue_; max = referenceStrike; } PriceHelper h = new PriceHelper(smileSection_, optionType, price); Brent solver = new Brent(); try { k = solver.solve(h, 1.0E-5, swapRateValue_, a, b); } catch (Exception) { // use default value set above } return(Math.Min(Math.Max(k, min), max)); }
public double value(double x) { // first find the right side of the interval double upper = guess_; int evaluations = maxEvaluations_; while (nonCentralDist_.value(upper) < x && evaluations > 0) { upper *= 2.0; --evaluations; } // use a brent solver for the rest Brent solver = new Brent(); solver.setMaxEvaluations(evaluations); /*return solver.solve(compose(std::bind2nd(std::minus<Real>(),x), * nonCentralDist_), * accuracy_, 0.75*upper, * (evaluations == maxEvaluations_)? 0.0: 0.5*upper, * upper);*/ return(0d); }
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; }
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); }
//! Black volatility implied by the model public double impliedVolatility(double targetValue, double accuracy, int maxEvaluations, double minVol, double maxVol) { ImpliedVolatilityHelper f = new ImpliedVolatilityHelper(this, targetValue); Brent solver = new Brent(); solver.setMaxEvaluations(maxEvaluations); return solver.solve(f,accuracy,volatility_.link.value(), minVol, maxVol); }
//! Black volatility implied by the model public double impliedVolatility(double targetValue, double accuracy, int maxEvaluations, double minVol, double maxVol) { ImpliedVolatilityHelper f = new ImpliedVolatilityHelper(this, targetValue); Brent solver = new Brent(); solver.setMaxEvaluations(maxEvaluations); return(solver.solve(f, accuracy, volatility_.link.value(), minVol, maxVol)); }
public double yield(DayCounter dc, Compounding comp, Frequency freq, double accuracy, int maxEvaluations) { Brent solver = new Brent(); solver.setMaxEvaluations(maxEvaluations); YieldFinder objective = new YieldFinder(notional(settlementDate()), cashflows_, dirtyPrice(), dc, comp, freq, settlementDate()); return(solver.solve(objective, accuracy, 0.02, 0.0, 1.0)); }
public double MonthlyYield() { Brent solver = new Brent(); solver.setMaxEvaluations(100); List <CashFlow> cf = expectedCashflows(); MonthlyYieldFinder objective = new MonthlyYieldFinder(notional(settlementDate()), cf, settlementDate()); return(solver.solve(objective, 1.0e-10, 0.02, 0.0, 1.0) / 100); }
public static double calculate(Instrument instrument, IPricingEngine engine, SimpleQuote volQuote, double targetValue, double accuracy, int maxEvaluations, double minVol, double maxVol) { instrument.setupArguments(engine.getArguments()); engine.getArguments().validate(); PriceError f = new PriceError(engine, volQuote, targetValue); Brent solver = new Brent(); solver.setMaxEvaluations(maxEvaluations); double guess = (minVol + maxVol) / 2.0; double result = solver.solve(f, accuracy, guess, minVol, maxVol); return result; }
public static double calculate(Instrument instrument, IPricingEngine engine, SimpleQuote volQuote, double targetValue, double accuracy, int maxEvaluations, double minVol, double maxVol) { instrument.setupArguments(engine.getArguments()); engine.getArguments().validate(); PriceError f = new PriceError(engine, volQuote, targetValue); Brent solver = new Brent(); solver.setMaxEvaluations(maxEvaluations); double guess = (minVol + maxVol) / 2.0; double result = solver.solve(f, accuracy, guess, minVol, maxVol); return(result); }
public double value(double x) { // first find the right side of the interval double upper = guess_; int evaluations = maxEvaluations_; while (nonCentralDist_.value(upper) < x && evaluations > 0) { upper*=2.0; --evaluations; } // use a brent solver for the rest Brent solver = new Brent(); solver.setMaxEvaluations(evaluations); return 0d; }
/*! Extrapolation for unknown order of convergence * \param t first scaling factor for the step size * \param s second scaling factor for the step size */ public double value(double t, double s) { Utils.QL_REQUIRE(t > 1 && s > 1, () => "scaling factors must be greater than 1"); Utils.QL_REQUIRE(t > s, () => "t must be greater than s"); double ft = f_(delta_h_ / t); double fs = f_(delta_h_ / s); double k = new Brent().solve(new RichardsonEqn(fdelta_h_, ft, fs, t, s), 1e-8, 0.05, 10); double ts = Math.Pow(s, k); return((ts * fs - fdelta_h_) / (ts - 1.0)); }
private List <double> spreadsVolImplied() { Brent solver = new Brent(); List <double> result = new InitializedList <double>(nOptionExpiries_, 0.0); double guess = 0.0001, minSpread = -0.1, maxSpread = 0.1; for (int j = 0; j < nOptionExpiries_; ++j) { ObjectiveFunction f = new ObjectiveFunction(stripper1_, caps_[j], atmCapFloorPrices_[j]); solver.setMaxEvaluations(maxEvaluations_); double root = solver.solve(f, accuracy_, guess, minSpread, maxSpread); result[j] = root; } return(result); }
public double yield(double cleanPrice, DayCounter dc, Compounding comp, Frequency freq, Date settlement, double accuracy, int maxEvaluations) { if (settlement == null) { settlement = settlementDate(); } Brent solver = new Brent(); solver.setMaxEvaluations(maxEvaluations); double dirtyPrice = cleanPrice + accruedAmount(settlement); YieldFinder objective = new YieldFinder(notional(settlement), cashflows_, dirtyPrice, dc, comp, freq, settlement); return(solver.solve(objective, accuracy, 0.02, 0.0, 1.0)); }
protected override double blackVolImpl(double t, double strike) { HestonProcess process = hestonModel_.link.process(); double df = process.riskFreeRate().link.discount(t, true); double div = process.dividendYield().link.discount(t, true); double spotPrice = process.s0().link.value(); double fwd = spotPrice * process.dividendYield().link.discount(t, true) / process.riskFreeRate().link.discount(t, true); var payoff = new PlainVanillaPayoff(fwd > strike ? Option.Type.Put : Option.Type.Call, strike); double kappa = hestonModel_.link.kappa(); double theta = hestonModel_.link.theta(); double rho = hestonModel_.link.rho(); double sigma = hestonModel_.link.sigma(); double v0 = hestonModel_.link.v0(); AnalyticHestonEngine.ComplexLogFormula cpxLogFormula = AnalyticHestonEngine.ComplexLogFormula.Gatheral; AnalyticHestonEngine hestonEnginePtr = null; double?npv = null; int evaluations = 0; AnalyticHestonEngine.doCalculation( df, div, spotPrice, strike, t, kappa, theta, sigma, v0, rho, payoff, integration_, cpxLogFormula, hestonEnginePtr, ref npv, ref evaluations); if (npv <= 0.0) { return(Math.Sqrt(theta)); } Brent solver = new Brent(); solver.setMaxEvaluations(10000); double guess = Math.Sqrt(theta); double accuracy = Const.QL_EPSILON; var f = new ImpliedVolHelper(payoff.optionType(), strike, fwd, t, df, npv.Value); return(solver.solve(f, accuracy, guess, 0.01)); }
//@} //! \name Calculations //@{ //! returns the Black implied forward yield volatility /*! the forward yield volatility, see Hull, Fourth Edition, * Chapter 20, pg 536). Relevant only to European put/call * schedules */ public double impliedVolatility(double targetValue, Handle <YieldTermStructure> discountCurve, double accuracy, int maxEvaluations, double minVol, double maxVol) { calculate(); Utils.QL_REQUIRE(!isExpired(), () => "instrument expired"); double guess = 0.5 * (minVol + maxVol); blackDiscountCurve_.linkTo(discountCurve, false); ImpliedVolHelper f = new ImpliedVolHelper(this, targetValue); Brent solver = new Brent(); solver.setMaxEvaluations(maxEvaluations); return(solver.solve(f, accuracy, guess, minVol, maxVol)); }
public double value(double x) { CumulativeNormalDistribution phi = new CumulativeNormalDistribution(); double temp = (x - mux_) / sigmax_; double txy = Math.Sqrt(1.0 - rhoxy_ * rhoxy_); Vector lambda = new Vector(size_); int i; for (i = 0; i < size_; i++) { double tau = (i == 0 ? t_[0] - T_ : t_[i] - t_[i - 1]); double c = (i == size_ - 1 ? (1.0 + rate_ * tau) : rate_ * tau); lambda[i] = c * A_[i] * Math.Exp(-Ba_[i] * x); } //SolvingFunction function = new SolvingFunction(lambda, Bb_); //verifier le polymorphisme SolvingFunction function = new SolvingFunction(lambda, Bb_); Brent s1d = new Brent(); s1d.setMaxEvaluations(1000); double yb = s1d.solve(function, 1e-6, 0.00, -100.0, 100.0); double h1 = (yb - muy_) / (sigmay_ * txy) - rhoxy_ * (x - mux_) / (sigmax_ * txy); double value = phi.value(-w_ * h1); for (i = 0; i < size_; i++) { double h2 = h1 + Bb_[i] * sigmay_ *Math.Sqrt(1.0 - rhoxy_ *rhoxy_); double kappa = -Bb_[i] * (muy_ - 0.5 * txy * txy * sigmay_ * sigmay_ * Bb_[i] + rhoxy_ * sigmay_ * (x - mux_) / sigmax_); value -= lambda[i] * Math.Exp(kappa) * phi.value(-w_ * h2); } return(Math.Exp(-0.5 * temp * temp) * value / (sigmax_ * Math.Sqrt(2.0 * QLNet.Const.M_PI))); }
public double value(double x) { // first find the right side of the interval double upper = guess_; int evaluations = maxEvaluations_; while (nonCentralDist_.value(upper) < x && evaluations > 0) { upper *= 2.0; --evaluations; } // use a brent solver for the rest Brent solver = new Brent(); solver.setMaxEvaluations(evaluations); return(solver.solve(new IncChiQuareFinder(x, nonCentralDist_.value), accuracy_, 0.75 * upper, (evaluations == maxEvaluations_) ? 0.0 : 0.5 * upper, upper)); }
//! implied Z-spread. public static double zSpread(Leg leg, double npv, YieldTermStructure discount, DayCounter dayCounter, Compounding compounding, Frequency frequency, bool includeSettlementDateFlows, Date settlementDate = null, Date npvDate = null, double accuracy = 1.0e-10, int maxIterations = 100, double guess = 0.0) { if (settlementDate == null) { settlementDate = Settings.evaluationDate(); } if (npvDate == null) { npvDate = settlementDate; } Brent solver = new Brent(); solver.setMaxEvaluations(maxIterations); ZSpreadFinder objFunction = new ZSpreadFinder(leg, discount, npv, dayCounter, compounding, frequency, includeSettlementDateFlows, settlementDate, npvDate); double step = 0.01; return(solver.solve(objFunction, accuracy, guess, step)); }
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; }
// alternative delta type private double strikeFromDelta(double delta, DeltaVolQuote.DeltaType dt) { double res = 0.0; double arg = 0.0; InverseCumulativeNormal f = new InverseCumulativeNormal(); Utils.QL_REQUIRE(delta * phi_ >= 0.0, () => "Option type and delta are incoherent."); switch (dt) { case DeltaVolQuote.DeltaType.Spot: Utils.QL_REQUIRE(Math.Abs(delta) <= fDiscount_, () => "Spot delta out of range."); arg = -phi_ *f.value(phi_ *delta / fDiscount_) * stdDev_ + 0.5 * stdDev_ * stdDev_; res = forward_ * Math.Exp(arg); break; case DeltaVolQuote.DeltaType.Fwd: Utils.QL_REQUIRE(Math.Abs(delta) <= 1.0, () => "Forward delta out of range."); arg = -phi_ *f.value(phi_ *delta) * stdDev_ + 0.5 * stdDev_ * stdDev_; res = forward_ * Math.Exp(arg); break; case DeltaVolQuote.DeltaType.PaSpot: case DeltaVolQuote.DeltaType.PaFwd: // This has to be solved numerically. One of the // problems is that the premium adjusted call delta is // not monotonic in strike, such that two solutions // might occur. The one right to the max of the delta is // considered to be the correct strike. Some proper // interval bounds for the strike need to be chosen, the // numerics can otherwise be very unreliable and // unstable. I've chosen Brent over Newton, since the // interval can be specified explicitly and we can not // run into the area on the left of the maximum. The // put delta doesn't have this property and can be // solved without any problems, but also numerically. BlackDeltaPremiumAdjustedSolverClass f1 = new BlackDeltaPremiumAdjustedSolverClass( ot_, dt, spot_, dDiscount_, fDiscount_, stdDev_, delta); Brent solver = new Brent(); solver.setMaxEvaluations(1000); double accuracy = 1.0e-10; double rightLimit = 0.0; double leftLimit = 0.0; // Strike of not premium adjusted is always to the right of premium adjusted if (dt == DeltaVolQuote.DeltaType.PaSpot) { rightLimit = strikeFromDelta(delta, DeltaVolQuote.DeltaType.Spot); } else { rightLimit = strikeFromDelta(delta, DeltaVolQuote.DeltaType.Fwd); } if (phi_ < 0) { // if put res = solver.solve(f1, accuracy, rightLimit, 0.0, spot_ * 100.0); break; } else { // find out the left limit which is the strike // corresponding to the value where premium adjusted // deltas have their maximum. BlackDeltaPremiumAdjustedMaxStrikeClass g = new BlackDeltaPremiumAdjustedMaxStrikeClass( ot_, dt, spot_, dDiscount_, fDiscount_, stdDev_); leftLimit = solver.solve(g, accuracy, rightLimit * 0.5, 0.0, rightLimit); double guess = leftLimit + (rightLimit - leftLimit) * 0.5; res = solver.solve(f1, accuracy, guess, leftLimit, rightLimit); } // end if phi<0 else break; default: Utils.QL_FAIL("invalid delta type"); break; } return(res); }
public void calculate() { //prepare instruments int n = ts_.instruments_.Count, i; // ensure rate helpers are sorted ts_.instruments_.Sort((x, y) => x.latestDate().CompareTo(y.latestDate())); // check that there is no instruments with the same maturity for (i = 1; i < n; ++i) { Date m1 = ts_.instruments_[i - 1].latestDate(), m2 = ts_.instruments_[i].latestDate(); if (m1 == m2) { throw new ArgumentException("two instruments have the same maturity (" + m1 + ")"); } } // check that there is no instruments with invalid quote if ((i = ts_.instruments_.FindIndex(x => !x.quoteIsValid())) != -1) { throw new ArgumentException("instrument " + i + " (maturity: " + ts_.instruments_[i].latestDate() + ") has an invalid quote"); } // setup instruments and register with them ts_.instruments_.ForEach(x => x.setTermStructure(ts_)); // calculate dates and times ts_.dates_ = new InitializedList <Date>(n + 1); ts_.times_ = new InitializedList <double>(n + 1); ts_.dates_[0] = ts_.initialDate(ts_); ts_.times_[0] = ts_.timeFromReference(ts_.dates_[0]); for (i = 0; i < n; ++i) { ts_.dates_[i + 1] = ts_.instruments_[i].latestDate(); ts_.times_[i + 1] = ts_.timeFromReference(ts_.dates_[i + 1]); } // set initial guess only if the current curve cannot be used as guess if (validCurve_) { if (ts_.data_.Count != n + 1) { throw new ArgumentException("dimension mismatch: expected " + n + 1 + ", actual " + ts_.data_.Count); } } else { ts_.data_ = new InitializedList <double>(n + 1); ts_.data_[0] = ts_.initialValue(ts_); for (i = 0; i < n; ++i) { ts_.data_[i + 1] = ts_.initialGuess(); } } Brent solver = new Brent(); int maxIterations = ts_.maxIterations(); for (int iteration = 0; ; ++iteration) { List <double> previousData = ts_.data(); // restart from the previous interpolation if (validCurve_) { ts_.interpolation_ = ts_.interpolator_.interpolate(ts_.times_, ts_.times_.Count, ts_.data_); } for (i = 1; i < n + 1; ++i) { // calculate guess before extending interpolation to ensure that any extrapolation is performed // using the curve bootstrapped so far and no more RateHelper instrument = ts_.instruments_[i - 1]; double guess = 0; if (validCurve_ || iteration > 0) { guess = ts_.data_[i]; } else if (i == 1) { guess = ts_.initialGuess(); } else { // most traits extrapolate guess = ts_.guess(ts_, ts_.dates_[i]); } // bracket double min = ts_.minValueAfter(i, ts_.data_); double max = ts_.maxValueAfter(i, ts_.data_); if (guess <= min || guess >= max) { guess = (min + max) / 2.0; } if (!validCurve_ && iteration == 0) { // extend interpolation a point at a time try { ts_.interpolation_ = ts_.interpolator_.interpolate(ts_.times_, i + 1, ts_.data_); } catch { if (!ts_.interpolator_.global) { throw; // no chance to fix it in a later iteration } // otherwise, if the target interpolation is not usable yet ts_.interpolation_ = new Linear().interpolate(ts_.times_, i + 1, ts_.data_); } } // required because we just changed the data // is it really required? ts_.interpolation_.update(); try { var error = new BootstrapError(ts_, instrument, i); double r = solver.solve(error, ts_.accuracy_, guess, min, max); // redundant assignment (as it has been already performed by BootstrapError in solve procedure), but safe ts_.data_[i] = r; } catch (Exception e) { validCurve_ = false; throw new ArgumentException(" iteration: " + iteration + 1 + "could not bootstrap the " + i + " instrument, maturity " + ts_.dates_[i] + ": " + e.Message); } } if (!ts_.interpolator_.global) { break; // no need for convergence loop } else if (!validCurve_ && iteration == 0) { // ensure the target interpolation is used ts_.interpolation_ = ts_.interpolator_.interpolate(ts_.times_, ts_.times_.Count, ts_.data_); // at least one more iteration is needed to check convergence continue; } // exit conditions double improvement = 0.0; for (i = 1; i < n + 1; ++i) { improvement = Math.Max(improvement, Math.Abs(ts_.data_[i] - previousData[i])); } if (improvement <= ts_.accuracy_) // convergence reached { break; } if (!(iteration + 1 < maxIterations)) { throw new ArgumentException("convergence not reached after " + iteration + 1 + " iterations; last improvement " + improvement + ", required accuracy " + ts_.accuracy_); } } validCurve_ = true; }
public void calculate() { //prepare instruments int n = ts_.instruments_.Count, i; // ensure rate helpers are sorted ts_.instruments_.Sort((x, y) => x.latestDate().CompareTo(y.latestDate())); // check that there is no instruments with the same maturity for (i = 1; i < n; ++i) { Date m1 = ts_.instruments_[i - 1].latestDate(), m2 = ts_.instruments_[i].latestDate(); if (m1 == m2) throw new ArgumentException("two instruments have the same maturity (" + m1 + ")"); } // check that there is no instruments with invalid quote if ((i = ts_.instruments_.FindIndex(x => !x.quoteIsValid())) != -1) throw new ArgumentException("instrument " + i + " (maturity: " + ts_.instruments_[i].latestDate() + ") has an invalid quote"); // setup instruments and register with them ts_.instruments_.ForEach(x => x.setTermStructure(ts_)); // calculate dates and times ts_.dates_ = new InitializedList<Date>(n + 1); ts_.times_ = new InitializedList<double>(n + 1); ts_.dates_[0] = ts_.initialDate(ts_); ts_.times_[0] = ts_.timeFromReference(ts_.dates_[0]); for (i = 0; i < n; ++i) { ts_.dates_[i + 1] = ts_.instruments_[i].latestDate(); ts_.times_[i + 1] = ts_.timeFromReference(ts_.dates_[i + 1]); } // set initial guess only if the current curve cannot be used as guess if (validCurve_) { if (ts_.data_.Count != n + 1) throw new ArgumentException("dimension mismatch: expected " + n + 1 + ", actual " + ts_.data_.Count); } else { ts_.data_ = new InitializedList<double>(n + 1); ts_.data_[0] = ts_.initialValue(ts_); for (i=0; i<n; ++i) ts_.data_[i+1] = ts_.initialGuess(); } Brent solver = new Brent(); int maxIterations = ts_.maxIterations(); for (int iteration=0; ; ++iteration) { List<double> previousData = ts_.data(); // restart from the previous interpolation if (validCurve_) { ts_.interpolation_ = ts_.interpolator_.interpolate(ts_.times_, ts_.times_.Count, ts_.data_); } for (i=1; i<n+1; ++i) { // calculate guess before extending interpolation to ensure that any extrapolation is performed // using the curve bootstrapped so far and no more RateHelper instrument = ts_.instruments_[i-1]; double guess = 0; if (validCurve_ || iteration>0) { guess = ts_.data_[i]; } else if (i==1) { guess = ts_.initialGuess(); } else { // most traits extrapolate guess = ts_.guess(ts_, ts_.dates_[i]); } // bracket double min = ts_.minValueAfter(i, ts_.data_); double max = ts_.maxValueAfter(i, ts_.data_); if (guess <= min || guess >= max) guess = (min + max) / 2.0; if (!validCurve_ && iteration == 0) { // extend interpolation a point at a time try { ts_.interpolation_ = ts_.interpolator_.interpolate(ts_.times_, i + 1, ts_.data_); } catch { if (!ts_.interpolator_.global) throw; // no chance to fix it in a later iteration // otherwise, if the target interpolation is not usable yet ts_.interpolation_ = new Linear().interpolate(ts_.times_, i + 1, ts_.data_); } } // required because we just changed the data // is it really required? ts_.interpolation_.update(); try { var error = new BootstrapError(ts_, instrument, i); double r = solver.solve(error, ts_.accuracy_, guess, min, max); // redundant assignment (as it has been already performed by BootstrapError in solve procedure), but safe ts_.data_[i] = r; } catch (Exception e) { validCurve_ = false; throw new ArgumentException(" iteration: " + iteration + 1 + "could not bootstrap the " + i + " instrument, maturity " + ts_.dates_[i] + ": " + e.Message); } } if (!ts_.interpolator_.global) break; // no need for convergence loop else if (!validCurve_ && iteration == 0) { // ensure the target interpolation is used ts_.interpolation_ = ts_.interpolator_.interpolate(ts_.times_, ts_.times_.Count, ts_.data_); // at least one more iteration is needed to check convergence continue; } // exit conditions double improvement = 0.0; for (i=1; i<n+1; ++i) improvement = Math.Max(improvement, Math.Abs(ts_.data_[i]-previousData[i])); if (improvement<=ts_.accuracy_) // convergence reached break; if (!(iteration+1 < maxIterations)) throw new ArgumentException("convergence not reached after " + iteration+1 + " iterations; last improvement " + improvement + ", required accuracy " + ts_.accuracy_); } validCurve_ = true; }
/*! Extrapolation for unknown order of convergence \param t first scaling factor for the step size \param s second scaling factor for the step size */ public double value( double t, double s ) { Utils.QL_REQUIRE(t > 1 && s > 1, ()=>"scaling factors must be greater than 1"); Utils.QL_REQUIRE(t > s, ()=> "t must be greater than s"); double ft = f_(delta_h_/t); double fs = f_(delta_h_/s); double k = new Brent().solve(new RichardsonEqn(fdelta_h_, ft, fs, t, s), 1e-8, 0.05, 10); double ts = Math.Pow(s, k); return (ts*fs-fdelta_h_)/(ts-1.0); }
public double value(double x) { CumulativeNormalDistribution phi = new CumulativeNormalDistribution(); double temp = (x - mux_)/sigmax_; double txy = Math.Sqrt(1.0 - rhoxy_*rhoxy_); Vector lambda = new Vector(size_); int i; for (i=0; i<size_; i++) { double tau = (i==0 ? t_[0] - T_ : t_[i] - t_[i-1]); double c = (i==size_-1 ? (1.0+rate_*tau) : rate_*tau); lambda[i] = c*A_[i]*Math.Exp(-Ba_[i]*x); } //SolvingFunction function = new SolvingFunction(lambda, Bb_); //verifier le polymorphisme SolvingFunction function = new SolvingFunction(lambda, Bb_); Brent s1d = new Brent(); s1d.setMaxEvaluations(1000); double yb = s1d.solve(function, 1e-6, 0.00, -100.0, 100.0); double h1 = (yb - muy_)/(sigmay_*txy) - rhoxy_*(x - mux_)/(sigmax_*txy); double value = phi.value(-w_*h1); for (i=0; i<size_; i++) { double h2 = h1 + Bb_[i]*sigmay_*Math.Sqrt(1.0-rhoxy_*rhoxy_); double kappa = - Bb_[i] * (muy_ - 0.5*txy*txy*sigmay_*sigmay_*Bb_[i] + rhoxy_*sigmay_*(x-mux_)/sigmax_); value -= lambda[i] *Math.Exp(kappa)*phi.value(-w_*h2); } return Math.Exp(-0.5*temp*temp)*value/ (sigmax_*Math.Sqrt(2.0*QLNet.Const.M_PI)); }
public override Vector evolve(double t0, Vector x0, double dt, Vector dw) { Vector retVal = new Vector(2); double vol, vol2, mu, nu, dy; double sdt = Math.Sqrt(dt); double sqrhov = Math.Sqrt(1.0 - rho_ * rho_); switch (discretization_) { // For the definition of PartialTruncation, FullTruncation // and Reflection see Lord, R., R. Koekkoek and D. van Dijk (2006), // "A Comparison of biased simulation schemes for // stochastic volatility models", // Working Paper, Tinbergen Institute case Discretization.PartialTruncation: vol = (x0[1] > 0.0) ? Math.Sqrt(x0[1]) : 0.0; vol2 = sigma_ * vol; mu = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - 0.5 * vol * vol; nu = kappa_ * (theta_ - x0[1]); retVal[0] = x0[0] * Math.Exp(mu * dt + vol * dw[0] * sdt); retVal[1] = x0[1] + nu * dt + vol2 * sdt * (rho_ * dw[0] + sqrhov * dw[1]); break; case Discretization.FullTruncation: vol = (x0[1] > 0.0) ? Math.Sqrt(x0[1]) : 0.0; vol2 = sigma_ * vol; mu = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - 0.5 * vol * vol; nu = kappa_ * (theta_ - vol * vol); retVal[0] = x0[0] * Math.Exp(mu * dt + vol * dw[0] * sdt); retVal[1] = x0[1] + nu * dt + vol2 * sdt * (rho_ * dw[0] + sqrhov * dw[1]); break; case Discretization.Reflection: vol = Math.Sqrt(Math.Abs(x0[1])); vol2 = sigma_ * vol; mu = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - 0.5 * vol * vol; nu = kappa_ * (theta_ - vol * vol); retVal[0] = x0[0] * Math.Exp(mu * dt + vol * dw[0] * sdt); retVal[1] = vol * vol + nu * dt + vol2 * sdt * (rho_ * dw[0] + sqrhov * dw[1]); break; case Discretization.NonCentralChiSquareVariance: // use Alan Lewis trick to decorrelate the equity and the variance // process by using y(t)=x(t)-\frac{rho}{sigma}\nu(t) // and Ito's Lemma. Then use exact sampling for the variance // process. For further details please read the Wilmott thread // "QuantLib code is very high quality" vol = (x0[1] > 0.0) ? Math.Sqrt(x0[1]) : 0.0; mu = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - 0.5 * vol * vol; retVal[1] = varianceDistribution(x0[1], dw[1], dt); dy = (mu - rho_ / sigma_ * kappa_ * (theta_ - vol * vol)) * dt + vol * sqrhov * dw[0] * sdt; retVal[0] = x0[0] * Math.Exp(dy + rho_ / sigma_ * (retVal[1] - x0[1])); break; case Discretization.QuadraticExponential: case Discretization.QuadraticExponentialMartingale: { // for details of the quadratic exponential discretization scheme // see Leif Andersen, // Efficient Simulation of the Heston Stochastic Volatility Model double ex = Math.Exp(-kappa_ * dt); double m = theta_ + (x0[1] - theta_) * ex; double s2 = x0[1] * sigma_ * sigma_ * ex / kappa_ * (1 - ex) + theta_ * sigma_ * sigma_ / (2 * kappa_) * (1 - ex) * (1 - ex); double psi = s2 / (m * m); double g1 = 0.5; double g2 = 0.5; double k0 = -rho_ * kappa_ * theta_ * dt / sigma_; double k1 = g1 * dt * (kappa_ * rho_ / sigma_ - 0.5) - rho_ / sigma_; double k2 = g2 * dt * (kappa_ * rho_ / sigma_ - 0.5) + rho_ / sigma_; double k3 = g1 * dt * (1 - rho_ * rho_); double k4 = g2 * dt * (1 - rho_ * rho_); double A = k2 + 0.5 * k4; if (psi < 1.5) { double b2 = 2 / psi - 1 + Math.Sqrt(2 / psi * (2 / psi - 1)); double b = Math.Sqrt(b2); double a = m / (1 + b2); if (discretization_ == Discretization.QuadraticExponentialMartingale) { // martingale correction Utils.QL_REQUIRE(A < 1 / (2 * a), () => "illegal value"); k0 = -A * b2 * a / (1 - 2 * A * a) + 0.5 * Math.Log(1 - 2 * A * a) - (k1 + 0.5 * k3) * x0[1]; } retVal[1] = a * (b + dw[1]) * (b + dw[1]); } else { double p = (psi - 1) / (psi + 1); double beta = (1 - p) / m; double u = new CumulativeNormalDistribution().value(dw[1]); if (discretization_ == Discretization.QuadraticExponentialMartingale) { // martingale correction Utils.QL_REQUIRE(A < beta, () => "illegal value"); k0 = -Math.Log(p + beta * (1 - p) / (beta - A)) - (k1 + 0.5 * k3) * x0[1]; } retVal[1] = ((u <= p) ? 0.0 : Math.Log((1 - p) / (1 - u)) / beta); } mu = riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value(); retVal[0] = x0[0] * Math.Exp(mu * dt + k0 + k1 * x0[1] + k2 * retVal[1] + Math.Sqrt(k3 * x0[1] + k4 * retVal[1]) * dw[0]); } break; case Discretization.BroadieKayaExactSchemeLobatto: case Discretization.BroadieKayaExactSchemeLaguerre: case Discretization.BroadieKayaExactSchemeTrapezoidal: { double nu_0 = x0[1]; double nu_t = varianceDistribution(nu_0, dw[1], dt); double x = Math.Min(1.0 - Const.QL_EPSILON, Math.Max(0.0, new CumulativeNormalDistribution().value(dw[2]))); cdf_nu_ds f = new cdf_nu_ds(this, nu_0, nu_t, dt, discretization_); double vds = new Brent().solve(f, 1e-5, -x, theta_ * dt, 0.1 * theta_ * dt); //double vds = new Brent().solve( boost::lambda::bind(&cdf_nu_ds, *this, boost::lambda::_1, // nu_0, nu_t, dt, discretization_)-x, // 1e-5, theta_*dt, 0.1*theta_*dt); double vdw = (nu_t - nu_0 - kappa_ * theta_ * dt + kappa_ * vds) / sigma_; mu = (riskFreeRate_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value() - dividendYield_.link.forwardRate(t0, t0 + dt, Compounding.Continuous).value()) * dt - 0.5 * vds + rho_ * vdw; double sig = Math.Sqrt((1 - rho_ * rho_) * vds); double s = x0[0] * Math.Exp(mu + sig * dw[0]); retVal[0] = s; retVal[1] = nu_t; } break; default: Utils.QL_FAIL("unknown discretization schema"); break; } return(retVal); }
public double MonthlyYield() { Brent solver = new Brent(); solver.setMaxEvaluations(100); List<CashFlow> cf = expectedCashflows(); MonthlyYieldFinder objective = new MonthlyYieldFinder(notional(settlementDate()), cf, settlementDate()); return solver.solve(objective, 1.0e-10, 0.02, 0.0, 1.0) /100 ; }
public override void calculate() { Utils.QL_REQUIRE(arguments_.settlementType == Settlement.Type.Physical, () => "cash-settled swaptions not priced by Jamshidian engine"); Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () => "cannot use the Jamshidian decomposition on exotic swaptions"); Utils.QL_REQUIRE(arguments_.swap.spread.IsEqual(0.0), () => "non zero spread (" + arguments_.swap.spread + ") not allowed"); 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(); } List <double> amounts = new InitializedList <double>(arguments_.fixedCoupons.Count); for (int i = 0; i < amounts.Count; i++) { amounts[i] = arguments_.fixedCoupons[i]; } amounts[amounts.Count - 1] = amounts.Last() + arguments_.nominal; double maturity = dayCounter.yearFraction(referenceDate, arguments_.exercise.date(0)); List <double> fixedPayTimes = new InitializedList <double>(arguments_.fixedPayDates.Count); for (int i = 0; i < fixedPayTimes.Count; i++) { fixedPayTimes[i] = dayCounter.yearFraction(referenceDate, arguments_.fixedPayDates[i]); } rStarFinder finder = new rStarFinder(model_, arguments_.nominal, maturity, fixedPayTimes, amounts); Brent s1d = new Brent(); double minStrike = -10.0; double maxStrike = 10.0; s1d.setMaxEvaluations(10000); s1d.setLowerBound(minStrike); s1d.setUpperBound(maxStrike); double rStar = s1d.solve(finder, 1e-8, 0.05, minStrike, maxStrike); Option.Type w = arguments_.type == VanillaSwap.Type.Payer ? Option.Type.Put : Option.Type.Call; int size = arguments_.fixedCoupons.Count; double value = 0.0; for (int i = 0; i < size; i++) { double fixedPayTime = dayCounter.yearFraction(referenceDate, arguments_.fixedPayDates[i]); double strike = model_.link.discountBond(maturity, fixedPayTime, rStar); double dboValue = model_.link.discountBondOption( w, strike, maturity, fixedPayTime); value += amounts[i] * dboValue; } results_.value = value; }
//! implied Z-spread. public static double zSpread(Leg leg, double npv, YieldTermStructure discount, DayCounter dayCounter, Compounding compounding, Frequency frequency, bool includeSettlementDateFlows, Date settlementDate = null, Date npvDate = null, double accuracy = 1.0e-10, int maxIterations = 100, double guess = 0.0) { if (settlementDate == null) settlementDate = Settings.evaluationDate(); if (npvDate == null) npvDate = settlementDate; Brent solver = new Brent(); solver.setMaxEvaluations(maxIterations); ZSpreadFinder objFunction = new ZSpreadFinder(leg,discount,npv,dayCounter, compounding, frequency, includeSettlementDateFlows, settlementDate, npvDate); double step = 0.01; return solver.solve(objFunction, accuracy, guess, step); }
public double value(double x) { // first find the right side of the interval double upper = guess_; int evaluations = maxEvaluations_; while (nonCentralDist_.value(upper) < x && evaluations > 0) { upper*=2.0; --evaluations; } // use a brent solver for the rest Brent solver = new Brent(); solver.setMaxEvaluations(evaluations); /*return solver.solve(compose(std::bind2nd(std::minus<Real>(),x), nonCentralDist_), accuracy_, 0.75*upper, (evaluations == maxEvaluations_)? 0.0: 0.5*upper, upper);*/ return 0d; }